├── .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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
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 |
--------------------------------------------------------------------------------