├── .gitignore ├── .idea ├── .gitignore ├── LaradateFilters.iml ├── modules.xml ├── php.xml └── vcs.xml ├── README.md ├── composer.json ├── composer.lock └── src ├── Enums ├── DateRange.php └── SearchDirection.php ├── Exceptions ├── ConventionException.php └── DateException.php ├── ServiceProvider.php ├── Traits ├── Builder │ └── PackageBuilder.php └── BuilderTrait.php └── config └── lara_date_filter.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | composer.lock -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/LaradateFilters.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Date Filtering Package 2 | 3 | A Laravel package for advanced date filtering and manipulation 4 | 5 | Laravel Date Filtering is a package that simplifies date-based filtering for your Laravel Eloquent models. It provides a 6 | set of convenient methods to filter records based on various date and time intervals. 7 | 8 | ## Table of Contents 9 | 10 | - [Installation](#installation) 11 | - [Usage](#usage) 12 | - [Examples](#examples) 13 | 14 | 15 | ## Installation 16 | 17 | You can install the package via Composer: 18 | 19 | ```bash 20 | composer require omar-elnaghy/laradate-filters 21 | ``` 22 | then publish config file 23 | ```bash 24 | php artisan vendor:publish --provider="OmarElnaghy\LaraDateFilters\ServiceProvider" 25 | ``` 26 | 27 | ## Usage 28 | 29 | Date Filtering Methods: Use the provided methods like FilterByDateRange, FilterByDateHoursRange, 30 | FilterByDateMinutesRange, etc., to filter records based on your specific criteria. 31 | 32 | ```php 33 | 34 | use Illuminate\Database\Eloquent\Model; 35 | use OmarElnaghy\LaraDateFilters\Traits\Builder\PackageBuilder; 36 | 37 | class YourModel extends Model 38 | { 39 | public function newEloquentBuilder($query) 40 | { 41 | return new PackageBuilder($query); 42 | } 43 | } 44 | ``` 45 | 46 | ## Features 47 | 48 | **Date Range Filtering** : You can filter records based on a specified date range, including records created "after" 49 | or "before" a certain date and time. 50 | 51 | ```php 52 | $startDate = Carbon::parse('2023-9-03'); 53 | $range = \OmarElnaghy\LaraDateFilters\Enums\DateRange::INCLUSIVE; 54 | $direction = 'after'; 55 | $results = Post::filterByDateRange(2,'day',$startDate, $direction, $range)->get(); 56 | ``` 57 | 58 | **Flexible Time Units** : You can filter records using various time units, such as seconds, minutes, hours, days, weeks, 59 | or months. 60 | 61 | ```php 62 | $results = Post::filterByDateRange(2,'day',$startDate, $direction, $range)->get(); 63 | $results = Post::filterByDateRange(2,'week',$startDate, $direction, $range)->get(); 64 | $results = Post::filterByDateRange(2,'hour',$startDate, $direction, $range)->get(); 65 | ``` 66 | 67 | **Inclusive or Exclusive Ranges** : You can choose whether the date range should be inclusive or exclusive, allowing you 68 | to fine-tune your query results. 69 | 70 | ```php 71 | $range = \OmarElnaghy\LaraDateFilters\Enums\DateRange::INCLUSIVE; 72 | $range = \OmarElnaghy\LaraDateFilters\Enums\DateRange::EXCLUSIVE; 73 | ``` 74 | 75 | ***The key feature*** 76 | 77 | The key feature of this trait is its ability to catch and handle dynamic date filtering methods based on a simple naming 78 | convention, making it incredibly convenient and powerful for developers: 79 | 80 | Dynamic Date Filtering Magic 81 | 82 | Unleash the magic of dynamic date filtering with our BuilderTrait! No more writing tedious, repetitive date filtering 83 | methods. With this trait, you can create date filters on the fly by simply following a naming convention. 84 | 85 | 86 | ```php 87 | 88 | $results = Post::filterByDateSecondsRange(2,$startDate, $direction, $range)->get(); 89 | 90 | $results = Post::filterByDateMinutesRange(2,$startDate, $direction, $range)->get(); 91 | 92 | $results = Post::filterByDateHoursRange(2,$startDate, $direction, $range)->get(); 93 | 94 | $results = Post::filterByDateDaysRange(2,$startDate, $direction, $range)->get(); 95 | 96 | $results = Post::filterByDateWeeksRange(2,$startDate, $direction, $range)->get(); 97 | 98 | $results = Post::filterByDateMonthsRange(2,$startDate, $direction, $range)->get(); 99 | 100 | ``` 101 | 102 | Effortless Date Filtering 103 | 104 | Imagine you want to filter records by date, but you don't want to write separate methods for every possible 105 | duration—seconds, minutes, hours, days, weeks, months, and more. Our BuilderTrait has you covered. Just name your method 106 | following the pattern "filterByDateXRange," and voila! X can be any duration, and the trait will handle the rest. 107 | 108 | ```php 109 | // [Duration] is a number refer to the number of [Date Unit] you want to search in 110 | return Post::filterByDate(Duration)(Date Unit)Range($startDate, $direction, $range)->get(); 111 | ``` 112 | 113 | Convenient and Flexible 114 | 115 | Need to filter records for the last 30 minutes? Call filterByDate30MinutesRange(). Want records from the last week? It's 116 | as simple as filterByDate{duration}{unit}Range(). The trait dynamically generates these methods, making your code clean and your 117 | life easier. 118 | 119 | ## Examples 120 | 121 | 1 - Filter by Custom duration and date unit (second,minutes,hours,..) 122 | 123 | ```php 124 | $startDate = Carbon::parse('2023-09-03'); 125 | $range = \OmarElnaghy\LaraDateFilters\Enums\DateRange::INCLUSIVE; 126 | $direction = 'after'; 127 | 128 | return Post::filterByDate5DayRange($startDate, $direction, $range)->get(); 129 | 130 | return Post::filterByDate6WeekRange($startDate, $direction, $range)->get(); 131 | 132 | return Post::filterByDate7MonthRange($startDate, $direction, $range)->get(); 133 | ``` 134 | 135 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omar-elnaghy/laradate-filters", 3 | "description": "A Laravel package for advanced date filtering and manipulation", 4 | "type": "library", 5 | "license": "MIT", 6 | "autoload": { 7 | "psr-4": { 8 | "OmarElnaghy\\LaraDateFilters\\": "src/" 9 | } 10 | }, 11 | "authors": [ 12 | { 13 | "name": "omarelnaghy", 14 | "email": "omarelnaghy53@gmail.com" 15 | } 16 | ], 17 | "tag": "1.0.0", 18 | "extra": { 19 | "laravel": { 20 | "providers": [ 21 | "OmarElnaghy\\LaraDateFilters\\ServiceProvider" 22 | ] 23 | } 24 | }, 25 | "require": {} 26 | } 27 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "b39bc6e6fc3541cce38b073ba6fbdc41", 8 | "packages": [], 9 | "packages-dev": [], 10 | "aliases": [], 11 | "minimum-stability": "stable", 12 | "stability-flags": [], 13 | "prefer-stable": false, 14 | "prefer-lowest": false, 15 | "platform": [], 16 | "platform-dev": [], 17 | "plugin-api-version": "2.3.0" 18 | } 19 | -------------------------------------------------------------------------------- /src/Enums/DateRange.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom( 15 | __DIR__ . '/config/lara_date_filter.php', 'lara_date_filter' 16 | ); 17 | 18 | } 19 | 20 | public function boot() 21 | { 22 | $this->publishes([ 23 | __DIR__ . '/config/lara_date_filter.php'=> config_path('lara_date_filter.php') 24 | ]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Traits/Builder/PackageBuilder.php: -------------------------------------------------------------------------------- 1 | getModel()->dateColumn ?? "created_at"; 20 | } 21 | 22 | public function FilterByDateRange(int $duration, string $dateUnit, Carbon $date, SearchDirection $direction = SearchDirection::AFTER, DateRange $range = DateRange::INCLUSIVE) 23 | { 24 | $end = clone $date; 25 | $start = clone $date; 26 | 27 | $addToDateMethod = 'add' . ucfirst($dateUnit); 28 | $subFromDateMethod = 'sub' . ucfirst($dateUnit); 29 | 30 | 31 | if ($direction->value === 'after') { 32 | $end->$addToDateMethod($duration); 33 | $date = $range->value === 'exclusive' ? $date->$addToDateMethod(1) : $date; 34 | $end = $range->value === 'exclusive' ? $end->$subFromDateMethod(1) : $end; 35 | return $this->whereBetween($this->getClassVars(), [$date, $end]); 36 | 37 | } 38 | if ($direction->value === 'before') { 39 | $start->$subFromDateMethod($duration); 40 | $date = $range->value === 'exclusive' ? $date->$subFromDateMethod(1) : $date; 41 | $start = $range->value === 'exclusive' ? $start->$subFromDateMethod(1) : $start; 42 | 43 | return $this->whereBetween($this->getClassVars(), [$start, $date]); 44 | } 45 | 46 | DateException::invalidValue(); 47 | } 48 | 49 | public function FilterByDateHoursRange(int $duration, SearchDirection $direction, Carbon $date, DateRange $range = DateRange::INCLUSIVE) 50 | { 51 | return $this->FilterByDateRange($duration, 'hour', $date, $direction, $range); 52 | } 53 | 54 | public function FilterByDateMinutesRange(int $duration, SearchDirection $direction, Carbon $date, DateRange $range = DateRange::INCLUSIVE) 55 | { 56 | return $this->FilterByDateRange($duration, 'minute', $date, $direction, $range); 57 | } 58 | 59 | public function FilterByDateSecondsRange(int $duration, SearchDirection $direction, Carbon $date, DateRange $range = DateRange::INCLUSIVE) 60 | { 61 | return $this->FilterByDateRange($duration, 'second', $date, $direction, $range); 62 | } 63 | 64 | public function FilterByDateDaysRange(int $duration, SearchDirection $direction, Carbon $date, DateRange $range = DateRange::INCLUSIVE) 65 | { 66 | return $this->FilterByDateRange($duration, 'day', $date, $direction, $range); 67 | } 68 | 69 | public function FilterByDateWeeksRange(int $duration, SearchDirection $direction, Carbon $date, DateRange $range = DateRange::INCLUSIVE) 70 | { 71 | return $this->FilterByDateRange($duration, 'week', $date, $direction, $range); 72 | } 73 | 74 | public function FilterByDateMonthsRange(int $duration, SearchDirection $direction, Carbon $date, DateRange $range = DateRange::INCLUSIVE) 75 | { 76 | return $this->FilterByDateRange($duration, 'month', $date, $direction, $range); 77 | } 78 | 79 | /** 80 | * @throws ConventionException 81 | */ 82 | public function __call($method, $parameters) 83 | { 84 | $matches = []; 85 | $conventions = config('lara_date_filter.custom_date_filter_convention', []); 86 | $conventions = array_merge($conventions, ['filterByDate{duration}{unit}Range']); 87 | 88 | if (!empty($conventions)) { 89 | foreach ($conventions as $convention) { 90 | $pattern = str_replace(['{duration}', '{unit}'], ['(\d+)', '([A-Za-z]+)'], $convention); 91 | $patternWithoutNumeric = explode('(\d+)', $pattern); 92 | $patternWithSlash = $patternWithoutNumeric[0] . '/'; 93 | if (preg_match("/^$pattern$/", $method, $matches) || preg_match("/^$patternWithSlash", $method, $matches)) { 94 | if (isset($matches[1], $matches[2])){ 95 | try { 96 | $this->validateConvention($matches[1], $matches[2]); 97 | return $this->filterByDateRange($matches[1], $matches[2], ...$parameters); 98 | } catch (Exception $exception) { 99 | return parent::__call($method, $parameters); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | return parent::__call($method, $parameters); 106 | } 107 | 108 | /** 109 | * @throws ConventionException 110 | */ 111 | private function validateConvention($duration, $unit): void 112 | { 113 | if (!isset($duration) || !is_numeric($duration)) { 114 | throw ConventionException::missingDuration(); 115 | } 116 | if (!isset($unit) || !is_numeric($duration)) { 117 | throw ConventionException::missingDateUnit(); 118 | } 119 | 120 | if (!in_array($unit, $this->dateUnits)) { 121 | throw ConventionException::invalidDateUnit(); 122 | } 123 | } 124 | 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/config/lara_date_filter.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'get{duration}{unit}Records', 5 | 'get{duration}{unit}Records', 6 | 'get{duration}{unit}Records', 7 | ], 8 | ]; 9 | --------------------------------------------------------------------------------