├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── database ├── factories │ └── UserFactory.php ├── migrations │ └── 2020_01_01_000000_create_users_table.php └── seeds │ ├── DatabaseSeeder.php │ └── UsersTableSeeder.php ├── helpers └── helpers.php ├── models ├── User.php └── UserFilters.php ├── phpunit.xml ├── src ├── FilterQueryString.php ├── Filters │ ├── BaseClause.php │ ├── ComparisonClauses │ │ ├── BaseComparison.php │ │ ├── Between │ │ │ ├── Between.php │ │ │ ├── Betweener.php │ │ │ └── NotBetween.php │ │ ├── GreaterOrEqualTo.php │ │ ├── GreaterThan.php │ │ ├── LessOrEqualTo.php │ │ └── LessThan.php │ ├── OrderbyClause.php │ ├── WhereClause.php │ ├── WhereInClause.php │ └── WhereLikeClause.php └── Resolvings.php └── tests ├── CustomFilterTest.php ├── CustomParametersTest.php ├── Filters ├── CombinationTest.php ├── ComparisonClauses │ ├── BetweenTest.php │ ├── CombinationTest.php │ ├── GreaterOrEqualTest.php │ ├── GreaterThanTest.php │ ├── LessOrEqualToTest.php │ ├── LessThanTest.php │ └── NotBetweenTest.php ├── OrderbyClauseTest.php ├── WhereClauseTest.php ├── WhereInClauseTest.php └── WhereLikeClauseTest.php └── TestCase.php /.gitignore: -------------------------------------------------------------------------------- 1 | todo 2 | notes 3 | .idea 4 | vendor 5 | docker 6 | docker-compose.yaml 7 | .phpunit.result.cache -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mehrad Sadeghi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Filter Query String 2 | #### Filter your queries based on url query string parameters like a breeze. 3 | 4 | *Compatible with Laravel **5.x** **6.x** **7.x** **8.x** **9.x** **10.x** **11.x** **12.x***. 5 | 6 | ## Table of Content 7 | - [Describing the Problem](#Describing-the-Problem) 8 | - [Usage](#Usage) 9 | - [Installation](#Usage) 10 | - [Available Filters](#Available-Methods) 11 | - [Sort](#Sort) 12 | - [Comparisons](#Comparisons) 13 | - [In](#In) 14 | - [Like](#Like) 15 | - [Where clause](#Where-Clause-Default-Filter) 16 | - [Custom Filters](#Custom-Filters) 17 | - [Conditional Filters](#Conditional-Filters) 18 | 19 | ## Describing the Problem 20 | 21 | You have probably faced the situation where you needed to filter your query based on given parameters in url query-string and after developing the logics, You've had such a code: 22 | 23 | ```php 24 | $users = User::latest(); 25 | 26 | if(request('username')) { 27 | $users->where('username', request('username')); 28 | } 29 | 30 | if(request('age')) { 31 | $users->where('age', '>', request('age')); 32 | } 33 | 34 | if(request('email')) { 35 | $users->where('email', request('email')); 36 | } 37 | 38 | return $users->get(); 39 | 40 | ``` 41 | 42 | This works, But it's not a good practice. 43 | 44 | When the number of parameters starts to grow, The number of these kind of `if` statements also grows and your code gets huge and hard to maintain. 45 | 46 | Also it's against the Open/Closed principal of SOLID principles, Because when you have a new parameter, You need to get into your existing code and add a new logic (which may breaks the existing implementations). 47 | 48 | So we have to design a way to make our filters logics separated from each other and apply them into the final query, which is the whole idea behind this package. 49 | 50 | ## Usage 51 | 1. First you need to install the package: 52 | 53 | `$ composer require mehradsadeghi/laravel-filter-querystring` 54 | 55 | 2. Then you should `use` the `FilterQueryString` trait in your model, And define `$filters` property which can be consist of [available filters](#Available-Methods) or your [custom filters](#custom-filters). 56 | 57 | ```php 58 | use Mehradsadeghi\FilterQueryString\FilterQueryString; 59 | 60 | class User extends Model 61 | { 62 | use FilterQueryString; 63 | 64 | protected $filters = []; 65 | 66 | ... 67 | } 68 | ``` 69 | 3. You need to use `filter()` method in your eloquent query. For example: 70 | 71 | ```php 72 | User::select('name')->filter()->get(); 73 | ``` 74 | 75 | ### Available Methods 76 | - [Sort](#Sort) 77 | - [Comparisons](#Comparisons) 78 | - [In](#In) 79 | - [Like](#Like) 80 | - [Where clause](#Where-Clause-Default-Filter) 81 | 82 | For the purpose of explaining each method, Imagine we have such data in our `users` table: 83 | 84 | | id | name | email | username | age | created_at 85 | |:---:|:--------:|:--------------------------:|:----------:|:----:|:----------:| 86 | | 1 | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 87 | | 2 | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 88 | | 3 | hossein | hossein@example.com | hossein123 | 22 | 2020-11-01 | 89 | | 4 | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 90 | 91 | And assume our query is something like this: 92 | 93 | ```php 94 | User::filter()->get(); 95 | ``` 96 | 97 | ### Sort 98 | Sort is the equivalent to `order by` sql statement which can be used flexible in `FilterQueryString`: 99 | 100 | Conventions: 101 | 102 | ``` 103 | ?sort=field 104 | ?sort=field,sort_type 105 | ?sort[0]=field1&sort[1]=field2 106 | ?sort[0]=field1&sort[1]=field2,sort_type 107 | ?sort[0]=field1,sort_type&sort[1]=field2,sort_type 108 | ``` 109 | 110 | In User.php 111 | ```php 112 | protected $filters = ['sort']; 113 | ``` 114 | **Single `sort`**: 115 | 116 | `https://example.com?sort=created_at` 117 | 118 | Output: 119 | 120 | | name | email | username | age | created_at 121 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 122 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 123 | | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 124 | | hossein | hossein@example.com | hossein123 | 22 | 2020-11-01 | 125 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 126 | 127 | - **Note** that when you're not defining `sort_type`, It'll be `asc` by default. 128 | 129 | **Multiple `sort`s**: 130 | 131 | `https://example.com?sort[0]=age,desc&sort[1]=created_at,desc` 132 | 133 | Output: 134 | 135 | | name | email | username | age | created_at 136 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 137 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 138 | | hossein | hossein@example.com | hossein123 | 22 | 2020-11-01 | 139 | | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 140 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 141 | 142 | **Bare in mind** that `sort` parameter with invalid values will be ignored from query and has no effect to the result. 143 | 144 | 145 | ### Comparisons 146 | Comparisons are consist of 6 filters: 147 | - greater 148 | - greater_or_equal 149 | - less 150 | - less_or_equal 151 | - between 152 | - not_between 153 | 154 | Conventions: 155 | 156 | ``` 157 | ?greater=field,value 158 | ?greater_or_equal=field,value 159 | ?less=field,value 160 | ?less_or_equal=field,value 161 | ?between=field,value1,value2 162 | ?not_between=field,value1,value2 163 | ``` 164 | 165 | In User.php 166 | ```php 167 | protected $filters = [ 168 | 'greater', 169 | 'greater_or_equal', 170 | 'less', 171 | 'less_or_equal', 172 | 'between', 173 | 'not_between' 174 | ]; 175 | ``` 176 | 177 | **Example of `greater`**: 178 | 179 | `https://example.com?greater=age,20` 180 | 181 | Output: 182 | 183 | | name | email | username | age | created_at 184 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 185 | | hossein | hossein@example.com | hossein123 | 22 | 2020-11-01 | 186 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 187 | 188 | **Example of `not_between`**: 189 | 190 | `https://example.com?not_between=age,21,30` 191 | 192 | Output: 193 | 194 | | name | email | username | age | created_at 195 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 196 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 197 | | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 198 | 199 | **Bare in mind** that comparison parameters with invalid values will be ignored from query and has no effect to the result. 200 | 201 | ### In 202 | In clause is the equivalent to `where in` sql statement. 203 | 204 | Convention: 205 | 206 | ``` 207 | ?in=field,value1,value2 208 | ``` 209 | 210 | In User.php 211 | ```php 212 | protected $filters = ['in']; 213 | ``` 214 | **Example**: 215 | 216 | `https://example.com?in=name,mehrad,reza` 217 | 218 | Output: 219 | 220 | | name | email | username | age | created_at 221 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 222 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 223 | | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 224 | 225 | **Bare in mind** that `in` parameter with invalid values will be ignored from query and has no effect to the result. 226 | 227 | ### Like 228 | Like clause is the equivalent to `like '%value%'` sql statement. 229 | 230 | Conventions: 231 | 232 | ``` 233 | ?like=field,value 234 | ?like[0]=field1,value1&like[1]=field2,value2 235 | ``` 236 | 237 | In User.php 238 | ```php 239 | protected $filters = ['like']; 240 | ``` 241 | **Single `like`**: 242 | 243 | `https://example.com?like=name,meh` 244 | 245 | Output: 246 | 247 | | name | email | username | age | created_at 248 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 249 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 250 | 251 | 252 | **Multiple `like`s**: 253 | 254 | `https://example.com?like[0]=name,meh&like[1]=username,dar` 255 | 256 | Output: 257 | 258 | | name | email | username | age | created_at 259 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 260 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 261 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 262 | 263 | **Bare in mind** that `like` parameter with invalid values will be ignored from query and has no effect to the result. 264 | 265 | ### Where Clause (default filter) 266 | Generally when your query string parameters are not one of previous available methods, It'll get filtered by the default filter which is the `where` sql statement. It's the proper filter when you need to directly filter one of your table's columns. 267 | 268 | Conventions: 269 | 270 | ``` 271 | ?field=value 272 | ?field1=value&field2=value 273 | ?field1[0]=value1&field1[1]=value2 274 | ?field1[0]=value1&field1[1]=value2&field2[0]=value1&field2[1]=value2 275 | ``` 276 | 277 | Assuming we want to filter `name`, `username` and `age` database columns, In User.php 278 | ```php 279 | protected $filters = ['name', 'username', 'age']; 280 | ``` 281 | **Example**: 282 | 283 | `https://example.com?name=mehrad` 284 | 285 | Output: 286 | 287 | | name | email | username | age | created_at 288 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 289 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 290 | 291 | 292 | **Example**: 293 | 294 | `https://example.com?age=22&username=dariush123` 295 | 296 | Output: 297 | 298 | | name | email | username | age | created_at 299 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 300 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 301 | 302 | 303 | **Example**: 304 | 305 | `https://example.com?name[0]=mehrad&name[1]=dariush` 306 | 307 | Output: 308 | 309 | | name | email | username | age | created_at 310 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 311 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 312 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 313 | 314 | **Example**: 315 | 316 | `https://example.com?name[0]=mehrad&name[1]=dariush&username[0]=mehrad123&username[1]=reza1234` 317 | 318 | Output: 319 | 320 | | name | email | username | age | created_at 321 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 322 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 323 | 324 | **Bare in mind** that `default` filter parameter with invalid values will be ignored from query and has no effect to the result. 325 | 326 | ### Custom Filters 327 | By custom filters you can define your own methods as filters. This helps with the Open/Closed of SOLID principles, Hence each time a new filter is needed, you don't have to edit previous filters and you can just write a separate method for it. 328 | 329 | Let's create a custom filter. Assuming you want to create a filter named `all_except` which retrieves all users except the one that is specified: 330 | 331 | In User.php 332 | ```php 333 | protected $filters = ['all_except']; 334 | 335 | public function all_except($query, $value) { 336 | return $query->where('name', '!=', $value); 337 | } 338 | ``` 339 | To test our newly added filter: 340 | 341 | `https://example.com?all_except=mehrad` 342 | 343 | Output: 344 | 345 | | name | email | username | age | created_at 346 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 347 | | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 348 | | hossein | hossein@example.com | hossein123 | 22 | 2020-11-01 | 349 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 350 | 351 | **Note** that your custom defined filters have the most priority which means you can even override available filters. 352 | 353 | For example lets change `in` filter in a way that only accepts 3 values: 354 | 355 | In User.php 356 | ```php 357 | protected $filters = ['in']; 358 | 359 | public function in($query, $value) { 360 | 361 | $exploded = explode(',', $value); 362 | 363 | if(count($exploded) != 4) { 364 | // throwing an exception or whatever you like to do 365 | } 366 | 367 | $field = array_shift($exploded); 368 | 369 | return $query->whereIn($field, $exploded); 370 | } 371 | ``` 372 | 373 | **Another** good example for custom filters are when you don't want to expose your database table's column name. For example assume we don't want to expose that we have a column named `username` in `users` table: 374 | 375 | In User.php 376 | ```php 377 | protected $filters = ['by']; 378 | 379 | public function by($query, $value) { 380 | return $query->where('username', $value); 381 | } 382 | ``` 383 | 384 | `https://example.com?by=dariush123` 385 | 386 | Output: 387 | 388 | | name | email | username | age | created_at 389 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 390 | | dariush | dariush@example.com | dariush123 | 22 | 2020-12-01 | 391 | 392 | #### Minor Tip 393 | In order to prevent your model to get messy or populated with filter methods, You can create a trait for it and put everything about filters inside the trait. 394 | 395 | ### Conditional Filters 396 | The `$filters` property in your model is acting kind of global for that model. It means when you use `filter()` method on your eloquent query, it'll always performs all the `$filters` filters. 397 | 398 | There might be situations that based on a condition you need to specify which filters exactly you wish to be filtered. 399 | 400 | To achieve this you can specify your desired filters as arguments in `filter()` method. 401 | 402 | Example: 403 | 404 | In your query: 405 | ```php 406 | User::filter('in')->get(); 407 | ``` 408 | 409 | `in=name,mehrad,reza&like=name,mehrad` 410 | 411 | Output: 412 | 413 | | name | email | username | age | created_at 414 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 415 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 416 | | reza | reza@example.com | reza123 | 20 | 2020-10-01 | 417 | 418 | If the `in` argument was not specified, The result of query would be only one record (`mehrad`). 419 | 420 | Another example: 421 | 422 | In your query: 423 | ```php 424 | User::filter('like', 'name')->get(); 425 | ``` 426 | 427 | `like=name,mehrad,reza,dariush,hossein&name[0]=mehrad&name[1]=hossein&username=mehrad` 428 | 429 | Output: 430 | 431 | | name | email | username | age | created_at 432 | |:--------:|:--------------------------:|:----------:|:----:|:----------:| 433 | | mehrad | mehrad@example.com | mehrad123 | 20 | 2020-09-01 | 434 | | hossein | hossein@example.com | hossein123 | 22 | 2020-11-01 | 435 | ---------------------------------------------- 436 | 437 | ### Your Stars Matter 438 | If you find this package useful and you want to encourage me to maintain and work on it, Just press the star button to declare your willing. 439 | 440 | ---------------------------------------------- 441 | 442 | ### Reward me with a cup of tea :tea: 443 | 444 | Send me as much as a cup of tea worth in your country, so I'll have the energy to maintain this package. 445 | 446 | - Ethereum: 0x2D5BFdEc132F9F0E9498Fb0B58C800db4007D154 447 | 448 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mehradsadeghi/laravel-filter-querystring", 3 | "description": "Filter your queries based on url query string parameters like a breeze.", 4 | "keywords": [ 5 | "query", 6 | "query-string", 7 | "querystring", 8 | "filter", 9 | "filter-querystring", 10 | "filter-query-string" 11 | ], 12 | "homepage": "https://github.com/mehradsadeghi/laravel-filter-querystring", 13 | "license": "MIT", 14 | "type": "library", 15 | "authors": [ 16 | { 17 | "name": "Mehrad Sadeghi", 18 | "email": "mehrad177@gmail.com", 19 | "role": "Developer" 20 | } 21 | ], 22 | "require": { 23 | "php": "^7.1|^8.0", 24 | "laravel/framework": "5.*|6.*|7.*|8.*|9.*|10.*|11.*|12.*" 25 | }, 26 | "require-dev": { 27 | "orchestra/testbench": "^4.0" 28 | }, 29 | "autoload": { 30 | "files": [ 31 | "helpers/helpers.php" 32 | ], 33 | "psr-4": { 34 | "Mehradsadeghi\\FilterQueryString\\": "src/" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "classmap": [ 39 | "database" 40 | ], 41 | "psr-4": { 42 | "Mehradsadeghi\\FilterQueryString\\Models\\": "models/", 43 | "Mehradsadeghi\\FilterQueryString\\Tests\\": "tests/" 44 | } 45 | }, 46 | "scripts": { 47 | "test": "vendor/bin/phpunit", 48 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 49 | } 50 | } -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | define(User::class, function (Faker $faker) { 9 | return [ 10 | 'name' => $faker->name, 11 | 'email' => $faker->unique()->safeEmail, 12 | 'username' => $faker->unique()->userName, 13 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 14 | 'age' => $faker->randomNumber(2), 15 | ]; 16 | }); 17 | -------------------------------------------------------------------------------- /database/migrations/2020_01_01_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->string('username')->unique(); 21 | $table->string('password'); 22 | $table->unsignedTinyInteger('age'); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('users'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UsersTableSeeder::class); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /database/seeds/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | getStub(); 16 | 17 | foreach ($users as $user) { 18 | factory(User::class)->create($user); 19 | } 20 | } 21 | 22 | private function getStub() 23 | { 24 | return [ 25 | [ 26 | 'name' => 'mehrad', 27 | 'email' => 'mehrad@example.com', 28 | 'username' => 'mehrad', 29 | 'age' => 20, 30 | 'created_at' => '2020-09-01', 31 | 'updated_at' => '2020-09-01', 32 | ], 33 | [ 34 | 'name' => 'reza', 35 | 'email' => 'reza@example.com', 36 | 'username' => 'reza', 37 | 'age' => 20, 38 | 'created_at' => '2020-10-01', 39 | 'updated_at' => '2020-10-01', 40 | ], 41 | [ 42 | 'name' => 'hossein', 43 | 'email' => 'hossein@example.com', 44 | 'username' => 'hossein', 45 | 'age' => 22, 46 | 'created_at' => '2020-11-01', 47 | 'updated_at' => '2020-11-01', 48 | ], 49 | [ 50 | 'name' => 'dariush', 51 | 'email' => 'dariush@example.com', 52 | 'username' => 'dariush', 53 | 'age' => 22, 54 | 'created_at' => '2020-12-01', 55 | 'updated_at' => '2020-12-01', 56 | ], 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /helpers/helpers.php: -------------------------------------------------------------------------------- 1 | where('age', '<', 20); 29 | } 30 | 31 | return $query; 32 | } 33 | 34 | public function old($query, $value) { 35 | 36 | if($value == 1) { 37 | $query->where('age', '>', 20); 38 | } 39 | 40 | return $query; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./tests 6 | 7 | 8 | 9 | 10 | ./app 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/FilterQueryString.php: -------------------------------------------------------------------------------- 1 | WhereClause::class, 16 | 'sort' => OrderbyClause::class, 17 | 'greater' => GreaterThan::class, 18 | 'greater_or_equal' => GreaterOrEqualTo::class, 19 | 'less' => LessThan::class, 20 | 'less_or_equal' => LessOrEqualTo::class, 21 | 'between' => Between::class, 22 | 'not_between' => NotBetween::class, 23 | 'in' => WhereInClause::class, 24 | 'like' => WhereLikeClause::class, 25 | ]; 26 | 27 | public function scopeFilter($query, ...$filters) 28 | { 29 | $filters = collect($this->getFilters($filters))->map(function ($values, $filter) { 30 | return $this->resolve($filter, $values); 31 | })->toArray(); 32 | 33 | return app(Pipeline::class) 34 | ->send($query) 35 | ->through($filters) 36 | ->thenReturn(); 37 | } 38 | 39 | private function getFilters($filters) 40 | { 41 | $filter = function ($key) use($filters) { 42 | 43 | $filters = $filters ?: $this->filters ?: []; 44 | 45 | return $this->unguardFilters != true ? in_array($key, $filters) : true; 46 | }; 47 | 48 | return array_filter(request()->query(), $filter, ARRAY_FILTER_USE_KEY) ?? []; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Filters/BaseClause.php: -------------------------------------------------------------------------------- 1 | values = $values; 16 | $this->filter = $filter; 17 | } 18 | 19 | public function handle($query, $nextFilter) 20 | { 21 | $query = $nextFilter($query); 22 | 23 | if(static::validate($this->values) === false) { 24 | return $query; 25 | } 26 | 27 | return static::apply($query); 28 | } 29 | 30 | abstract protected function apply($query): Builder; 31 | 32 | abstract protected function validate($value): bool; 33 | } 34 | -------------------------------------------------------------------------------- /src/Filters/ComparisonClauses/BaseComparison.php: -------------------------------------------------------------------------------- 1 | normalizeValues($this->values); 17 | 18 | foreach ($this->normalized as $field => $value) { 19 | $query->{$this->determineMethod($value)}($field, $this->operator, $value); 20 | } 21 | 22 | return $query; 23 | } 24 | 25 | public function validate($value): bool 26 | { 27 | if(is_null($value)) { 28 | return false; 29 | } 30 | 31 | if (!hasComma($value)) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | protected function determineMethod($value) 39 | { 40 | return isDateTime($value) ? 'whereDate' : 'where'; 41 | } 42 | 43 | protected function normalizeValues($values) 44 | { 45 | [$field, $val] = separateCommaValues($values); 46 | $this->normalized[$field] = $val; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Filters/ComparisonClauses/Between/Between.php: -------------------------------------------------------------------------------- 1 | normalizeValues($this->values); 12 | 13 | foreach($this->normalized as $field => $values) { 14 | $query->{$this->method}($field, $values); 15 | } 16 | 17 | return $query; 18 | } 19 | 20 | public function validate($value): bool 21 | { 22 | if (count(separateCommaValues($value)) != 3) { 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | 29 | protected function normalizeValues($values) 30 | { 31 | [$field, $val1, $val2] = separateCommaValues($values); 32 | $this->normalized[$field] = [$val1, $val2]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Filters/ComparisonClauses/Between/NotBetween.php: -------------------------------------------------------------------------------- 1 | ='; 8 | } 9 | -------------------------------------------------------------------------------- /src/Filters/ComparisonClauses/GreaterThan.php: -------------------------------------------------------------------------------- 1 | '; 8 | } 9 | -------------------------------------------------------------------------------- /src/Filters/ComparisonClauses/LessOrEqualTo.php: -------------------------------------------------------------------------------- 1 | normalizeValues() as $field => $order) { 12 | $query->orderBy($field, $order); 13 | } 14 | 15 | return $query; 16 | } 17 | 18 | public function validate($value): bool { 19 | return !in_array(null, (array)$value); 20 | } 21 | 22 | private function normalizeValues() 23 | { 24 | $normalized = []; 25 | 26 | foreach ((array)$this->values as $value) { 27 | 28 | $exploded = separateCommaValues($value); 29 | 30 | if (!empty($exploded[1]) and in_array($exploded[1], ['asc', 'desc'])) { 31 | $normalized[$exploded[0]] = $exploded[1]; 32 | continue; 33 | } 34 | 35 | $normalized[$exploded[0]] = 'asc'; 36 | } 37 | 38 | return $normalized; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Filters/WhereClause.php: -------------------------------------------------------------------------------- 1 | values) ? 'orWhere' : 'andWhere'; 12 | 13 | return $this->{$method}($query, $this->filter, $this->values); 14 | } 15 | 16 | protected function validate($value): bool { 17 | return !is_null($value); 18 | } 19 | 20 | private function orWhere($query, $filter, $values) 21 | { 22 | $query->where(function($query) use($values, $filter) { 23 | foreach((array)$values as $value) { 24 | $query->orWhere($filter, $value); 25 | } 26 | }); 27 | 28 | return $query; 29 | } 30 | 31 | private function andWhere($query, $filter, $values) 32 | { 33 | foreach((array)$values as $value) { 34 | $query->where($filter, $value); 35 | } 36 | 37 | return $query; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Filters/WhereInClause.php: -------------------------------------------------------------------------------- 1 | normalizeValues(); 12 | 13 | return $query->whereIn($field, $values); 14 | } 15 | 16 | public function validate($value): bool 17 | { 18 | if(is_null($value)) { 19 | return false; 20 | } 21 | 22 | if(count(separateCommaValues($value)) < 2) { 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | 29 | private function normalizeValues() 30 | { 31 | $elements = separateCommaValues($this->values); 32 | return [array_shift($elements), $elements]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Filters/WhereLikeClause.php: -------------------------------------------------------------------------------- 1 | normalizeValues(); 12 | 13 | $query->where(function($query) use($normalized) { 14 | foreach ($normalized as $field => $values) { 15 | foreach ($values as $value) { 16 | $query->orWhere($field, 'like', "%$value%"); 17 | } 18 | } 19 | }); 20 | 21 | return $query; 22 | } 23 | 24 | public function validate($value): bool 25 | { 26 | if (is_null($value)) { 27 | return false; 28 | } 29 | 30 | foreach ((array) $value as $item) { 31 | if(count(separateCommaValues($item)) != 2) { 32 | return false; 33 | } 34 | } 35 | 36 | return true; 37 | } 38 | 39 | private function normalizeValues() 40 | { 41 | $normalized = []; 42 | 43 | foreach ((array) $this->values as $value) { 44 | [$field, $value] = separateCommaValues($value); 45 | $normalized[$field][] = $value; 46 | } 47 | 48 | return $normalized; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Resolvings.php: -------------------------------------------------------------------------------- 1 | isCustomFilter($filterName)) { 10 | return $this->resolveCustomFilter($filterName, $values); 11 | } 12 | 13 | $availableFilter = $this->availableFilters[$filterName] ?? $this->availableFilters['default']; 14 | 15 | return app($availableFilter, ['filter' => $filterName, 'values' => $values]); 16 | } 17 | 18 | private function resolveCustomFilter($filterName, $values) 19 | { 20 | return $this->getClosure($this->makeCallable($filterName), $values); 21 | } 22 | 23 | private function makeCallable($filter) 24 | { 25 | return static::class.'@'.$filter; 26 | } 27 | 28 | private function isCustomFilter($filterName) 29 | { 30 | return method_exists($this, $filterName); 31 | } 32 | 33 | private function getClosure($callable, $values) 34 | { 35 | return function ($query, $nextFilter) use ($callable, $values) { 36 | return app()->call($callable, ['query' => $nextFilter($query), 'value' => $values]); 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/CustomFilterTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 15 | 16 | $response->assertJsonCount(0); 17 | 18 | $query = 'young=0'; 19 | 20 | $response = $this->get("/?$query"); 21 | 22 | $response->assertJsonCount(User::count()); 23 | } 24 | 25 | /** @test */ 26 | public function young_and_old_custom_method() 27 | { 28 | $query = 'young=1&old=1'; 29 | 30 | $response = $this->get("/?$query"); 31 | 32 | $response->assertJsonCount(0); 33 | } 34 | 35 | /** @test */ 36 | public function young_custom_method_and_in() 37 | { 38 | $query = 'young=0&in=name,mehrad'; 39 | 40 | $response = $this->get("/?$query"); 41 | 42 | $response->assertJsonCount(1); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/CustomParametersTest.php: -------------------------------------------------------------------------------- 1 | filter('in')->get(); 15 | }); 16 | 17 | $query = 'in=name,mehrad,reza&like=name,mehrad'; 18 | 19 | $response = $this->get("/?$query"); 20 | 21 | $response->assertJsonCount(2); 22 | } 23 | 24 | /** @test */ 25 | public function filter_with_specific_parameters_can_be_performed_correctly2() 26 | { 27 | Route::get('/', function () { 28 | return User::select('name')->filter('like', 'name')->get(); 29 | }); 30 | 31 | $query = 'like=name,mehrad,reza,dariush,hossein&name[0]=mehrad&name[1]=hossein&username=mehrad'; 32 | 33 | $response = $this->get("/?$query"); 34 | 35 | $response->assertJsonCount(2); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Filters/CombinationTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 15 | $decodedResponse = $response->decodeResponseJson(); 16 | 17 | $response->assertJsonCount(2); 18 | $this->assertEquals('mehrad', $decodedResponse[0]['name']); 19 | } 20 | 21 | /** @test */ 22 | public function combination2() 23 | { 24 | $query = 'like[0]=name,meh&like[1]=name,rez&like[2]=name,omi&less=age,21&sort=created_at,desc'; 25 | 26 | $response = $this->get("/?$query"); 27 | $decodedResponse = $response->decodeResponseJson(); 28 | 29 | $response->assertJsonCount(2); 30 | $this->assertEquals('reza', $decodedResponse[0]['name']); 31 | } 32 | 33 | /** @test */ 34 | public function combination3() 35 | { 36 | $query = 'greater_or_equal=age,21&sort=created_at,desc'; 37 | 38 | $response = $this->get("/?$query"); 39 | $decodedResponse = $response->decodeResponseJson(); 40 | 41 | $response->assertJsonCount(2); 42 | $this->assertEquals('dariush', $decodedResponse[0]['name']); 43 | } 44 | 45 | /** @test */ 46 | public function combination4() 47 | { 48 | $query = 'in=name,mehrad,reza,hossein¬_between=age,22,30&sort=updated_at'; 49 | 50 | $response = $this->get("/?$query"); 51 | $decodedResponse = $response->decodeResponseJson(); 52 | 53 | $response->assertJsonCount(2); 54 | $this->assertEquals('mehrad', $decodedResponse[0]['name']); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/BetweenTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(4); 18 | } 19 | 20 | /** @test */ 21 | public function list_of_user_with_age_between_10_and_20() 22 | { 23 | $query = 'between=age,10,20'; 24 | 25 | $response = $this->get("/?$query"); 26 | 27 | $response->assertJsonCount(2); 28 | } 29 | 30 | /** @test */ 31 | public function between_statement_with_invalid_parameters_will_be_ignored() 32 | { 33 | $query = 'between=created_at,2020-11-01'; 34 | 35 | $response = $this->get("/?$query"); 36 | 37 | $response->assertJsonCount(User::count()); 38 | 39 | $query = 'between=created_at'; 40 | 41 | $response = $this->get("/?$query"); 42 | 43 | $response->assertJsonCount(User::count()); 44 | 45 | $query = 'between='; 46 | 47 | $response = $this->get("/?$query"); 48 | 49 | $response->assertJsonCount(User::count()); 50 | 51 | $query = 'between=created_at,2020-11-01,2020-12-01,2020-09-01'; 52 | 53 | $response = $this->get("/?$query"); 54 | 55 | $response->assertJsonCount(User::count()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/CombinationTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 15 | 16 | $response->assertJsonCount(1); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/GreaterOrEqualTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(4); 18 | 19 | $query = 'greater_or_equal=created_at,2020-10-01'; 20 | 21 | $response = $this->get("/?$query"); 22 | 23 | $response->assertJsonCount(3); 24 | } 25 | 26 | /** @test */ 27 | public function greater_or_equal_with_undefined_field_or_value_will_be_ignored() 28 | { 29 | $query = 'greater_or_equal=20'; 30 | 31 | $response = $this->get("/?$query"); 32 | 33 | $response->assertJsonCount(User::count()); 34 | 35 | $query = 'greater_or_equal=age'; 36 | 37 | $response = $this->get("/?$query"); 38 | 39 | $response->assertJsonCount(User::count()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/GreaterThanTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(2); 18 | 19 | $query = 'greater=created_at,2020-10-01'; 20 | 21 | $response = $this->get("/?$query"); 22 | 23 | $response->assertJsonCount(2); 24 | } 25 | 26 | /** @test */ 27 | public function greater_than_with_undefined_field_or_value_will_be_ignored() 28 | { 29 | $query = 'greater=20'; 30 | 31 | $response = $this->get("/?$query"); 32 | 33 | $response->assertJsonCount(User::count()); 34 | 35 | $query = 'greater=age'; 36 | 37 | $response = $this->get("/?$query"); 38 | 39 | $response->assertJsonCount(User::count()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/LessOrEqualToTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(4); 18 | 19 | $query = 'less_or_equal=created_at,2020-10-01'; 20 | 21 | $response = $this->get("/?$query"); 22 | 23 | $response->assertJsonCount(2); 24 | } 25 | 26 | /** @test */ 27 | public function less_or_equal_with_undefined_field_or_value_will_be_ignored() 28 | { 29 | $query = 'less_or_equal=20'; 30 | 31 | $response = $this->get("/?$query"); 32 | 33 | $response->assertJsonCount(User::count()); 34 | 35 | $query = 'less_or_equal=age'; 36 | 37 | $response = $this->get("/?$query"); 38 | 39 | $response->assertJsonCount(User::count()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/LessThanTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(2); 18 | 19 | $query = 'less=created_at,2020-10-01'; 20 | 21 | $response = $this->get("/?$query"); 22 | 23 | $response->assertJsonCount(1); 24 | } 25 | 26 | /** @test */ 27 | public function less_with_undefined_field_or_value_will_be_ignored() 28 | { 29 | $query = 'less=20'; 30 | 31 | $response = $this->get("/?$query"); 32 | 33 | $response->assertJsonCount(User::count()); 34 | 35 | $query = 'less=age'; 36 | 37 | $response = $this->get("/?$query"); 38 | 39 | $response->assertJsonCount(User::count()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Filters/ComparisonClauses/NotBetweenTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(2); 18 | } 19 | 20 | /** @test */ 21 | public function list_of_user_with_age_not_between_20_and_30() 22 | { 23 | $query = 'not_between=age,20,30'; 24 | 25 | $response = $this->get("/?$query"); 26 | 27 | $response->assertJsonCount(0); 28 | } 29 | 30 | /** @test */ 31 | public function not_between_statement_with_invalid_parameters_will_be_ignored() 32 | { 33 | $query = 'not_between=created_at,2020-11-01'; 34 | 35 | $response = $this->get("/?$query"); 36 | 37 | $response->assertJsonCount(User::count()); 38 | 39 | $query = 'not_between=created_at'; 40 | 41 | $response = $this->get("/?$query"); 42 | 43 | $response->assertJsonCount(User::count()); 44 | 45 | $query = 'not_between='; 46 | 47 | $response = $this->get("/?$query"); 48 | 49 | $response->assertJsonCount(User::count()); 50 | 51 | $query = 'not_between=created_at,2020-11-01,2020-12-01,2020-09-01'; 52 | 53 | $response = $this->get("/?$query"); 54 | 55 | $response->assertJsonCount(User::count()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Filters/OrderbyClauseTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(User::count()); 18 | } 19 | 20 | /** @test */ 21 | public function a_sort_clause_without_sort_type_can_be_performed_correctly() 22 | { 23 | $query = 'sort=name'; 24 | 25 | $response = $this->get("/?$query"); 26 | 27 | $decodedResponse = $response->decodeResponseJson(); 28 | 29 | $this->assertEquals('dariush', $decodedResponse[0]['name']); 30 | $this->assertEquals('reza', end($decodedResponse)['name']); 31 | } 32 | 33 | /** @test */ 34 | public function a_sort_clause_with_sort_type_can_be_performed_correctly() 35 | { 36 | $query = 'sort=name,desc'; 37 | 38 | $response = $this->get("/?$query"); 39 | 40 | $decodedResponse = $response->decodeResponseJson(); 41 | 42 | $this->assertEquals('reza', $decodedResponse[0]['name']); 43 | $this->assertEquals('dariush', end($decodedResponse)['name']); 44 | } 45 | 46 | /** @test */ 47 | public function a_sort_clause_with_two_fields_and_without_sort_type_can_be_performed_correctly() 48 | { 49 | $query = 'sort=name,created_at'; 50 | 51 | $response = $this->get("/?$query"); 52 | 53 | $decodedResponse = $response->decodeResponseJson(); 54 | 55 | $this->assertEquals('dariush', $decodedResponse[0]['name']); 56 | $this->assertEquals('reza', end($decodedResponse)['name']); 57 | 58 | $query = 'sort=created_at,name'; 59 | 60 | $response = $this->get("/?$query"); 61 | 62 | $decodedResponse = $response->decodeResponseJson(); 63 | 64 | $this->assertEquals('mehrad', $decodedResponse[0]['name']); 65 | $this->assertEquals('dariush', end($decodedResponse)['name']); 66 | } 67 | 68 | /** @test */ 69 | public function a_sort_clause_with_two_fields_and_with_one_sort_type_can_be_performed_correctly() 70 | { 71 | $query = 'sort=name,created_at,desc'; 72 | 73 | $response = $this->get("/?$query"); 74 | 75 | $decodedResponse = $response->decodeResponseJson(); 76 | 77 | $this->assertEquals('dariush', $decodedResponse[0]['name']); 78 | $this->assertEquals('reza', end($decodedResponse)['name']); 79 | 80 | $query = 'sort=created_at,desc,name'; 81 | 82 | $response = $this->get("/?$query"); 83 | 84 | $decodedResponse = $response->decodeResponseJson(); 85 | 86 | $this->assertEquals('dariush', $decodedResponse[0]['name']); 87 | $this->assertEquals('mehrad', end($decodedResponse)['name']); 88 | } 89 | 90 | /** @test */ 91 | public function a_sort_clause_with_two_fields_and_with_two_sort_type_can_be_performed_correctly() 92 | { 93 | $query = 'sort[0]=age,desc&sort[1]=name,desc'; 94 | 95 | $response = $this->get("/?$query"); 96 | 97 | $decodedResponse = $response->decodeResponseJson(); 98 | 99 | $this->assertEquals('hossein', $decodedResponse[0]['name']); 100 | $this->assertEquals('mehrad', end($decodedResponse)['name']); 101 | 102 | $query = 'sort[0]=age,desc&sort[1]=created_at,desc'; 103 | 104 | $response = $this->get("/?$query"); 105 | 106 | $decodedResponse = $response->decodeResponseJson(); 107 | 108 | $this->assertEquals('dariush', $decodedResponse[0]['name']); 109 | $this->assertEquals('mehrad', end($decodedResponse)['name']); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /tests/Filters/WhereClauseTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 17 | 18 | $response->assertJsonCount(User::count()); 19 | } 20 | 21 | /** @test */ 22 | public function a_where_clause_can_be_performed_correctly() 23 | { 24 | $query = 'name=mehrad'; 25 | 26 | $response = $this->get("/?$query"); 27 | 28 | $response->assertJsonCount(1); 29 | $response->assertJson([['name' => 'mehrad']]); 30 | 31 | $query = 'name=reza'; 32 | 33 | $response = $this->get("/?$query"); 34 | 35 | $response->assertJsonCount(1); 36 | $response->assertJson([['name' => 'reza']]); 37 | } 38 | 39 | /** @test */ 40 | public function two_non_array_will_unite_the_result() 41 | { 42 | $query = 'name=mehrad&username=hossein'; 43 | 44 | $response = $this->get("/?$query"); 45 | 46 | $response->assertJsonCount(0); 47 | 48 | $query = 'name=mehrad&username=mehrad'; 49 | 50 | $response = $this->get("/?$query"); 51 | 52 | $response->assertJsonCount(1); 53 | $response->assertJson([['name' => 'mehrad']]); 54 | } 55 | 56 | /** @test */ 57 | public function a_where_query_with_wrong_field_name_will_be_ignored() 58 | { 59 | $query = 'wrong_field=mehrad'; 60 | 61 | $response = $this->get("/?$query"); 62 | 63 | $response->assertJsonCount(User::count()); 64 | 65 | $query = 'name=mehrad&wrong_field=hossein'; 66 | 67 | $response = $this->get("/?$query"); 68 | 69 | $response->assertJsonCount(1); 70 | } 71 | 72 | /** @test */ 73 | public function no_query_will_be_performed_without_using_filter_eloquent_method() 74 | { 75 | Route::get('/temp', function () { 76 | return User::select('name')->get(); 77 | }); 78 | 79 | $query = 'name=mehrad'; 80 | 81 | $response = $this->get("/temp?$query"); 82 | 83 | $response->assertJsonCount(User::count()); 84 | } 85 | 86 | /** @test */ 87 | public function two_values_of_one_field_will_union_the_result() 88 | { 89 | $query = 'name[0]=mehrad&name[1]=hossein'; 90 | 91 | $response = $this->get("/?$query"); 92 | 93 | $response->assertJsonCount(2); 94 | } 95 | 96 | /** @test */ 97 | public function two_values_of_two_fields_will_union_internally_and_unite_externally_the_result() 98 | { 99 | $query = 'name[0]=mehrad&name[1]=hossein&username[0]=reza&username[1]=dariush'; 100 | 101 | $response = $this->get("/?$query"); 102 | 103 | $response->assertJsonCount(0); 104 | } 105 | 106 | /** @test */ 107 | public function two_values_of_one_field_and_one_value_of_another_field_will_unite_the_result() 108 | { 109 | $query = 'name[0]=mehrad&name[1]=reza&username=hossein'; 110 | 111 | $response = $this->get("/?$query"); 112 | 113 | $response->assertJsonCount(0); 114 | } 115 | 116 | /** @test */ 117 | public function two_values_of_two_fields_and_one_value_of_another_field_will_unite_the_result() 118 | { 119 | $query = 'name[0]=mehrad&name[1]=reza&username[0]=hossein&username[1]=mehrad&email=mehrad@example.com'; 120 | 121 | $response = $this->get("/?$query"); 122 | 123 | $response->assertJsonCount(1); 124 | 125 | $query = 'name[0]=mehrad&name[1]=reza&username[0]=hossein&username[1]=mehrad&email=dariush@example.com'; 126 | 127 | $response = $this->get("/?$query"); 128 | 129 | $response->assertJsonCount(0); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /tests/Filters/WhereInClauseTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 16 | 17 | $response->assertJsonCount(2); 18 | } 19 | 20 | /** @test */ 21 | public function wherein_clause_with_empty_field_and_values_will_be_ignored() 22 | { 23 | $query = 'in='; 24 | 25 | $response = $this->get("/?$query"); 26 | 27 | $response->assertJsonCount(User::count()); 28 | } 29 | 30 | /** @test */ 31 | public function wherein_clause_with_empty_values() 32 | { 33 | $query = 'in=name'; 34 | 35 | $response = $this->get("/?$query"); 36 | 37 | $response->assertJsonCount(User::count()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Filters/WhereLikeClauseTest.php: -------------------------------------------------------------------------------- 1 | get("/?$query"); 17 | 18 | $response->assertJsonCount(1); 19 | } 20 | 21 | /** @test */ 22 | public function two_where_like_clauses_can_be_performed() 23 | { 24 | $query = 'like[0]=name,meh&like[1]=email,reza'; 25 | 26 | $response = $this->get("/?$query"); 27 | 28 | $response->assertJsonCount(2); 29 | 30 | $query = 'like[0]=name,meh&like[1]=name,rez'; 31 | 32 | $response = $this->get("/?$query"); 33 | 34 | $response->assertJsonCount(2); 35 | } 36 | 37 | /** @test */ 38 | public function where_like_clause_with_invalid_values_will_be_ignored() 39 | { 40 | $query = 'like='; 41 | 42 | $response = $this->get("/?$query"); 43 | 44 | $response->assertJsonCount(User::count()); 45 | 46 | $query = 'like=name'; 47 | 48 | $response = $this->get("/?$query"); 49 | 50 | $response->assertJsonCount(User::count()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | loadMigrationsFrom(__DIR__.'/../database/migrations'); 15 | $this->withFactories(__DIR__.'/../database/factories'); 16 | $this->artisan('db:seed'); 17 | 18 | $this->defineDefaultRoute(); 19 | } 20 | 21 | private function defineDefaultRoute() 22 | { 23 | Route::get('/', function () { 24 | return User::select('name')->filter()->get(); 25 | }); 26 | } 27 | } --------------------------------------------------------------------------------