From 74da715364676dd6c55665004b0aa597bcc962e2 Mon Sep 17 00:00:00 2001 From: Omid Alizadeh Date: Wed, 7 Jul 2021 22:47:54 +0430 Subject: [PATCH 01/27] chore: add command test --- tests/CommandTest.php | 21 +++++++++++++++++++++ tests/TestCase.php | 5 +++++ 2 files changed, 26 insertions(+) create mode 100644 tests/CommandTest.php diff --git a/tests/CommandTest.php b/tests/CommandTest.php new file mode 100644 index 0000000..4f67761 --- /dev/null +++ b/tests/CommandTest.php @@ -0,0 +1,21 @@ +getFilterPath($filterFileName))) { + unlink($this->getFilterPath($filterFileName)); + } + $this->assertFalse(File::exists($this->getFilterPath($filterFileName))); + Artisan::call('make:filter TestFilter'); + $this->assertTrue(File::exists($this->getFilterPath($filterFileName))); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 0295050..898f057 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -41,4 +41,9 @@ protected function seedTestData() { return (new TestUserSeeder)->run(); } + + protected function getFilterPath(?string $filterFileName = null): string + { + return app_path("Http\Filters" . "\\{$filterFileName}"); + } } From 3f9dc5a29ed71c557bb70aa5620441e85173339b Mon Sep 17 00:00:00 2001 From: Omid Date: Thu, 7 Oct 2021 21:07:55 +0330 Subject: [PATCH 02/27] refactor: test db folders --- .../migrations => Database/Migrations}/CreateTestUsersTable.php | 0 tests/{database/seeders => Database/Seeders}/TestUserSeeder.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/{database/migrations => Database/Migrations}/CreateTestUsersTable.php (100%) rename tests/{database/seeders => Database/Seeders}/TestUserSeeder.php (100%) diff --git a/tests/database/migrations/CreateTestUsersTable.php b/tests/Database/Migrations/CreateTestUsersTable.php similarity index 100% rename from tests/database/migrations/CreateTestUsersTable.php rename to tests/Database/Migrations/CreateTestUsersTable.php diff --git a/tests/database/seeders/TestUserSeeder.php b/tests/Database/Seeders/TestUserSeeder.php similarity index 100% rename from tests/database/seeders/TestUserSeeder.php rename to tests/Database/Seeders/TestUserSeeder.php From e3ab2b5db3d991a48b1b23920283b482fbd87bae Mon Sep 17 00:00:00 2001 From: Omid Date: Thu, 7 Oct 2021 21:08:17 +0330 Subject: [PATCH 03/27] composer update & minimum php v7.4 --- composer.json | 2 +- composer.lock | 1422 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 1003 insertions(+), 421 deletions(-) diff --git a/composer.json b/composer.json index e3c8fc2..de427c4 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/contracts": "^6.0|^7.0|^8.0", "illuminate/console": "^6.0|^7.0|^8.0", diff --git a/composer.lock b/composer.lock index d0c9de4..828d563 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c4437649cbf2fa1d642e0d13138afb4c", + "content-hash": "5b63bc540f2b233c7fd8ebd9ca691a75", "packages": [ { "name": "brick/math", - "version": "0.9.2", + "version": "0.9.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { @@ -27,7 +27,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "vimeo/psalm": "4.9.2" }, "type": "library", "autoload": { @@ -52,15 +52,94 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-08-15T20:50:18+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "0992cc19268b259a39e86f296da5f0677841f42c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c", + "reference": "0992cc19268b259a39e86f296da5f0677841f42c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^3.14" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1" + }, + "time": "2021-08-13T13:06:58+00:00" }, { "name": "doctrine/inflector", @@ -368,31 +447,26 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.0.1", + "version": "v1.0.2", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb" + "reference": "84afea85c6841deeea872f36249a206e878a5de0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/84afea85c6841deeea872f36249a206e878a5de0", + "reference": "84afea85c6841deeea872f36249a206e878a5de0", "shasum": "" }, "require": { - "php": "^7.0|^8.0", - "phpoption/phpoption": "^1.7.3" + "php": "^7.0 || ^8.0", + "phpoption/phpoption": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0" + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "GrahamCampbell\\ResultType\\": "src/" @@ -405,7 +479,7 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk" } ], "description": "An Implementation Of The Result Type", @@ -418,7 +492,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.1" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.2" }, "funding": [ { @@ -430,20 +504,20 @@ "type": "tidelift" } ], - "time": "2020-04-13T13:17:36+00:00" + "time": "2021-08-28T21:34:50+00:00" }, { "name": "laravel/framework", - "version": "v8.49.0", + "version": "v8.62.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "855a919d08b45f93cb3cf709736528c3d1531884" + "reference": "60a7e00488167ce2babf3a2aeb3677e48aaf39be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/855a919d08b45f93cb3cf709736528c3d1531884", - "reference": "855a919d08b45f93cb3cf709736528c3d1531884", + "url": "https://api.github.com/repos/laravel/framework/zipball/60a7e00488167ce2babf3a2aeb3677e48aaf39be", + "reference": "60a7e00488167ce2babf3a2aeb3677e48aaf39be", "shasum": "" }, "require": { @@ -453,15 +527,17 @@ "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "league/commonmark": "^1.3", + "laravel/serializable-closure": "^1.0", + "league/commonmark": "^1.3|^2.0.2", "league/flysystem": "^1.1", "monolog/monolog": "^2.0", "nesbot/carbon": "^2.31", "opis/closure": "^3.6", "php": "^7.3|^8.0", "psr/container": "^1.0", + "psr/log": "^1.0 || ^2.0", "psr/simple-cache": "^1.0", - "ramsey/uuid": "^4.0", + "ramsey/uuid": "^4.2.2", "swiftmailer/swiftmailer": "^6.0", "symfony/console": "^5.1.4", "symfony/error-handler": "^5.1.4", @@ -480,7 +556,8 @@ "tightenco/collect": "<5.5.33" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "psr/simple-cache-implementation": "1.0" }, "replace": { "illuminate/auth": "self.version", @@ -516,22 +593,22 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.155", - "doctrine/dbal": "^2.6|^3.0", + "aws/aws-sdk-php": "^3.189.0", + "doctrine/dbal": "^2.13.3|^3.1.2", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^6.5.5|^7.0.1", "league/flysystem-cached-adapter": "^1.0", - "mockery/mockery": "^1.4.2", + "mockery/mockery": "^1.4.4", "orchestra/testbench-core": "^6.23", "pda/pheanstalk": "^4.0", - "phpunit/phpunit": "^8.5.8|^9.3.3", + "phpunit/phpunit": "^8.5.19|^9.5.8", "predis/predis": "^1.1.2", "symfony/cache": "^5.1.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).", "brianium/paratest": "Required to run tests in parallel (^6.0).", - "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.2).", "ext-ftp": "Required to use the Flysystem FTP driver.", "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", "ext-memcached": "Required to use the memcache cache driver.", @@ -545,10 +622,10 @@ "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", - "mockery/mockery": "Required to use mocking (^1.4.2).", + "mockery/mockery": "Required to use mocking (^1.4.4).", "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", - "phpunit/phpunit": "Required to use assertions and run tests (^8.5.8|^9.3.3).", + "phpunit/phpunit": "Required to use assertions and run tests (^8.5.19|^9.5.8).", "predis/predis": "Required to use the predis connector (^1.1.2).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0).", @@ -598,46 +675,114 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-06-29T13:50:21+00:00" + "time": "2021-09-28T13:30:25+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "679e24d36ff8b9be0e36f5222244ec8602e18867" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/679e24d36ff8b9be0e36f5222244ec8602e18867", + "reference": "679e24d36ff8b9be0e36f5222244ec8602e18867", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.18", + "phpstan/phpstan": "^0.12.98", + "symfony/var-dumper": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2021-09-29T13:25:52+00:00" }, { "name": "league/commonmark", - "version": "1.6.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "44ffd8d3c4a9133e4bd0548622b09c55af39db5f" + "reference": "2df87709f44b0dd733df86aef0830dce9b1f0f13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/44ffd8d3c4a9133e4bd0548622b09c55af39db5f", - "reference": "44ffd8d3c4a9133e4bd0548622b09c55af39db5f", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2df87709f44b0dd733df86aef0830dce9b1f0f13", + "reference": "2df87709f44b0dd733df86aef0830dce9b1f0f13", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "scrutinizer/ocular": "1.7.*" + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/polyfill-php80": "^1.15" }, "require-dev": { - "cebe/markdown": "~1.0", - "commonmark/commonmark.js": "0.29.2", - "erusev/parsedown": "~1.0", + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.30.0", + "commonmark/commonmark.js": "0.30.0", + "composer/package-versions-deprecated": "^1.8", + "erusev/parsedown": "^1.0", "ext-json": "*", "github/gfm": "0.29.0", - "michelf/php-markdown": "~1.4", - "mikehaertl/php-shellcommand": "^1.4", - "phpstan/phpstan": "^0.12.90", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2", - "scrutinizer/ocular": "^1.5", - "symfony/finder": "^4.2" + "michelf/php-markdown": "^1.4", + "phpstan/phpstan": "^0.12.88", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" }, - "bin": [ - "bin/commonmark" - ], "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.1-dev" + } + }, "autoload": { "psr-4": { "League\\CommonMark\\": "src" @@ -655,7 +800,7 @@ "role": "Lead Developer" } ], - "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)", + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", "homepage": "https://commonmark.thephpleague.com", "keywords": [ "commonmark", @@ -669,6 +814,7 @@ ], "support": { "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", "issues": "https://github.com/thephpleague/commonmark/issues", "rss": "https://github.com/thephpleague/commonmark/releases.atom", "source": "https://github.com/thephpleague/commonmark" @@ -699,20 +845,102 @@ "type": "tidelift" } ], - "time": "2021-06-26T11:57:13+00:00" + "time": "2021-08-14T14:06:04+00:00" + }, + { + "name": "league/config", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e", + "reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.90", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2021-08-14T12:15:32+00:00" }, { "name": "league/flysystem", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32" + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/18634df356bfd4119fe3d6156bdb990c414c14ea", + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea", "shasum": "" }, "require": { @@ -785,7 +1013,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.4" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.5" }, "funding": [ { @@ -793,20 +1021,20 @@ "type": "other" } ], - "time": "2021-06-23T21:56:05+00:00" + "time": "2021-08-17T13:49:42+00:00" }, { "name": "league/mime-type-detection", - "version": "1.7.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + "reference": "b38b25d7b372e9fddb00335400467b223349fd7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", - "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/b38b25d7b372e9fddb00335400467b223349fd7e", + "reference": "b38b25d7b372e9fddb00335400467b223349fd7e", "shasum": "" }, "require": { @@ -837,7 +1065,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.8.0" }, "funding": [ { @@ -849,28 +1077,28 @@ "type": "tidelift" } ], - "time": "2021-01-18T20:58:21+00:00" + "time": "2021-09-25T08:23:19+00:00" }, { "name": "monolog/monolog", - "version": "2.2.0", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9", "shasum": "" }, "require": { "php": ">=7.2", - "psr/log": "^1.0.1" + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", @@ -878,14 +1106,14 @@ "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4", + "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpstan/phpstan": "^0.12.59", + "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <7.0.1", + "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { @@ -893,8 +1121,11 @@ "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", "ext-mbstring": "Allow to work properly with unicode symbols", "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", @@ -933,7 +1164,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.2.0" + "source": "https://github.com/Seldaek/monolog/tree/2.3.5" }, "funding": [ { @@ -945,31 +1176,32 @@ "type": "tidelift" } ], - "time": "2020-12-14T13:15:25+00:00" + "time": "2021-10-01T21:08:31+00:00" }, { "name": "nesbot/carbon", - "version": "2.50.0", + "version": "2.53.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "f47f17d17602b2243414a44ad53d9f8b9ada5fdb" + "reference": "f4655858a784988f880c1b8c7feabbf02dfdf045" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/f47f17d17602b2243414a44ad53d9f8b9ada5fdb", - "reference": "f47f17d17602b2243414a44ad53d9f8b9ada5fdb", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/f4655858a784988f880c1b8c7feabbf02dfdf045", + "reference": "f4655858a784988f880c1b8c7feabbf02dfdf045", "shasum": "" }, "require": { "ext-json": "*", "php": "^7.1.8 || ^8.0", "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { "doctrine/orm": "^2.7", - "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.0", "kylekatarnls/multi-tester": "^2.0", "phpmd/phpmd": "^2.9", "phpstan/extension-installer": "^1.0", @@ -983,8 +1215,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev", - "dev-3.x": "3.x-dev" + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" }, "laravel": { "providers": [ @@ -1038,7 +1270,154 @@ "type": "tidelift" } ], - "time": "2021-06-28T22:38:45+00:00" + "time": "2021-09-06T09:29:23+00:00" + }, + { + "name": "nette/schema", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "f5ed39fc96358f922cedfd1e516f0dadf5d2be0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/f5ed39fc96358f922cedfd1e516f0dadf5d2be0d", + "reference": "f5ed39fc96358f922cedfd1e516f0dadf5d2be0d", + "shasum": "" + }, + "require": { + "nette/utils": "^3.1.4 || ^4.0", + "php": ">=7.1 <8.1" + }, + "require-dev": { + "nette/tester": "^2.3 || ^2.4", + "phpstan/phpstan-nette": "^0.12", + "tracy/tracy": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.2.1" + }, + "time": "2021-03-04T17:51:11+00:00" + }, + { + "name": "nette/utils", + "version": "v3.2.5", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "9cd80396ca58d7969ab44fc7afcf03624dfa526e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/9cd80396ca58d7969ab44fc7afcf03624dfa526e", + "reference": "9cd80396ca58d7969ab44fc7afcf03624dfa526e", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.2" + }, + "conflict": { + "nette/di": "<3.0.6" + }, + "require-dev": { + "nette/tester": "~2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v3.2.5" + }, + "time": "2021-09-20T10:50:11+00:00" }, { "name": "opis/closure", @@ -1107,29 +1486,29 @@ }, { "name": "phpoption/phpoption", - "version": "1.7.5", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" + "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5455cb38aed4523f99977c4a12ef19da4bfe2a28", + "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0" + "php": "^7.0 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^6.5.14 || ^7.0.20 || ^8.5.19 || ^9.5.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -1148,7 +1527,7 @@ }, { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk" } ], "description": "Option Type for PHP", @@ -1160,7 +1539,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" + "source": "https://github.com/schmittjoh/php-option/tree/1.8.0" }, "funding": [ { @@ -1172,7 +1551,7 @@ "type": "tidelift" } ], - "time": "2020-07-20T17:29:33+00:00" + "time": "2021-08-28T21:27:29+00:00" }, { "name": "psr/container", @@ -1274,30 +1653,30 @@ }, { "name": "psr/log", - "version": "1.1.4", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376", + "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1318,9 +1697,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/2.0.0" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2021-07-14T16:41:46+00:00" }, { "name": "psr/simple-cache", @@ -1375,20 +1754,21 @@ }, { "name": "ramsey/collection", - "version": "1.1.3", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa", + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa", "shasum": "" }, "require": { - "php": "^7.2 || ^8" + "php": "^7.3 || ^8", + "symfony/polyfill-php81": "^1.23" }, "require-dev": { "captainhook/captainhook": "^5.3", @@ -1398,6 +1778,7 @@ "hamcrest/hamcrest-php": "^2", "jangregor/phpstan-prophecy": "^0.8", "mockery/mockery": "^1.3", + "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1", "phpstan/phpstan": "^0.12.32", "phpstan/phpstan-mockery": "^0.12.5", @@ -1425,7 +1806,7 @@ "homepage": "https://benramsey.com" } ], - "description": "A PHP 7.2+ library for representing and manipulating collections.", + "description": "A PHP library for representing and manipulating collections.", "keywords": [ "array", "collection", @@ -1436,7 +1817,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.1.3" + "source": "https://github.com/ramsey/collection/tree/1.2.1" }, "funding": [ { @@ -1448,53 +1829,54 @@ "type": "tidelift" } ], - "time": "2021-01-21T17:40:04+00:00" + "time": "2021-08-06T03:41:06+00:00" }, { "name": "ramsey/uuid", - "version": "4.1.1", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", "shasum": "" }, "require": { "brick/math": "^0.8 || ^0.9", "ext-json": "*", - "php": "^7.2 || ^8", + "php": "^7.2 || ^8.0", "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8" + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.8", - "goaop/framework": "^2", + "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" + "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -1507,7 +1889,10 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true } }, "autoload": { @@ -1523,7 +1908,6 @@ "MIT" ], "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", @@ -1531,16 +1915,19 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" + "source": "https://github.com/ramsey/uuid/tree/4.2.3" }, "funding": [ { "url": "https://github.com/ramsey", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" } ], - "time": "2020-08-18T17:17:46+00:00" + "time": "2021-09-25T23:10:38+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -1619,16 +2006,16 @@ }, { "name": "symfony/console", - "version": "v5.3.2", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "649730483885ff2ca99ca0560ef0e5f6b03f2ac1" + "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/649730483885ff2ca99ca0560ef0e5f6b03f2ac1", - "reference": "649730483885ff2ca99ca0560ef0e5f6b03f2ac1", + "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", + "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", "shasum": "" }, "require": { @@ -1636,11 +2023,12 @@ "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2", "symfony/string": "^5.1" }, "conflict": { + "psr/log": ">=3", "symfony/dependency-injection": "<4.4", "symfony/dotenv": "<5.1", "symfony/event-dispatcher": "<4.4", @@ -1648,10 +2036,10 @@ "symfony/process": "<4.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2", "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/event-dispatcher": "^4.4|^5.0", @@ -1697,7 +2085,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.2" + "source": "https://github.com/symfony/console/tree/v5.3.7" }, "funding": [ { @@ -1713,24 +2101,25 @@ "type": "tidelift" } ], - "time": "2021-06-12T09:42:48+00:00" + "time": "2021-08-25T20:02:16+00:00" }, { "name": "symfony/css-selector", - "version": "v5.3.0", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814" + "reference": "7fb120adc7f600a59027775b224c13a33530dd90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/7fb120adc7f600a59027775b224c13a33530dd90", + "reference": "7fb120adc7f600a59027775b224c13a33530dd90", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -1762,7 +2151,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0" + "source": "https://github.com/symfony/css-selector/tree/v5.3.4" }, "funding": [ { @@ -1778,7 +2167,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:40:38+00:00" + "time": "2021-07-21T12:38:00+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1849,22 +2238,21 @@ }, { "name": "symfony/error-handler", - "version": "v5.3.3", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "43323e79c80719e8a4674e33484bca98270d223f" + "reference": "3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/43323e79c80719e8a4674e33484bca98270d223f", - "reference": "43323e79c80719e8a4674e33484bca98270d223f", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321", + "reference": "3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/log": "^1.0", - "symfony/polyfill-php80": "^1.15", + "psr/log": "^1|^2|^3", "symfony/var-dumper": "^4.4|^5.0" }, "require-dev": { @@ -1898,7 +2286,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.3.3" + "source": "https://github.com/symfony/error-handler/tree/v5.3.7" }, "funding": [ { @@ -1914,27 +2302,27 @@ "type": "tidelift" } ], - "time": "2021-06-24T08:13:00+00:00" + "time": "2021-08-28T15:07:08+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.3.0", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce" + "reference": "ce7b20d69c66a20939d8952b617506a44d102130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67a5f354afa8e2f231081b3fa11a5912f933c3ce", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ce7b20d69c66a20939d8952b617506a44d102130", + "reference": "ce7b20d69c66a20939d8952b617506a44d102130", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/event-dispatcher-contracts": "^2", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/dependency-injection": "<4.4" @@ -1944,7 +2332,7 @@ "symfony/event-dispatcher-implementation": "2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/error-handler": "^4.4|^5.0", @@ -1983,7 +2371,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.7" }, "funding": [ { @@ -1999,7 +2387,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -2082,20 +2470,21 @@ }, { "name": "symfony/finder", - "version": "v5.3.0", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6" + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", + "url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93", + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -2123,7 +2512,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.0" + "source": "https://github.com/symfony/finder/tree/v5.3.7" }, "funding": [ { @@ -2139,7 +2528,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T12:52:38+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -2221,23 +2610,23 @@ }, { "name": "symfony/http-foundation", - "version": "v5.3.3", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "0e45ab1574caa0460d9190871a8ce47539e40ccf" + "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0e45ab1574caa0460d9190871a8ce47539e40ccf", - "reference": "0e45ab1574caa0460d9190871a8ce47539e40ccf", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", + "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "require-dev": { "predis/predis": "~1.0", @@ -2274,7 +2663,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.3.3" + "source": "https://github.com/symfony/http-foundation/tree/v5.3.7" }, "funding": [ { @@ -2290,33 +2679,33 @@ "type": "tidelift" } ], - "time": "2021-06-27T09:19:40+00:00" + "time": "2021-08-27T11:20:35+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.3.3", + "version": "v5.3.9", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "90ad9f4b21ddcb8ebe9faadfcca54929ad23f9f8" + "reference": "ceaf46a992f60e90645e7279825a830f733a17c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/90ad9f4b21ddcb8ebe9faadfcca54929ad23f9f8", - "reference": "90ad9f4b21ddcb8ebe9faadfcca54929ad23f9f8", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ceaf46a992f60e90645e7279825a830f733a17c5", + "reference": "ceaf46a992f60e90645e7279825a830f733a17c5", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/log": "~1.0", + "psr/log": "^1|^2", "symfony/deprecation-contracts": "^2.1", "symfony/error-handler": "^4.4|^5.0", "symfony/event-dispatcher": "^5.0", "symfony/http-client-contracts": "^1.1|^2", - "symfony/http-foundation": "^5.3", + "symfony/http-foundation": "^5.3.7", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/browser-kit": "<4.4", @@ -2335,7 +2724,7 @@ "twig/twig": "<2.13" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", @@ -2386,7 +2775,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.3.3" + "source": "https://github.com/symfony/http-kernel/tree/v5.3.9" }, "funding": [ { @@ -2402,20 +2791,20 @@ "type": "tidelift" } ], - "time": "2021-06-30T08:27:49+00:00" + "time": "2021-09-28T10:25:11+00:00" }, { "name": "symfony/mime", - "version": "v5.3.2", + "version": "v5.3.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "47dd7912152b82d0d4c8d9040dbc93d6232d472a" + "reference": "a756033d0a7e53db389618653ae991eba5a19a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/47dd7912152b82d0d4c8d9040dbc93d6232d472a", - "reference": "47dd7912152b82d0d4c8d9040dbc93d6232d472a", + "url": "https://api.github.com/repos/symfony/mime/zipball/a756033d0a7e53db389618653ae991eba5a19a11", + "reference": "a756033d0a7e53db389618653ae991eba5a19a11", "shasum": "" }, "require": { @@ -2423,7 +2812,7 @@ "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "egulias/email-validator": "~3.0.0", @@ -2469,7 +2858,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.3.2" + "source": "https://github.com/symfony/mime/tree/v5.3.8" }, "funding": [ { @@ -2485,7 +2874,7 @@ "type": "tidelift" } ], - "time": "2021-06-09T10:58:01+00:00" + "time": "2021-09-10T12:30:38+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2648,16 +3037,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab" + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/24b72c6baa32c746a4d0840147c9715e42bb68ab", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", "shasum": "" }, "require": { @@ -2709,7 +3098,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" }, "funding": [ { @@ -2725,7 +3114,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-intl-idn", @@ -2900,16 +3289,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", "shasum": "" }, "require": { @@ -2960,7 +3349,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" }, "funding": [ { @@ -2976,7 +3365,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-php72", @@ -3135,16 +3524,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", "shasum": "" }, "require": { @@ -3198,7 +3587,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" }, "funding": [ { @@ -3214,25 +3603,104 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-07-28T13:41:28+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "e66119f3de95efc359483f810c4c3e6436279436" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", + "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-21T13:25:03+00:00" }, { "name": "symfony/process", - "version": "v5.3.2", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "714b47f9196de61a196d86c4bad5f09201b307df" + "reference": "38f26c7d6ed535217ea393e05634cb0b244a1967" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/714b47f9196de61a196d86c4bad5f09201b307df", - "reference": "714b47f9196de61a196d86c4bad5f09201b307df", + "url": "https://api.github.com/repos/symfony/process/zipball/38f26c7d6ed535217ea393e05634cb0b244a1967", + "reference": "38f26c7d6ed535217ea393e05634cb0b244a1967", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3260,7 +3728,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.3.2" + "source": "https://github.com/symfony/process/tree/v5.3.7" }, "funding": [ { @@ -3276,26 +3744,26 @@ "type": "tidelift" } ], - "time": "2021-06-12T10:15:01+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/routing", - "version": "v5.3.0", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "368e81376a8e049c37cb80ae87dbfbf411279199" + "reference": "be865017746fe869007d94220ad3f5297951811b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/368e81376a8e049c37cb80ae87dbfbf411279199", - "reference": "368e81376a8e049c37cb80ae87dbfbf411279199", + "url": "https://api.github.com/repos/symfony/routing/zipball/be865017746fe869007d94220ad3f5297951811b", + "reference": "be865017746fe869007d94220ad3f5297951811b", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "doctrine/annotations": "<1.12", @@ -3305,7 +3773,7 @@ }, "require-dev": { "doctrine/annotations": "^1.12", - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^5.3", "symfony/dependency-injection": "^4.4|^5.0", "symfony/expression-language": "^4.4|^5.0", @@ -3350,7 +3818,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.3.0" + "source": "https://github.com/symfony/routing/tree/v5.3.7" }, "funding": [ { @@ -3366,7 +3834,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-08-04T21:42:42+00:00" }, { "name": "symfony/service-contracts", @@ -3449,16 +3917,16 @@ }, { "name": "symfony/string", - "version": "v5.3.3", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1" + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1", - "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1", + "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", "shasum": "" }, "require": { @@ -3512,7 +3980,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.3" + "source": "https://github.com/symfony/string/tree/v5.3.7" }, "funding": [ { @@ -3528,27 +3996,27 @@ "type": "tidelift" } ], - "time": "2021-06-27T11:44:38+00:00" + "time": "2021-08-26T08:00:08+00:00" }, { "name": "symfony/translation", - "version": "v5.3.3", + "version": "v5.3.9", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "380b8c9e944d0e364b25f28e8e555241eb49c01c" + "reference": "6e69f3551c1a3356cf6ea8d019bf039a0f8b6886" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/380b8c9e944d0e364b25f28e8e555241eb49c01c", - "reference": "380b8c9e944d0e364b25f28e8e555241eb49c01c", + "url": "https://api.github.com/repos/symfony/translation/zipball/6e69f3551c1a3356cf6ea8d019bf039a0f8b6886", + "reference": "6e69f3551c1a3356cf6ea8d019bf039a0f8b6886", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/translation-contracts": "^2.3" }, "conflict": { @@ -3562,7 +4030,7 @@ "symfony/translation-implementation": "2.3" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^4.4|^5.0", "symfony/console": "^4.4|^5.0", "symfony/dependency-injection": "^5.0", @@ -3607,7 +4075,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.3.3" + "source": "https://github.com/symfony/translation/tree/v5.3.9" }, "funding": [ { @@ -3623,7 +4091,7 @@ "type": "tidelift" } ], - "time": "2021-06-27T12:22:47+00:00" + "time": "2021-08-26T08:22:53+00:00" }, { "name": "symfony/translation-contracts", @@ -3705,22 +4173,22 @@ }, { "name": "symfony/var-dumper", - "version": "v5.3.3", + "version": "v5.3.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "46aa709affb9ad3355bd7a810f9662d71025c384" + "reference": "eaaea4098be1c90c8285543e1356a09c8aa5c8da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/46aa709affb9ad3355bd7a810f9662d71025c384", - "reference": "46aa709affb9ad3355bd7a810f9662d71025c384", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/eaaea4098be1c90c8285543e1356a09c8aa5c8da", + "reference": "eaaea4098be1c90c8285543e1356a09c8aa5c8da", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "phpunit/phpunit": "<5.4.3", @@ -3773,7 +4241,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.3.3" + "source": "https://github.com/symfony/var-dumper/tree/v5.3.8" }, "funding": [ { @@ -3789,7 +4257,7 @@ "type": "tidelift" } ], - "time": "2021-06-24T08:13:00+00:00" + "time": "2021-09-24T15:59:58+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -3846,31 +4314,31 @@ }, { "name": "vlucas/phpdotenv", - "version": "v5.3.0", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56" + "reference": "accaddf133651d4b5cf81a119f25296736ffc850" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", - "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/accaddf133651d4b5cf81a119f25296736ffc850", + "reference": "accaddf133651d4b5cf81a119f25296736ffc850", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.1", + "graham-campbell/result-type": "^1.0.2", "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.7.4", - "symfony/polyfill-ctype": "^1.17", - "symfony/polyfill-mbstring": "^1.17", - "symfony/polyfill-php80": "^1.17" + "phpoption/phpoption": "^1.8", + "symfony/polyfill-ctype": "^1.23", + "symfony/polyfill-mbstring": "^1.23.1", + "symfony/polyfill-php80": "^1.23.1" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5.1" + "phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10" }, "suggest": { "ext-filter": "Required to use the boolean validator." @@ -3893,13 +4361,11 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com", - "homepage": "https://gjcampbell.co.uk/" + "email": "hello@gjcampbell.co.uk" }, { "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://vancelucas.com/" + "email": "vance@vancelucas.com" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -3910,7 +4376,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.3.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.3.1" }, "funding": [ { @@ -3922,7 +4388,7 @@ "type": "tidelift" } ], - "time": "2021-01-20T15:23:13+00:00" + "time": "2021-10-02T19:24:42+00:00" }, { "name": "voku/portable-ascii", @@ -4129,21 +4595,21 @@ }, { "name": "fakerphp/faker", - "version": "v1.14.1", + "version": "v1.16.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1" + "reference": "271d384d216e5e5c468a6b28feedf95d49f83b35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1", - "reference": "ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/271d384d216e5e5c468a6b28feedf95d49f83b35", + "reference": "271d384d216e5e5c468a6b28feedf95d49f83b35", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", - "psr/container": "^1.0", + "psr/container": "^1.0 || ^2.0", "symfony/deprecation-contracts": "^2.2" }, "conflict": { @@ -4163,7 +4629,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v1.15-dev" + "dev-main": "v1.16-dev" } }, "autoload": { @@ -4188,35 +4654,38 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v.1.14.1" + "source": "https://github.com/FakerPHP/Faker/tree/v1.16.0" }, - "time": "2021-03-30T06:27:33+00:00" + "time": "2021-09-06T14:53:37+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.8.2", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/1dc8d9cba3897165e16d12bb13d813afb1eb3fe7", + "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7", "shasum": "" }, "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" }, "provide": { + "psr/http-factory-implementation": "1.0", "psr/http-message-implementation": "1.0" }, "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -4224,16 +4693,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "2.0-dev" } }, "autoload": { "psr-4": { "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4248,6 +4714,11 @@ { "name": "Tobias Schultze", "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" } ], "description": "PSR-7 message implementation that also provides common utility methods", @@ -4263,9 +4734,9 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" + "source": "https://github.com/guzzle/psr7/tree/2.0.0" }, - "time": "2021-04-26T09:17:50+00:00" + "time": "2021-06-30T20:03:07+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -4320,16 +4791,16 @@ }, { "name": "mockery/mockery", - "version": "1.4.3", + "version": "1.4.4", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea" + "reference": "e01123a0e847d52d186c5eb4b9bf58b0c6d00346" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/d1339f64479af1bee0e82a0413813fe5345a54ea", - "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea", + "url": "https://api.github.com/repos/mockery/mockery/zipball/e01123a0e847d52d186c5eb4b9bf58b0c6d00346", + "reference": "e01123a0e847d52d186c5eb4b9bf58b0c6d00346", "shasum": "" }, "require": { @@ -4386,9 +4857,9 @@ ], "support": { "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.4.3" + "source": "https://github.com/mockery/mockery/tree/1.4.4" }, - "time": "2021-02-24T09:51:49+00:00" + "time": "2021-09-13T15:28:59+00:00" }, { "name": "myclabs/deep-copy", @@ -4450,16 +4921,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.5", + "version": "v4.13.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" + "reference": "50953a2691a922aa1769461637869a0a2faa3f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", + "reference": "50953a2691a922aa1769461637869a0a2faa3f53", "shasum": "" }, "require": { @@ -4500,28 +4971,28 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" }, - "time": "2021-05-03T19:11:20+00:00" + "time": "2021-09-20T12:20:58+00:00" }, { "name": "orchestra/testbench", - "version": "v6.19.0", + "version": "v6.21.1", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "4e3ee38295d793f0d4864203d5e1f0b952635d1b" + "reference": "f61383c001a97f0a116b0c58f74385424aa9de33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/4e3ee38295d793f0d4864203d5e1f0b952635d1b", - "reference": "4e3ee38295d793f0d4864203d5e1f0b952635d1b", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/f61383c001a97f0a116b0c58f74385424aa9de33", + "reference": "f61383c001a97f0a116b0c58f74385424aa9de33", "shasum": "" }, "require": { - "laravel/framework": "^8.26", + "laravel/framework": "^8.54", "mockery/mockery": "^1.4.2", - "orchestra/testbench-core": "^6.23", + "orchestra/testbench-core": "^6.25.2", "php": "^7.3 || ^8.0", "phpunit/phpunit": "^8.4 || ^9.3.3", "spatie/laravel-ray": "^1.18" @@ -4555,7 +5026,7 @@ ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v6.19.0" + "source": "https://github.com/orchestral/testbench/tree/v6.21.1" }, "funding": [ { @@ -4567,20 +5038,20 @@ "type": "liberapay" } ], - "time": "2021-07-01T02:50:07+00:00" + "time": "2021-09-18T09:37:03+00:00" }, { "name": "orchestra/testbench-core", - "version": "v6.23.0", + "version": "v6.25.2", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "6d88802eb6010ab845ec8b3a07895148262297f3" + "reference": "03d8cce6e500a9c64da4cbaa776236c91b2572a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/6d88802eb6010ab845ec8b3a07895148262297f3", - "reference": "6d88802eb6010ab845ec8b3a07895148262297f3", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/03d8cce6e500a9c64da4cbaa776236c91b2572a1", + "reference": "03d8cce6e500a9c64da4cbaa776236c91b2572a1", "shasum": "" }, "require": { @@ -4590,7 +5061,7 @@ "vlucas/phpdotenv": "^5.1" }, "require-dev": { - "laravel/framework": "^8.26", + "laravel/framework": "^8.54", "laravel/laravel": "8.x-dev", "mockery/mockery": "^1.4.2", "orchestra/canvas": "^6.1", @@ -4599,7 +5070,7 @@ "symfony/process": "^5.0" }, "suggest": { - "laravel/framework": "Required for testing (^8.26).", + "laravel/framework": "Required for testing (^8.54).", "mockery/mockery": "Allow using Mockery for testing (^1.4.2).", "orchestra/testbench-browser-kit": "Allow using legacy Laravel BrowserKit for testing (^6.0).", "orchestra/testbench-dusk": "Allow using Laravel Dusk for testing (^6.0).", @@ -4617,7 +5088,10 @@ "autoload": { "psr-4": { "Orchestra\\Testbench\\": "src/" - } + }, + "files": [ + "src/helpers.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4654,20 +5128,20 @@ "type": "liberapay" } ], - "time": "2021-06-15T22:53:33+00:00" + "time": "2021-09-18T01:47:58+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { @@ -4712,9 +5186,9 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", @@ -4878,16 +5352,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", "shasum": "" }, "require": { @@ -4895,7 +5369,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -4921,39 +5396,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2021-10-02T14:08:47+00:00" }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -4988,29 +5463,29 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/1.14.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-09-10T09:02:12+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "9.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", + "nikic/php-parser": "^4.12.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -5059,7 +5534,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" }, "funding": [ { @@ -5067,7 +5542,7 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2021-09-17T05:39:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5312,16 +5787,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.6", + "version": "9.5.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb" + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb", - "reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", "shasum": "" }, "require": { @@ -5333,11 +5808,11 @@ "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-code-coverage": "^9.2.7", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -5399,7 +5874,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.6" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" }, "funding": [ { @@ -5411,7 +5886,115 @@ "type": "github" } ], - "time": "2021-06-23T05:14:38+00:00" + "time": "2021-09-25T07:38:51+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "86406047271859ffc13424a048541f4531f53601" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/86406047271859ffc13424a048541f4531f53601", + "reference": "86406047271859ffc13424a048541f4531f53601", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "support": { + "source": "https://github.com/silexphp/Pimple/tree/v3.4.0" + }, + "time": "2021-03-06T08:28:00+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" }, { "name": "psr/http-message", @@ -6538,16 +7121,16 @@ }, { "name": "spatie/laravel-ray", - "version": "1.23.0", + "version": "1.26.1", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ray.git", - "reference": "2e49e83f3df25e4ef7a145cb0247d2038b8d3436" + "reference": "5ecc2ebbdad8ae3ec31274596d922495cff69184" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/2e49e83f3df25e4ef7a145cb0247d2038b8d3436", - "reference": "2e49e83f3df25e4ef7a145cb0247d2038b8d3436", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/5ecc2ebbdad8ae3ec31274596d922495cff69184", + "reference": "5ecc2ebbdad8ae3ec31274596d922495cff69184", "shasum": "" }, "require": { @@ -6560,13 +7143,14 @@ "spatie/backtrace": "^1.0", "spatie/ray": "^1.27.1", "symfony/stopwatch": "4.2|^5.1", - "zbateson/mail-mime-parser": "^1.3.1" + "zbateson/mail-mime-parser": "^1.3.1|^2.0" }, "require-dev": { "facade/ignition": "^2.5", "guzzlehttp/guzzle": "^7.3", "laravel/framework": "^7.20|^8.19", "orchestra/testbench-core": "^5.0|^6.0", + "phpstan/phpstan": "^0.12.93", "phpunit/phpunit": "^9.3", "spatie/phpunit-snapshot-assertions": "^4.2" }, @@ -6603,7 +7187,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-ray/issues", - "source": "https://github.com/spatie/laravel-ray/tree/1.23.0" + "source": "https://github.com/spatie/laravel-ray/tree/1.26.1" }, "funding": [ { @@ -6615,24 +7199,24 @@ "type": "other" } ], - "time": "2021-06-24T14:47:53+00:00" + "time": "2021-10-01T13:08:05+00:00" }, { "name": "spatie/macroable", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/spatie/macroable.git", - "reference": "7a99549fc001c925714b329220dea680c04bfa48" + "reference": "ec2c320f932e730607aff8052c44183cf3ecb072" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/macroable/zipball/7a99549fc001c925714b329220dea680c04bfa48", - "reference": "7a99549fc001c925714b329220dea680c04bfa48", + "url": "https://api.github.com/repos/spatie/macroable/zipball/ec2c320f932e730607aff8052c44183cf3ecb072", + "reference": "ec2c320f932e730607aff8052c44183cf3ecb072", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^8.0" }, "require-dev": { "phpunit/phpunit": "^8.0|^9.3" @@ -6663,22 +7247,22 @@ ], "support": { "issues": "https://github.com/spatie/macroable/issues", - "source": "https://github.com/spatie/macroable/tree/1.0.1" + "source": "https://github.com/spatie/macroable/tree/2.0.0" }, - "time": "2020-11-03T10:15:05+00:00" + "time": "2021-03-26T22:39:02+00:00" }, { "name": "spatie/ray", - "version": "1.27.1", + "version": "1.30.2", "source": { "type": "git", "url": "https://github.com/spatie/ray.git", - "reference": "57880fa060c81256363b4b9706e99df447af8613" + "reference": "f6344f8abf3ede60c963d9d3f7f35fb526b6138c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/57880fa060c81256363b4b9706e99df447af8613", - "reference": "57880fa060c81256363b4b9706e99df447af8613", + "url": "https://api.github.com/repos/spatie/ray/zipball/f6344f8abf3ede60c963d9d3f7f35fb526b6138c", + "reference": "f6344f8abf3ede60c963d9d3f7f35fb526b6138c", "shasum": "" }, "require": { @@ -6694,8 +7278,8 @@ "require-dev": { "illuminate/support": "6.x|^8.18", "nesbot/carbon": "^2.43", + "phpstan/phpstan": "^0.12.92", "phpunit/phpunit": "^9.5", - "rector/rector": "^0.9.16", "spatie/phpunit-snapshot-assertions": "^4.2", "spatie/test-time": "^1.2" }, @@ -6728,7 +7312,7 @@ ], "support": { "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.27.1" + "source": "https://github.com/spatie/ray/tree/1.30.2" }, "funding": [ { @@ -6740,20 +7324,20 @@ "type": "other" } ], - "time": "2021-06-24T06:58:50+00:00" + "time": "2021-09-10T07:22:57+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.3.0", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "313d02f59d6543311865007e5ff4ace05b35ee65" + "reference": "b24c6a92c6db316fee69e38c80591e080e41536c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/313d02f59d6543311865007e5ff4ace05b35ee65", - "reference": "313d02f59d6543311865007e5ff4ace05b35ee65", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b24c6a92c6db316fee69e38c80591e080e41536c", + "reference": "b24c6a92c6db316fee69e38c80591e080e41536c", "shasum": "" }, "require": { @@ -6786,7 +7370,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v5.3.4" }, "funding": [ { @@ -6802,20 +7386,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-07-10T08:58:57+00:00" }, { "name": "symfony/yaml", - "version": "v5.3.3", + "version": "v5.3.6", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "485c83a2fb5893e2ff21bf4bfc7fdf48b4967229" + "reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/485c83a2fb5893e2ff21bf4bfc7fdf48b4967229", - "reference": "485c83a2fb5893e2ff21bf4bfc7fdf48b4967229", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7", + "reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7", "shasum": "" }, "require": { @@ -6861,7 +7445,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.3.3" + "source": "https://github.com/symfony/yaml/tree/v5.3.6" }, "funding": [ { @@ -6877,20 +7461,20 @@ "type": "tidelift" } ], - "time": "2021-06-24T08:13:00+00:00" + "time": "2021-07-29T06:20:01+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -6919,7 +7503,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -6927,34 +7511,32 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" }, { "name": "zbateson/mail-mime-parser", - "version": "1.3.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/zbateson/mail-mime-parser.git", - "reference": "706964d904798b8c22d63f62f0ec5f5bc84e30d9" + "reference": "da7b5913052d7b84fe789608761c4915281d0801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/706964d904798b8c22d63f62f0ec5f5bc84e30d9", - "reference": "706964d904798b8c22d63f62f0ec5f5bc84e30d9", + "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/da7b5913052d7b84fe789608761c4915281d0801", + "reference": "da7b5913052d7b84fe789608761c4915281d0801", "shasum": "" }, "require": { - "guzzlehttp/psr7": "^1.0", + "guzzlehttp/psr7": "^1.7.0|^2.0", "php": ">=5.4", + "pimple/pimple": "^3.0", "zbateson/mb-wrapper": "^1.0.1", - "zbateson/stream-decorators": "^1.0.4" + "zbateson/stream-decorators": "^1.0.6" }, "require-dev": { - "jms/serializer": "^1.1", "mikey179/vfsstream": "^1.6.0", - "phing/phing": "^2.15.0", - "phpdocumentor/phpdocumentor": "^2.9.0", - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5" + "sanmai/phpunit-legacy-adapter": "^6.3 || ^8.2" }, "suggest": { "ext-iconv": "For best support/performance", @@ -7002,7 +7584,7 @@ "type": "github" } ], - "time": "2020-12-02T21:55:45+00:00" + "time": "2021-08-23T02:13:55+00:00" }, { "name": "zbateson/mb-wrapper", @@ -7073,25 +7655,25 @@ }, { "name": "zbateson/stream-decorators", - "version": "1.0.4", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/zbateson/stream-decorators.git", - "reference": "6f54738dfecc65e1d5bfb855035836748083a6dd" + "reference": "3403c4323bd1cd15fe54348b031b26b064c706af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/6f54738dfecc65e1d5bfb855035836748083a6dd", - "reference": "6f54738dfecc65e1d5bfb855035836748083a6dd", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/3403c4323bd1cd15fe54348b031b26b064c706af", + "reference": "3403c4323bd1cd15fe54348b031b26b064c706af", "shasum": "" }, "require": { - "guzzlehttp/psr7": "^1.0.0", + "guzzlehttp/psr7": "^1.7.0|^2.0", "php": ">=5.4", "zbateson/mb-wrapper": "^1.0.0" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5" + "sanmai/phpunit-legacy-adapter": "^6.3 || ^8" }, "type": "library", "autoload": { @@ -7122,7 +7704,7 @@ ], "support": { "issues": "https://github.com/zbateson/stream-decorators/issues", - "source": "https://github.com/zbateson/stream-decorators/tree/master" + "source": "https://github.com/zbateson/stream-decorators/tree/1.0.6" }, "funding": [ { @@ -7130,7 +7712,7 @@ "type": "github" } ], - "time": "2020-08-10T18:59:43+00:00" + "time": "2021-07-08T19:01:59+00:00" } ], "aliases": [], @@ -7139,7 +7721,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*" }, "platform-dev": [], From 42a15c71f90185ec1e595ba4eb7a837ff08d2c5d Mon Sep 17 00:00:00 2001 From: Omid Date: Thu, 7 Oct 2021 21:11:37 +0330 Subject: [PATCH 04/27] chore: add more specific exceptions --- src/Exceptions/InvalidFilterException.php | 23 +------------------ src/Exceptions/InvalidRelationException.php | 7 ++++++ src/Exceptions/InvalidSortException.php | 7 ++++++ src/Exceptions/InvalidSumException.php | 7 ++++++ src/Exceptions/QueryFilterException.php | 25 +++++++++++++++++++++ 5 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 src/Exceptions/InvalidRelationException.php create mode 100644 src/Exceptions/InvalidSortException.php create mode 100644 src/Exceptions/InvalidSumException.php create mode 100644 src/Exceptions/QueryFilterException.php diff --git a/src/Exceptions/InvalidFilterException.php b/src/Exceptions/InvalidFilterException.php index b52c13d..ff64d2e 100644 --- a/src/Exceptions/InvalidFilterException.php +++ b/src/Exceptions/InvalidFilterException.php @@ -2,27 +2,6 @@ namespace Omalizadeh\QueryFilter\Exceptions; -use Exception; -use Illuminate\Http\Request; - -class InvalidFilterException extends Exception +class InvalidFilterException extends QueryFilterException { - protected $message; - protected $code; - - public function __construct( - $message, - $code = 422 - ) { - parent::__construct($message, $code); - $this->message = $message; - $this->code = $code; - } - - public function render(Request $request) - { - return response()->json([ - 'message' => $this->message - ], $this->code); - } } diff --git a/src/Exceptions/InvalidRelationException.php b/src/Exceptions/InvalidRelationException.php new file mode 100644 index 0000000..c83a668 --- /dev/null +++ b/src/Exceptions/InvalidRelationException.php @@ -0,0 +1,7 @@ +message = $message; + $this->code = $code; + } + + public function render(): \Illuminate\Http\JsonResponse + { + return response()->json([ + 'message' => $this->message + ], $this->code); + } +} From d39fd75ae6f0f587c81e1bdecc31d3df5b60e6b7 Mon Sep 17 00:00:00 2001 From: Omid Date: Thu, 7 Oct 2021 21:12:06 +0330 Subject: [PATCH 05/27] package structure overhaul --- src/Console/MakeFilterCommand.php | 2 +- src/Console/stubs/filter.php.stub | 54 ++- src/Filter.php | 672 +++++++++-------------------- src/ModelFilter.php | 150 +++++++ src/QueryFilter.php | 404 ++++++++--------- src/QueryFilterResult.php | 40 ++ src/QueryFilterServiceProvider.php | 5 + src/Traits/HasFilter.php | 8 +- tests/CommandTest.php | 2 +- tests/Filters/UserFilter.php | 36 +- tests/Models/User.php | 11 +- tests/QueryFilterTest.php | 23 +- tests/TestCase.php | 18 +- 13 files changed, 705 insertions(+), 720 deletions(-) create mode 100644 src/ModelFilter.php create mode 100644 src/QueryFilterResult.php diff --git a/src/Console/MakeFilterCommand.php b/src/Console/MakeFilterCommand.php index 5c4120b..2804fa2 100644 --- a/src/Console/MakeFilterCommand.php +++ b/src/Console/MakeFilterCommand.php @@ -17,7 +17,7 @@ protected function getStub() protected function getDefaultNamespace($rootNamespace) { - return $rootNamespace . '\Http\Filters'; + return $rootNamespace . '\Filters'; } protected function getArguments() diff --git a/src/Console/stubs/filter.php.stub b/src/Console/stubs/filter.php.stub index 9b5c5ef..b3ba447 100644 --- a/src/Console/stubs/filter.php.stub +++ b/src/Console/stubs/filter.php.stub @@ -2,24 +2,50 @@ namespace {{ namespace }}; -use Omalizadeh\QueryFilter\Filter; -use Illuminate\Http\Request; +use Omalizadeh\QueryFilter\ModelFilter; -class {{ class }} extends Filter +class {{ class }} extends ModelFilter { - public function __construct(Request $request) + public function getSortableAttributes(): array { - parent::__construct($request); - $this->sortableAttributes = []; - $this->filterableAttributes = []; - $this->filterableRelations = []; - $this->loadableRelations = []; - $this->summableAttributes = []; + return [ + // + ]; + } + + public function getSummableAttributes(): array + { + return [ + // + ]; + } + + public function getFilterableAttributes(): array + { + return [ + // + ]; + } - // Max valid limit for pagination (records per page) - $this->maxPaginationLimit = 1000; + /** + * 'relation_name' => [ + * 'filter_key' => 'db_origin_key', + * ], + * 'relation_name' => [ + * 'filter_and_db_key', + * ], + */ + public function getFilterableRelations(): array + { + return [ + // + ]; + } - // Data can be accessed without pagination - $this->hasFiltersWithoutPagination = true; + public function getLoadableRelations(): array + { + return [ + // + ]; } } diff --git a/src/Filter.php b/src/Filter.php index 2f9aef0..22cb282 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -2,533 +2,237 @@ namespace Omalizadeh\QueryFilter; -use JsonException; -use RuntimeException; +use Illuminate\Contracts\Support\Jsonable; use Illuminate\Support\Arr; -use Illuminate\Http\Request; -use Illuminate\Database\Eloquent\Builder; +use JsonException; use Omalizadeh\QueryFilter\Exceptions\InvalidFilterException; +use Omalizadeh\QueryFilter\Exceptions\InvalidRelationException; +use Omalizadeh\QueryFilter\Exceptions\InvalidSortException; +use Omalizadeh\QueryFilter\Exceptions\InvalidSumException; -class Filter extends QueryFilter +class Filter implements Jsonable { - protected $builder; - protected $request; - protected $filterableAttributes = []; - protected $sortableAttributes = []; - protected $filterableRelations = []; - protected $loadableRelations = []; - protected $summableAttributes = []; - protected $maxPaginationLimit = 1000; - protected $hasFiltersWithoutPagination = true; + protected array $filterGroups = []; + protected array $sorts = []; + protected array $sums = []; + protected array $relations = []; + protected ?int $offset = null; + protected ?int $limit = null; + + public function __construct( + array $filterGroups = [], + array $sorts = [], + array $sums = [], + array $relations = [], + ?int $offset = null, + ?int $limit = null + ) { + $this->setFilterGroups($filterGroups); + $this->setSorts($sorts); + $this->setSums($sums); + $this->setRelations($relations); + $this->setOffset($offset); + $this->setLimit($limit); + } + + public function setFilterGroups(array $filterGroups): Filter + { + foreach ($filterGroups as $filterGroup) { + foreach ($filterGroup as &$filter) { + $filter = $this->validateFilter($filter); + } - /** - * Filter constructor. - * - * @param Request $request - * - * @throws \JsonException - */ - public function __construct(Request $request) - { - $this->request = $request; - $this->setParameters(); - } + $this->filterGroups[] = $filterGroup; + } - public function getRequest(): Request - { - return $this->request; + return $this; } - /** - * @throws \JsonException - */ - protected function setParameters(): void + public function addFilterGroup(array $filterGroup): Filter { - try { - $requestData = json_decode( - $this->getRequest()->input('filter', '{}'), - true, - 512, - JSON_THROW_ON_ERROR - ); - } catch (JsonException $ex) { - throw new InvalidFilterException('Cannot parse json filter. check json structure.'); - } - $sortData = Arr::get($requestData, 'sort', []); - if (!empty($sortData)) { - $this->setSortData($sortData); - } - $page = Arr::get($requestData, 'page', []); - if (!empty($page)) { - $this->setPage($page); - } - $filters = Arr::get($requestData, 'filters', []); - if (!empty($filters)) { - $this->setFilters($filters); - } - $withs = Arr::get($requestData, 'with', []); - if (!empty($withs)) { - $this->setLoadRelations($withs); - } - $sums = Arr::get($requestData, 'sum', []); - if (!empty($sums)) { - $this->setSumFields($sums); + foreach ($filterGroup as &$filter) { + $filter = $this->validateFilter($filter); } - } - /** - * @param $builder - * - * @return array - */ - public function apply($builder): array - { - if ($this->hasFilter()) { - $builder = $this->applyFilters($builder); - } - if ($this->hasWith()) { - $builder = $this->load($builder); - } - if ($this->hasSum()) { - $sum = $this->sum($builder); - } - if ($this->hasSort()) { - $builder = $this->sort($builder); - } - $count = $builder->count(); - $builder = $this->applyPagination($builder); - $this->builder = $builder; + $this->filterGroups[] = $filterGroup; - return array($builder, $count, $sum ?? []); + return $this; } - public function toSql() + public function addFilter(string $field, string $op, $value): Filter { - if (!$this->builder instanceof Builder) { - throw new RuntimeException("Builder is not created."); - } - $bindings = $this->builder->getBindings(); - $sql = str_replace('?', '%s', $this->builder->toSql()); - return vsprintf($sql, $bindings); - } + $this->validateOperator($op); - public function getFilterFields(): array - { - $filters = $this->getFilters(); - $fields = []; - foreach ($filters as $filter) { - $fields[] = collect($filter)->pluck('field')->toArray(); - } - $fields = array_unique(Arr::flatten($fields)); - return array_intersect($this->filterableAttributes, $fields); + $this->filterGroups[] = [ + [ + 'field' => $field, + 'op' => $op, + 'value' => $value + ] + ]; + + return $this; } - protected function applyPagination(Builder $entries): Builder + public function setSorts(array $sorts): Filter { - if ($this->hasPage()) { - if ($this->getLimit() > $this->getMaxPaginationLimit()) { - $this->setLimit($this->getMaxPaginationLimit()); + foreach ($sorts as $sort) { + if (!is_array($sort)) { + throw new InvalidSortException('Sort must be an array containing field and dir.'); } - return $this->paginate($entries); - } elseif (!$this->canFilterWithoutPagination()) { - $this->setLimit($this->getMaxPaginationLimit()); - $this->setOffset(0); + if (!isset($sort['field'], $sort['dir'])) { + throw new InvalidSortException('Field or dir key not found in sort array.'); + } - return $this->paginate($entries); + $this->sort($sort['field'], $sort['dir']); } - return $entries; + return $this; } - protected function paginate(Builder $entries): Builder + public function setPage(int $offset, int $limit): Filter { - $entries = $entries->limit($this->getLimit()); - $entries = $entries->offset($this->getOffset()); + $this->setOffset($offset); + $this->setLimit($limit); - return $entries; + return $this; } - /** - * @param Builder $entries - * - * @return Builder - */ - protected function applyFilters(Builder $entries): Builder + public function setSums(array $sums): Filter { - foreach ($this->getFilters() as $filters) { - $entries = $this->applyFilter($filters, $entries); + foreach ($sums as $sum) { + if (!is_string($sum) || empty($sum)) { + throw new InvalidSumException('Sums array must contain only non-empty strings of field names.'); + } + + $this->sum($sum); } - return $entries; + + return $this; } - /** - * @param $filters - * @param $entries - * - * @return Builder - */ - protected function applyFilter($filters, $entries): Builder + public function setRelations(array $relations): Filter { - return $entries->where(function ($query) use ($filters) { - foreach ($filters as $filterKey => $item) { - $item = $this->sanitizeFilter($item); - if (!$this->filterRelations($query, $item, $filterKey === 0)) { - if ($this->hasFilterableAttribute($item->field)) { - if ($filterKey === 0) { - $this->where($query, $item); - } else { - $this->orWhere($query, $item); - } - } else { - continue; - } - } + foreach ($relations as $relation) { + if (!is_string($relation) || empty($relation)) { + throw new InvalidRelationException('Relations array must contain only non-empty strings.'); } - }); - } - /** - * @param $query - * @param $item - * - * @return Builder - */ - protected function where($query, $item): Builder - { - if ($this->isWhereNull($item)) { - return $this->whereNull($query, $item->field); - } - if ($this->isWhereNotNull($item)) { - return $this->whereNotNull($query, $item->field); - } - if ($this->isWhereIn($item)) { - return $this->whereIn($query, $item); + $this->with($relation); } - if ($this->isWhereNotIn($item)) { - return $this->whereNotIn($query, $item); - } - return $query->where($item->field, $item->op, $item->value); - } - /** - * @param $query - * @param $item - * - * @return mixed - */ - protected function orWhere($query, $item) - { - if ($this->isWhereNull($item)) { - return $this->whereNull($query, $item->field, true); - } - if ($this->isWhereNotNull($item)) { - return $this->whereNotNull($query, $item->field, true); - } - if ($this->isWhereIn($item)) { - return $this->whereIn($query, $item, true); - } - if ($this->isWhereNotIn($item)) { - return $this->whereNotIn($query, $item, true); - } - return $query->orWhere($item->field, $item->op, $item->value); + return $this; } - /** - * @param $query - * @param $item - * - * @return mixed - */ - protected function whereIn($query, $item, bool $orCondition = false) + public function sort(string $field, string $dir = 'asc'): Filter { - if ($orCondition) { - return $query->orWhereIn($item->field, $item->value); - } - return $query->whereIn($item->field, $item->value); - } + $this->sorts[] = [ + 'field' => $field, + 'dir' => strtolower($dir) === 'desc' ? 'desc' : 'asc' + ]; - /** - * @param $query - * @param $item - * - * @return mixed - */ - protected function whereNotIn($query, $item, bool $orCondition = false) - { - if ($orCondition) { - return $query->orWhereNotIn($item->field, $item->value); - } - return $query->whereNotIn($item->field, $item->value); + return $this; } - /** - * @param $query - * @param $columns - * @param bool $orCondition - * - * @return mixed - */ - protected function whereNull($query, $columns, bool $orCondition = false) + public function sum(string $field): Filter { - if ($orCondition) { - return $query->orWhereNull($columns); - } - return $query->whereNull($columns); - } + $this->sums[] = $field; - /** - * @param $query - * @param $columns - * @param bool $orCondition - * @param false $not - * - * @return mixed - */ - protected function whereNotNull($query, $columns, bool $orCondition = false) - { - if ($orCondition) { - return $query->orWhereNotNull($columns); - } - return $query->whereNotNull($columns); + return $this; } - /** - * relations = [ - * 'relation_name' => [ - * 'destination_key' => 'origin_key' - * ] - * ] - * - * @param $query - * @param $item - * @param bool $isWhere - * - * @return mixed - */ - protected function filterRelations(&$query, $item, bool $firstKey = true) + public function with(string $relation): Filter { - if (!$this->hasAnyFilterableRelation()) { - return false; - } - foreach ($this->filterableRelations as $relationName => $params) { - $relationKey = $this->hasFilterableRelation($params, $item); - if ($relationKey !== false) { - $item = $this->setFilterRelationKey($item, $relationKey); - $query = $this->filterRelation( - $query, - $item, - $relationName, - !$firstKey - ); - return true; - } - } - return false; - } + $this->relations[] = $relation; - /** - * @param $relationProperties - * @param $filter - * - * @return false|int|string - */ - protected function hasFilterableRelation($relationProperties, $filter) - { - if (empty($relationProperties)) { - return false; - } - if (!is_array($relationProperties)) { - $relationProperties = [$relationProperties]; - } - return $relationProperties[$filter->field] ?? - array_search($filter->field, $relationProperties, true); + return $this; } - /** - * @param $item 'filterObject' - * @param $keyName - * - * @return object $filter - */ - protected function setFilterRelationKey($item, $keyName) + public function setLimit(?int $limit): Filter { - if (!empty($keyName) and is_string($keyName)) { - $item->field = $keyName; - } - return $item; - } + $this->limit = $limit; - /** - * @param $entries - * @param $filter - * @param $relation - * @param $orCondition - * - * @return Builder - */ - protected function filterRelation($entries, $filter, $relation, bool $orCondition = false): Builder - { - if ($orCondition) { - return $entries->orWhereHas($relation, function ($query) use ($filter) { - $this->where($query, $filter); - }); - } - return $entries->whereHas($relation, function ($query) use ($filter) { - $this->where($query, $filter); - }); + return $this; } - /** - * @param $entries - * - * @return Builder - */ - protected function load($entries): Builder + public function setOffset(?int $offset): Filter { - foreach ($this->getLoadRelations() as $load) { - if ($this->hasLoadableRelation($load)) { - $entries = $entries->with($load); - } - } - return $entries; - } + $this->offset = $offset; - /** - * @param $entries - * - * @return Builder - */ - protected function sort($entries): Builder - { - foreach ($this->getSortData() as $sort) { - $sort = $this->sanitizeSort($sort); - $field = $sort->field; - if ($this->hasSortableAttribute($field)) { - $dir = $sort->dir; - $entries = $entries->orderBy($field, $dir); - } - } - return $entries; + return $this; } - protected function sum($entries): array + public function getFilterFields(): array { - $sum = array(); - foreach ($this->getSumFields() as $sumField) { - if ($this->hasSummableAttribute($sumField)) { - $sum[$sumField] = $entries->sum($sumField); - } + $filterGroups = $this->getFilterGroups(); + $fields = []; + + foreach ($filterGroups as $filter) { + $fields[] = collect($filter)->pluck('field')->toArray(); } - return $sum; + + return array_unique(Arr::flatten($fields)); } /** - * @param object $filter - * - * @return object $filter + * @return array */ - protected function sanitizeFilter(object $filter) + public function getFilterGroups(): array { - if ($this->isValidOperator($filter->op)) { - if (is_array($filter->value) and !in_array($filter->op, ['in', 'not'], true)) { - if ($filter->op === '=') { - $filter->op = 'in'; - } else { - $filter->op = 'not'; - } - } elseif ($filter->op === 'like' or $filter->op === 'not like') { - $filter->value = '%' . $filter->value . '%'; - } elseif ($filter->op === 'is' and $filter->value !== null) { - $filter->op = '='; - } elseif ($filter->op === '=' and $filter->value === null) { - $filter->op = 'is'; - } elseif (($filter->op === '!=' or $filter->op === '<>') and $filter->value === null) { - $filter->op = 'not'; - } - return $filter; - } - throw new InvalidFilterException('Filter operator is invalid. unknown op: ' . $filter->op); + return $this->filterGroups; } /** - * @param object $sort - * - * @return object $sort + * @return array */ - protected function sanitizeSort(object $sort) + public function getSums(): array { - if ($sort->dir === 'desc') { - return $sort; - } - $sort->dir = 'asc'; - return $sort; + return $this->sums; } - protected function getMaxPaginationLimit() + public function getPage(): array { - return $this->maxPaginationLimit; + return [ + 'limit' => $this->getLimit(), + 'offset' => $this->getOffset() + ]; } - protected function canFilterWithoutPagination() + public function getLimit(): ?int { - return (bool) $this->hasFiltersWithoutPagination; + return $this->limit; } - /** - * @param $item - * - * @return bool - */ - protected function isWhereIn($item): bool + public function getOffset(): ?int { - return ($item->op === 'in' and is_array($item->value)); + return $this->offset; } - /** - * @param $item - * - * @return bool - */ - protected function isWhereNotIn($item): bool + public function getRelations(): array { - return ($item->op === 'not' and is_array($item->value)); + return $this->relations; } - /** - * @param $item - * - * @return bool - */ - protected function isWhereNull($item): bool - { - return ($item->op === 'is' and $item->value === null); - } - - /** - * @param $item - * - * @return bool - */ - protected function isWhereNotNull($item): bool + public function getSorts(): array { - return ($item->op === 'not' and $item->value === null); + return $this->sorts; } /** * @return bool */ - public function hasFilter(): bool + public function hasAnyFilterGroup(): bool { - return !empty($this->filters); + return !empty($this->getFilterGroups()); } /** * @return bool */ - public function hasWith(): bool + public function hasRelations(): bool { - return !empty($this->loadRelations); + return !empty($this->getRelations()); } /** @@ -536,7 +240,7 @@ public function hasWith(): bool */ public function hasPage(): bool { - return $this->hasOffset() and $this->hasLimit(); + return $this->hasOffset() && $this->hasLimit(); } /** @@ -544,7 +248,7 @@ public function hasPage(): bool */ public function hasSort(): bool { - return !empty($this->sortData); + return !empty($this->getSorts()); } /** @@ -552,66 +256,112 @@ public function hasSort(): bool */ public function hasSum(): bool { - return !empty($this->sumFields); + return !empty($this->getSums()); } /** * @return bool */ - protected function hasLimit(): bool + public function hasLimit(): bool { - return !empty($this->limit); + return !is_null($this->getLimit()); } /** * @return bool */ - protected function hasOffset(): bool + public function hasOffset(): bool { - return isset($this->offset); + return !is_null($this->getOffset()); } - /** - * @return bool - */ - protected function hasAnyFilterableRelation(): bool - { - return !empty($this->filterableRelations); - } /** - * @return bool + * Convert filter to JSON string. + * + * @param int $options + * @return string + * @throws JsonException */ - protected function hasFilterableAttribute($fieldName): bool + public function toJson($options = 0): string { - return !empty($this->filterableAttributes) - and in_array($fieldName, $this->filterableAttributes, true); + $data = []; + + if (!empty($this->getFilterGroups())) { + $data['filters'] = $this->getFilterGroups(); + } + + if (!empty($this->getSorts())) { + $data['sorts'] = $this->getSorts(); + } + + if (!empty($this->getRelations())) { + $data['relations'] = $this->getRelations(); + } + + if (!empty($this->getSums())) { + $data['sums'] = $this->getSums(); + } + + if (!empty($this->getPage())) { + $data['page'] = $this->getPage(); + } + + return json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | $options); } /** - * @return bool + * @throws InvalidFilterException */ - protected function hasLoadableRelation($relationName): bool + protected function validateFilter(array $filter): array { - return !empty($this->loadableRelations) - and in_array($relationName, $this->loadableRelations, true); + if (!isset($filter['field']) || !is_string($filter['field'])) { + throw new InvalidFilterException('Filter field key not found or is invalid.'); + } + + if (!isset($filter['op']) || !is_string($filter['op'])) { + throw new InvalidFilterException('Filter op key not found or is invalid.'); + } + + if (!array_key_exists('value', $filter)) { + throw new InvalidFilterException('Value not found in filter.'); + } + + $this->validateOperator($filter['op']); + + if (is_array($filter['value']) && !in_array($filter['op'], ['in', 'not'], true)) { + $filter['op'] = ($filter['op'] === '=') ? 'in' : 'not'; + } elseif ($filter['op'] === 'like' || $filter['op'] === 'not like') { + $filter['value'] = '%'.$filter['value'].'%'; + } elseif ($filter['value'] === null) { + $filter['op'] = ($filter['op'] === '!=' || $filter['op'] === '<>' || $filter['op'] === 'not') ? 'not' : 'is'; + } + + return $filter; } - /** - * @return bool - */ - protected function hasSortableAttribute($fieldName): bool + protected function validateOperator(string $op): void { - return !empty($this->sortableAttributes) - and in_array($fieldName, $this->sortableAttributes, true); + if (!in_array($op, $this->getValidOperators(), true)) { + throw new InvalidFilterException("Invalid operator in filter: $op"); + } } - /** - * @return bool - */ - protected function hasSummableAttribute($fieldName): bool + protected function getValidOperators(): array { - return !empty($this->summableAttributes) - and in_array($fieldName, $this->summableAttributes, true); + return [ + '=', + '>', + '>=', + '<', + '<=', + '!=', + '<>', + 'like', + 'not like', + 'is', + 'not', + 'in' + ]; } } diff --git a/src/ModelFilter.php b/src/ModelFilter.php new file mode 100644 index 0000000..7388987 --- /dev/null +++ b/src/ModelFilter.php @@ -0,0 +1,150 @@ +request = $request; + $this->filter = $this->createFilterFromRequest(); + } + + abstract public function getSortableAttributes(): array; + + abstract public function getSummableAttributes(): array; + + abstract public function getFilterableAttributes(): array; + + abstract public function getFilterableRelations(): array; + + abstract public function getLoadableRelations(): array; + + public function getMaxPaginationLimit(): int + { + return $this->maxPaginationLimit; + } + + public function getRequest(): Request + { + return $this->request; + } + + public function getFilter(): Filter + { + return $this->filter; + } + + public function setFilter(Filter $filter): ModelFilter + { + $this->filter = $filter; + return $this; + } + + public function hasFilterableAttribute(string $attribute): bool + { + return in_array($attribute, $this->getFilterableAttributes(), true); + } + + public function hasFilterableRelation(string $relationAttribute) + { + foreach ($this->getFilterableRelations() as $relationName => $filterableRelationAttributes) { + if (!is_array($filterableRelationAttributes) && $filterableRelationAttributes === $relationAttribute) { + return [$relationName, $relationAttribute]; + } + if (isset($filterableRelationAttributes[$relationAttribute])) { + return [$relationName, $filterableRelationAttributes[$relationAttribute]]; + } + if (in_array($relationAttribute, $filterableRelationAttributes, true) !== false) { + return [$relationName, $relationAttribute]; + } + } + + return false; + } + + public function hasSortableAttribute(string $attribute): bool + { + return in_array($attribute, $this->getSortableAttributes(), true); + } + + public function hasSummableAttribute(string $attribute): bool + { + return in_array($attribute, $this->getSummableAttributes(), true); + } + + public function hasLoadableRelation(string $relation): bool + { + return in_array($relation, $this->getLoadableRelations(), true); + } + + /** + * @throws Exceptions\InvalidSortException + * @throws Exceptions\InvalidRelationException + * @throws InvalidFilterException + * @throws Exceptions\InvalidSumException + */ + protected function createFilterFromRequest(): Filter + { + try { + $requestData = json_decode( + $this->getRequest()->input('filter', '{}'), + true, + 512, + JSON_THROW_ON_ERROR + ); + } catch (JsonException $ex) { + throw new InvalidFilterException('Cannot parse json filter. check json structure.'); + } + + $filter = new Filter(); + + $sortData = Arr::get($requestData, 'sorts'); + if (!empty($sortData)) { + $filter->setSorts($sortData); + } + + $limit = Arr::get($requestData, 'page.limit'); + if (!empty($limit)) { + $filter->setLimit($limit); + } + + $offset = Arr::get($requestData, 'page.offset'); + if (!empty($offset)) { + $filter->setLimit($offset); + } + + $filterGroups = Arr::get($requestData, 'filters'); + if (!empty($filterGroups)) { + $filter->setFilterGroups($filterGroups); + } + + $relations = Arr::get($requestData, 'relations'); + if (!empty($relations)) { + $filter->setRelations($relations); + } + + $sums = Arr::get($requestData, 'sums'); + if (!empty($sums)) { + $filter->setSums($sums); + } + + return $filter; + } +} diff --git a/src/QueryFilter.php b/src/QueryFilter.php index e7ed151..37814b4 100644 --- a/src/QueryFilter.php +++ b/src/QueryFilter.php @@ -2,301 +2,307 @@ namespace Omalizadeh\QueryFilter; -use Illuminate\Contracts\Support\Jsonable; -use Illuminate\Support\Arr; -use Omalizadeh\QueryFilter\Exceptions\InvalidFilterException; +use Illuminate\Database\Eloquent\Builder; -class QueryFilter implements Jsonable +class QueryFilter { - protected $filters = []; - protected $sortData = []; - protected $sumFields = []; - protected $loadRelations = []; - protected $offset = null; - protected $limit = null; - - public function __construct(array $filtersList = []) + protected Builder $builder; + protected ModelFilter $modelFilter; + + public function __construct(Builder $builder, ModelFilter $modelFilter) { - $this->setFilters($filtersList); + $this->builder = $builder; + $this->modelFilter = $modelFilter; } /** - * @param array $filters - * - * @return $this + * @return QueryFilterResult */ - public function addFilter(array $filters): QueryFilter + public function applyFilter(): QueryFilterResult { - $filters = $this->prepareFilter($filters); - $this->filters[] = $filters; - return $this; - } + if ($this->getFilter()->hasAnyFilterGroup()) { + $this->applyFilterGroups(); + } - public function addMagicFilter(array $filter) - { - $key = key($filter); - $filter = ['field' => $key, 'op' => '=', 'value' => $filter[$key]]; - return $this->addFilter([$filter]); - } + if ($this->getFilter()->hasRelations()) { + $this->load(); + } - /** - * @param $filters - * - * @return mixed - */ - protected function prepareFilter($filters) - { - $keys = ['field', 'op', 'value']; - $constFilters = $filters; - foreach ($filters as &$filter) { - $filter = Arr::only((array)$filter, $keys); - if (count($filter) !== 3) { - throw new InvalidFilterException('invalid filter. filter must have these keys: ' . - join(', ', $keys) . - ". input filter: " . print_r($constFilters, true)); - } - $filter = (object)$filter; + if ($this->getFilter()->hasSum()) { + $sums = $this->sum(); } - return $filters; + + if ($this->getFilter()->hasSort()) { + $this->sort(); + } + + $this->applyPagination(); + + return new QueryFilterResult($this->getBuilder(), $this->getBuilder()->count(), $sums ?? []); } - /** - * @param $field - * @param $dir - * - * @return QueryFilter - */ - public function orderBy(string $field, string $dir) + protected function applyPagination(): Builder { - return $this->addOrderBy([ - 'field' => $field, - 'dir' => $dir - ]); + if (!$this->getFilter()->hasLimit() || $this->getFilter()->getLimit() > $this->getModelFilter()->getMaxPaginationLimit()) { + $this->getFilter()->setLimit($this->getModelFilter()->getMaxPaginationLimit()); + } + + if (!$this->getFilter()->hasOffset()) { + $this->getFilter()->setOffset(0); + } + + return $this->paginate(); } - /** - * @param $sortData - * - * @return $this - */ - public function addOrderBy(array $sortData): QueryFilter + protected function paginate(): Builder { - $sortData = $this->prepareOrderBy($sortData); - $this->sortData[] = $sortData; - return $this; + return $this->getBuilder()->limit($this->getFilter()->getLimit())->offset($this->getFilter()->getOffset()); } - /** - * @param $sortData - * - * @return array - */ - protected function prepareOrderBy($sortData) + protected function applyFilterGroups(): void { - $constSortData = $sortData; - $sortData = Arr::only($sortData, ['field', 'dir']); - if (count($sortData) !== 2) { - throw new InvalidFilterException('invalid order data. ' . print_r($constSortData, true)); + foreach ($this->getFilter()->getFilterGroups() as $filterGroup) { + $this->applyFilters($filterGroup); } - return (object) $sortData; } - /** - * @return array - */ - public function getSortData(): array + protected function applyFilters(array $filterGroup): void { - return $this->sortData; + $this->getBuilder()->where(function (Builder $query) use ($filterGroup) { + foreach ($filterGroup as $filterKey => $filter) { + if ( + !$this->filterRelations($query, $filter, $filterKey === 0) && + $this->getModelFilter()->hasFilterableAttribute($filter['field']) + ) { + $filterKey === 0 ? $this->where($query, $filter) : $this->orWhere($query, $filter); + } + } + }); } - /** - * @param array $sortDataList - * - * @return QueryFilter - */ - public function setSortData(array $sortDataList): QueryFilter + protected function where(Builder $query, array $filter): Builder { - foreach ($sortDataList as $sortData) { - $this->addOrderBy($sortData); + if ($this->isWhereNull($filter)) { + return $this->whereNull($query, $filter['field']); + } + if ($this->isWhereNotNull($filter)) { + return $this->whereNotNull($query, $filter['field']); + } + if ($this->isWhereIn($filter)) { + return $this->whereIn($query, $filter); + } + if ($this->isWhereNotIn($filter)) { + return $this->whereNotIn($query, $filter); } - return $this; - } - /** - * @return array - */ - public function getPage(): array - { - return [ - 'limit' => $this->getLimit(), - 'offset' => $this->getOffset() - ]; + return $query->where($filter['field'], $filter['op'], $filter['value']); } /** - * @param array $page - * - * @return QueryFilter + * @param Builder $query + * @param array $filter + * @return Builder */ - public function setPage(array $page): QueryFilter + protected function orWhere(Builder $query, array $filter): Builder { - if (!empty($page['limit']) and is_int($page['limit'])) { - $this->setLimit($page['limit']); + if ($this->isWhereNull($filter)) { + return $this->whereNull($query, $filter['field'], true); } - if (isset($page['offset']) and is_int($page['offset'])) { - $this->setOffset($page['offset']); + if ($this->isWhereNotNull($filter)) { + return $this->whereNotNull($query, $filter['field'], true); + } + if ($this->isWhereIn($filter)) { + return $this->whereIn($query, $filter, true); + } + if ($this->isWhereNotIn($filter)) { + return $this->whereNotIn($query, $filter, true); } - return $this; - } - public function getOffset(): ?int - { - return $this->offset; + return $query->orWhere($filter['field'], $filter['op'], $filter['value']); } /** - * @param $offset - * - * @return QueryFilter + * @param Builder $query + * @param array $filter + * @param bool $orCondition + * @return Builder */ - public function setOffset(int $offset): QueryFilter + protected function whereIn(Builder $query, array $filter, bool $orCondition = false): Builder { - $this->offset = $offset; - return $this; - } + if ($orCondition) { + return $query->orWhereIn($filter['field'], $filter['value']); + } - public function getLimit(): ?int - { - return $this->limit; + return $query->whereIn($filter['field'], $filter['value']); } /** - * @param $limit - * - * @return QueryFilter + * @param Builder $query + * @param array $filter + * @param bool $orCondition + * @return Builder */ - public function setLimit(int $limit): QueryFilter + protected function whereNotIn(Builder $query, array $filter, bool $orCondition = false):Builder { - $this->limit = $limit; - return $this; + if ($orCondition) { + return $query->orWhereNotIn($filter['field'], $filter['value']); + } + + return $query->whereNotIn($filter['field'], $filter['value']); } /** - * @return array + * @param Builder $query + * @param string $column + * @param bool $orCondition + * @return Builder */ - public function getFilters(): array + protected function whereNull(Builder $query, string $column, bool $orCondition = false): Builder { - return $this->filters; + if ($orCondition) { + return $query->orWhereNull($column); + } + + return $query->whereNull($column); } /** - * @return array + * @param Builder $query + * @param string $column + * @param bool $orCondition + * @return Builder */ - public function getLoadRelations(): array + protected function whereNotNull(Builder $query, string $column, bool $orCondition = false): Builder { - return $this->loadRelations; + if ($orCondition) { + return $query->orWhereNotNull($column); + } + + return $query->whereNotNull($column); } - public function setLoadRelations(array $loadRelations): QueryFilter + protected function filterRelations(Builder $query, array $filter, bool $firstKey = true): bool { - foreach ($loadRelations as $relation) { - $this->addLoadRelation($relation); + if (($relationInfo = $this->getModelFilter()->hasFilterableRelation($filter['field'])) !== false) { + [$relationName, $relationAttribute] = $relationInfo; + $filter['field'] = $relationAttribute; + + $this->filterRelation($query, $filter, $relationName, !$firstKey); + + return true; } - return $this; - } - public function addLoadRelation(string $loadRelation): QueryFilter - { - $this->loadRelations[] = $loadRelation; - return $this; + return false; } /** - * @param array $filtersList + * @param Builder $query + * @param array $filter + * @param string $relationName + * @param bool $orCondition * - * @return QueryFilter + * @return Builder */ - public function setFilters(array $filtersList): QueryFilter - { - foreach ($filtersList as $filters) { - $this->addFilter($filters); + protected function filterRelation( + Builder $query, + array $filter, + string $relationName, + bool $orCondition = false + ): Builder { + if ($orCondition) { + return $query->orWhereHas($relationName, function ($query) use ($filter) { + $this->where($query, $filter); + }); } - return $this; + + return $query->whereHas($relationName, function ($query) use ($filter) { + $this->where($query, $filter); + }); } - public function getSumFields(): array + protected function load(): void { - return $this->sumFields; + foreach ($this->getFilter()->getRelations() as $relation) { + if ($this->getModelFilter()->hasLoadableRelation($relation)) { + $this->getBuilder()->with($relation); + } + } } - public function setSumFields(array $sumFieldsList): QueryFilter + protected function sort(): void { - foreach ($sumFieldsList as $sumField) { - $this->addSumField($sumField); + foreach ($this->getFilter()->getSorts() as $sort) { + if ($this->getModelFilter()->hasSortableAttribute($sort['field'])) { + $this->getBuilder()->orderBy($sort['field'], $sort['dir']); + } } - return $this; } - public function addSumField(string $sumField) + protected function sum(): array { - return $this->sumFields[] = $sumField; + $sum = array(); + + foreach ($this->getFilter()->getSums() as $sumField) { + if ($this->getModelFilter()->hasSummableAttribute($sumField)) { + $sum[$sumField] = $this->getBuilder()->sum($sumField); + } + } + + return $sum; } /** + * @param $filter + * * @return bool */ - protected function isValidOperator($op): bool + protected function isWhereIn($filter): bool { - $operators = [ - '=', - '>', - '>=', - '<', - '<=', - '!=', - '<>', - 'like', - 'not like', - 'is', - 'not', - 'in' - ]; - return in_array($op, $operators, true); + return ($filter['op'] === 'in' and is_array($filter['value'])); } /** - * Encode a value as JSON. + * @param $filter * - * @param int $options + * @return bool + */ + protected function isWhereNotIn($filter): bool + { + return ($filter['op'] === 'not' and is_array($filter['value'])); + } + + /** + * @param $filter * - * @return string - * @throws \JsonException + * @return bool */ - public function toJson($options = 0) + protected function isWhereNull($filter): bool { - $options |= JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; - $data = []; - if (!empty($this->getFilters())) { - $data['filters'] = $this->getFilters(); - } - if (!empty($this->getPage())) { - $data['page'] = $this->getPage(); - } - if (!empty($this->getSortData())) { - $data['sort'] = $this->getSortData(); - } - if (!empty($this->getLoadRelations())) { - $data['with'] = $this->getLoadRelations(); - } - return json_encode($data, JSON_THROW_ON_ERROR | $options); + return ($filter['op'] === 'is' and $filter['value'] === null); } /** - * @return string - * @throws \JsonException + * @param $filter + * + * @return bool */ - public function __toString() + protected function isWhereNotNull($filter): bool + { + return ($filter['op'] === 'not' and $filter['value'] === null); + } + + protected function getFilter(): Filter + { + return $this->getModelFilter()->getFilter(); + } + + protected function getModelFilter(): ModelFilter + { + return $this->modelFilter; + } + + protected function getBuilder(): Builder { - return $this->toJson(); + return $this->builder; } } diff --git a/src/QueryFilterResult.php b/src/QueryFilterResult.php new file mode 100644 index 0000000..ba1f22a --- /dev/null +++ b/src/QueryFilterResult.php @@ -0,0 +1,40 @@ +builder = $builder; + $this->count = $count; + $this->sums = $sums; + } + + public function getCount(): int + { + return $this->count; + } + + public function getSums(): array + { + return $this->sums; + } + + public function getBuilder(): Builder + { + return $this->builder; + } + + public function getData(): Collection + { + return $this->builder->get(); + } +} diff --git a/src/QueryFilterServiceProvider.php b/src/QueryFilterServiceProvider.php index 92953bb..fb78b62 100644 --- a/src/QueryFilterServiceProvider.php +++ b/src/QueryFilterServiceProvider.php @@ -7,6 +7,11 @@ class QueryFilterServiceProvider extends ServiceProvider { + public function register() + { + // + } + public function boot() { if ($this->app->runningInConsole()) { diff --git a/src/Traits/HasFilter.php b/src/Traits/HasFilter.php index e6eab97..0f11ddd 100644 --- a/src/Traits/HasFilter.php +++ b/src/Traits/HasFilter.php @@ -2,10 +2,14 @@ namespace Omalizadeh\QueryFilter\Traits; +use Omalizadeh\QueryFilter\ModelFilter; +use Omalizadeh\QueryFilter\QueryFilter; +use Omalizadeh\QueryFilter\QueryFilterResult; + trait HasFilter { - public function scopeFilter($query, $filters) + public static function filter(ModelFilter $modelFilter): QueryFilterResult { - return $filters->apply($query); + return (new QueryFilter(static::query(), $modelFilter))->applyFilter(); } } diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 4f67761..ce22f5e 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -8,7 +8,7 @@ class CommandTest extends TestCase { /** @test */ - public function makeFilterCommandCreatesFilterClassTest() + public function makeFilterCommandCreatesFilterClassTest(): void { $filterFileName = 'TestFilter.php'; if (File::exists($this->getFilterPath($filterFileName))) { diff --git a/tests/Filters/UserFilter.php b/tests/Filters/UserFilter.php index 41d1a55..d4c17ce 100644 --- a/tests/Filters/UserFilter.php +++ b/tests/Filters/UserFilter.php @@ -2,34 +2,42 @@ namespace Omalizadeh\QueryFilter\Tests\Filters; -use Omalizadeh\QueryFilter\Filter; -use Illuminate\Http\Request; +use Omalizadeh\QueryFilter\ModelFilter; -class UserFilter extends Filter +class UserFilter extends ModelFilter { - public function __construct(Request $request) + public function getSortableAttributes(): array { - parent::__construct($request); - $this->sortableAttributes = [ + return [ 'id', 'created_at', 'updated_at' ]; - $this->filterableAttributes = [ + } + + public function getSummableAttributes(): array + { + return []; + } + + public function getFilterableAttributes(): array + { + return [ 'id', 'gender', 'phone', 'first_name', 'is_active' ]; - $this->filterableRelations = []; - $this->loadableRelations = []; - $this->summableAttributes = []; + } - // Max valid limit for pagination (records per page) - $this->maxPaginationLimit = 1000; + public function getFilterableRelations(): array + { + return []; + } - // Data can be accessed without pagination - $this->hasFiltersWithoutPagination = true; + public function getLoadableRelations(): array + { + return []; } } diff --git a/tests/Models/User.php b/tests/Models/User.php index ab8d2f9..c8c927b 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -14,20 +14,21 @@ class User extends Authenticatable ]; protected $casts = [ + 'gender' => 'boolean', 'is_active' => 'boolean' ]; - public function isMale() + public function isMale(): bool { - return !is_null($this->gender) and $this->gender == true; + return $this->gender === true; } - public function isFemale() + public function isFemale(): bool { - return !is_null($this->gender) and $this->gender == false; + return !is_null($this->gender) && $this->gender === false; } - public function isActive() + public function isActive(): bool { return $this->is_active; } diff --git a/tests/QueryFilterTest.php b/tests/QueryFilterTest.php index cb8643c..e95cdd7 100644 --- a/tests/QueryFilterTest.php +++ b/tests/QueryFilterTest.php @@ -4,7 +4,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Http\Request; -use Omalizadeh\QueryFilter\QueryFilter; +use Omalizadeh\QueryFilter\Filter; use Omalizadeh\QueryFilter\Tests\Filters\UserFilter; use Omalizadeh\QueryFilter\Tests\Models\User; @@ -20,22 +20,17 @@ protected function setUp(): void } /** @test */ - public function getDataWithoutFilterTest() + public function getDataWithoutFilterTest(): void { - $filters = new QueryFilter(); - $request = new Request([ - 'filter' => $filters->toJson() - ]); - $filters = new UserFilter($request); - [$users, $count] = User::filter($filters); - $users = $users->get(); - $this->assertCount($count, $users); + $filterResult = User::filter((new UserFilter(new Request()))); + $users = $filterResult->getData(); + $this->assertCount($filterResult->getCount(), $users); } /** @test */ - public function fieldEqualsFilterTest() + public function fieldEqualsFilterTest(): void { - $filters = new QueryFilter([ + $filters = new Filter([ [ [ 'field' => 'is_active', @@ -48,8 +43,8 @@ public function fieldEqualsFilterTest() 'filter' => $filters->toJson() ]); $filters = new UserFilter($request); - [$users, $count] = User::filter($filters); - $users = $users->get(); + $filterResult = User::filter($filters); + $users = $filterResult->getData(); foreach ($users as $user) { $this->assertTrue($user->isActive()); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 898f057..f1f576a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,14 +9,14 @@ class TestCase extends BaseTestCase { - protected function getPackageProviders($app) + protected function getPackageProviders($app): array { return [ QueryFilterServiceProvider::class ]; } - protected function getEnvironmentSetUp($app) + protected function getEnvironmentSetUp($app): void { $app['config']->set('database.default', 'test_db'); $app['config']->set('database.connections.test_db', [ @@ -26,24 +26,24 @@ protected function getEnvironmentSetUp($app) ]); } - protected function migrateAndSeed() + protected function migrateAndSeed(): void { $this->migrate(); - return $this->seedTestData(); + $this->seedTestData(); } - protected function migrate() + protected function migrate(): void { - return (new CreateTestUsersTable)->up(); + (new CreateTestUsersTable)->up(); } - protected function seedTestData() + protected function seedTestData(): void { - return (new TestUserSeeder)->run(); + (new TestUserSeeder)->run(); } protected function getFilterPath(?string $filterFileName = null): string { - return app_path("Http\Filters" . "\\{$filterFileName}"); + return app_path("Filters" . "\\{$filterFileName}"); } } From 8f7cbedb01200e49b81ab6276d2ba2db84a73ad8 Mon Sep 17 00:00:00 2001 From: Omid Date: Sun, 10 Oct 2021 22:45:39 +0330 Subject: [PATCH 06/27] docs: clarify relation attributes in stub --- src/Console/stubs/filter.php.stub | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Console/stubs/filter.php.stub b/src/Console/stubs/filter.php.stub index b3ba447..c04e1fa 100644 --- a/src/Console/stubs/filter.php.stub +++ b/src/Console/stubs/filter.php.stub @@ -29,10 +29,10 @@ class {{ class }} extends ModelFilter /** * 'relation_name' => [ - * 'filter_key' => 'db_origin_key', + * 'filter_key' => 'db_column_name', * ], * 'relation_name' => [ - * 'filter_and_db_key', + * 'filter_key_and_db_column_name', * ], */ public function getFilterableRelations(): array From 5e07e5fbff9fae38a52f34b04bb3cf99e44f3f50 Mon Sep 17 00:00:00 2001 From: Omid Date: Sun, 10 Oct 2021 22:46:43 +0330 Subject: [PATCH 07/27] chore: add magic filter with two args --- src/Filter.php | 67 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/src/Filter.php b/src/Filter.php index 22cb282..8326b7b 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -19,6 +19,12 @@ class Filter implements Jsonable protected ?int $offset = null; protected ?int $limit = null; + /** + * @throws InvalidSortException + * @throws InvalidRelationException + * @throws InvalidSumException + * @throws InvalidFilterException + */ public function __construct( array $filterGroups = [], array $sorts = [], @@ -35,6 +41,9 @@ public function __construct( $this->setLimit($limit); } + /** + * @throws InvalidFilterException + */ public function setFilterGroups(array $filterGroups): Filter { foreach ($filterGroups as $filterGroup) { @@ -48,6 +57,9 @@ public function setFilterGroups(array $filterGroups): Filter return $this; } + /** + * @throws InvalidFilterException + */ public function addFilterGroup(array $filterGroup): Filter { foreach ($filterGroup as &$filter) { @@ -59,17 +71,25 @@ public function addFilterGroup(array $filterGroup): Filter return $this; } - public function addFilter(string $field, string $op, $value): Filter + /** + * @throws InvalidFilterException + */ + public function addFilter(string $attribute, $op = null, $value = null): Filter { - $this->validateOperator($op); - - $this->filterGroups[] = [ - [ - 'field' => $field, - 'op' => $op, - 'value' => $value - ] - ]; + if (func_num_args() === 2) { + $value = $op; + $op = '='; + } else { + $this->validateOperator($op); + } + + $filter = $this->validateFilter([ + 'field' => $attribute, + 'op' => $op, + 'value' => $value + ]); + + $this->filterGroups[] = [$filter]; return $this; } @@ -85,7 +105,7 @@ public function setSorts(array $sorts): Filter throw new InvalidSortException('Field or dir key not found in sort array.'); } - $this->sort($sort['field'], $sort['dir']); + $this->addSort($sort['field'], $sort['dir']); } return $this; @@ -106,7 +126,7 @@ public function setSums(array $sums): Filter throw new InvalidSumException('Sums array must contain only non-empty strings of field names.'); } - $this->sum($sum); + $this->addSum($sum); } return $this; @@ -119,30 +139,30 @@ public function setRelations(array $relations): Filter throw new InvalidRelationException('Relations array must contain only non-empty strings.'); } - $this->with($relation); + $this->addRelation($relation); } return $this; } - public function sort(string $field, string $dir = 'asc'): Filter + public function addSort(string $attribute, string $dir = 'asc'): Filter { $this->sorts[] = [ - 'field' => $field, + 'field' => $attribute, 'dir' => strtolower($dir) === 'desc' ? 'desc' : 'asc' ]; return $this; } - public function sum(string $field): Filter + public function addSum(string $attribute): Filter { - $this->sums[] = $field; + $this->sums[] = $attribute; return $this; } - public function with(string $relation): Filter + public function addRelation(string $relation): Filter { $this->relations[] = $relation; @@ -163,16 +183,16 @@ public function setOffset(?int $offset): Filter return $this; } - public function getFilterFields(): array + public function getFilteredAttributes(): array { $filterGroups = $this->getFilterGroups(); - $fields = []; + $filteredAttributes = []; foreach ($filterGroups as $filter) { - $fields[] = collect($filter)->pluck('field')->toArray(); + $filteredAttributes[] = collect($filter)->pluck('field')->toArray(); } - return array_unique(Arr::flatten($fields)); + return array_unique(Arr::flatten($filteredAttributes)); } /** @@ -340,6 +360,9 @@ protected function validateFilter(array $filter): array return $filter; } + /** + * @throws InvalidFilterException + */ protected function validateOperator(string $op): void { if (!in_array($op, $this->getValidOperators(), true)) { From 7b662658d76834e57e38bbf77d69babd3f672875 Mon Sep 17 00:00:00 2001 From: Omid Date: Sun, 10 Oct 2021 22:47:44 +0330 Subject: [PATCH 08/27] chore: set max limit variable to protected --- src/ModelFilter.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ModelFilter.php b/src/ModelFilter.php index 7388987..8ef36c0 100644 --- a/src/ModelFilter.php +++ b/src/ModelFilter.php @@ -9,8 +9,7 @@ abstract class ModelFilter { - public int $maxPaginationLimit = 1000; - + protected int $maxPaginationLimit = 1000; protected Request $request; protected Filter $filter; @@ -100,7 +99,7 @@ public function hasLoadableRelation(string $relation): bool * @throws InvalidFilterException * @throws Exceptions\InvalidSumException */ - protected function createFilterFromRequest(): Filter + private function createFilterFromRequest(): Filter { try { $requestData = json_decode( From 6bf321dd0b6acf97a143d8a347b9e8d03524c290 Mon Sep 17 00:00:00 2001 From: Omid Date: Sun, 10 Oct 2021 22:49:15 +0330 Subject: [PATCH 09/27] refactor: missing space --- src/QueryFilter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QueryFilter.php b/src/QueryFilter.php index 37814b4..c5963bf 100644 --- a/src/QueryFilter.php +++ b/src/QueryFilter.php @@ -142,7 +142,7 @@ protected function whereIn(Builder $query, array $filter, bool $orCondition = fa * @param bool $orCondition * @return Builder */ - protected function whereNotIn(Builder $query, array $filter, bool $orCondition = false):Builder + protected function whereNotIn(Builder $query, array $filter, bool $orCondition = false): Builder { if ($orCondition) { return $query->orWhereNotIn($filter['field'], $filter['value']); From 6070173298ee48d4153bbf8ab55a6fc6a3173ae1 Mon Sep 17 00:00:00 2001 From: Omid Date: Mon, 11 Oct 2021 22:11:40 +0330 Subject: [PATCH 10/27] refactor: add sanitize filter method --- src/Filter.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Filter.php b/src/Filter.php index 8326b7b..dcb03bd 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -349,6 +349,11 @@ protected function validateFilter(array $filter): array $this->validateOperator($filter['op']); + return $this->sanitizeFilter($filter); + } + + protected function sanitizeFilter(array $filter): array + { if (is_array($filter['value']) && !in_array($filter['op'], ['in', 'not'], true)) { $filter['op'] = ($filter['op'] === '=') ? 'in' : 'not'; } elseif ($filter['op'] === 'like' || $filter['op'] === 'not like') { From 0a2ea92aec5517c67b72cffd82dfde1aac114000 Mon Sep 17 00:00:00 2001 From: Omid Date: Wed, 27 Oct 2021 23:43:31 +0330 Subject: [PATCH 11/27] chore: set abstract methods to protected --- src/Console/stubs/filter.php.stub | 10 +++++----- src/ModelFilter.php | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Console/stubs/filter.php.stub b/src/Console/stubs/filter.php.stub index c04e1fa..56a6fa6 100644 --- a/src/Console/stubs/filter.php.stub +++ b/src/Console/stubs/filter.php.stub @@ -6,21 +6,21 @@ use Omalizadeh\QueryFilter\ModelFilter; class {{ class }} extends ModelFilter { - public function getSortableAttributes(): array + protected function getSortableAttributes(): array { return [ // ]; } - public function getSummableAttributes(): array + protected function getSummableAttributes(): array { return [ // ]; } - public function getFilterableAttributes(): array + protected function getFilterableAttributes(): array { return [ // @@ -35,14 +35,14 @@ class {{ class }} extends ModelFilter * 'filter_key_and_db_column_name', * ], */ - public function getFilterableRelations(): array + protected function getFilterableRelations(): array { return [ // ]; } - public function getLoadableRelations(): array + protected function getLoadableRelations(): array { return [ // diff --git a/src/ModelFilter.php b/src/ModelFilter.php index 8ef36c0..0608462 100644 --- a/src/ModelFilter.php +++ b/src/ModelFilter.php @@ -25,15 +25,15 @@ public function __construct(Request $request) $this->filter = $this->createFilterFromRequest(); } - abstract public function getSortableAttributes(): array; + abstract protected function getSortableAttributes(): array; - abstract public function getSummableAttributes(): array; + abstract protected function getSummableAttributes(): array; - abstract public function getFilterableAttributes(): array; + abstract protected function getFilterableAttributes(): array; - abstract public function getFilterableRelations(): array; + abstract protected function getFilterableRelations(): array; - abstract public function getLoadableRelations(): array; + abstract protected function getLoadableRelations(): array; public function getMaxPaginationLimit(): int { From 8180264dbe009ff389f6275514f32382537fe280 Mon Sep 17 00:00:00 2001 From: Omid Date: Wed, 27 Oct 2021 23:43:58 +0330 Subject: [PATCH 12/27] feat: doesntHave filter --- src/Filter.php | 5 +++-- src/QueryFilter.php | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Filter.php b/src/Filter.php index dcb03bd..20cce70 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -74,7 +74,7 @@ public function addFilterGroup(array $filterGroup): Filter /** * @throws InvalidFilterException */ - public function addFilter(string $attribute, $op = null, $value = null): Filter + public function addFilter(string $attribute, $op = null, $value = null, bool $has = true): Filter { if (func_num_args() === 2) { $value = $op; @@ -86,7 +86,8 @@ public function addFilter(string $attribute, $op = null, $value = null): Filter $filter = $this->validateFilter([ 'field' => $attribute, 'op' => $op, - 'value' => $value + 'value' => $value, + 'has' => $has ]); $this->filterGroups[] = [$filter]; diff --git a/src/QueryFilter.php b/src/QueryFilter.php index c5963bf..6d8fb23 100644 --- a/src/QueryFilter.php +++ b/src/QueryFilter.php @@ -209,6 +209,18 @@ protected function filterRelation( string $relationName, bool $orCondition = false ): Builder { + if (isset($filter['has']) && $filter['has'] === false) { + if ($orCondition) { + return $query->orWhereDoesntHave($relationName, function ($query) use ($filter) { + $this->where($query, $filter); + }); + } + + return $query->whereDoesntHave($relationName, function ($query) use ($filter) { + $this->where($query, $filter); + }); + } + if ($orCondition) { return $query->orWhereHas($relationName, function ($query) use ($filter) { $this->where($query, $filter); From 2f9fd6ca1fb2886c7c3638aabb772d00e3714a60 Mon Sep 17 00:00:00 2001 From: Omid Date: Wed, 27 Oct 2021 23:44:18 +0330 Subject: [PATCH 13/27] tests: add more tests for relation filtering --- .../Migrations/CreateTestingPostsTable.php | 37 +++++++++ .../Migrations/CreateTestingProfilesTable.php | 39 +++++++++ ...sTable.php => CreateTestingUsersTable.php} | 5 +- tests/Database/Seeders/TestUserSeeder.php | 61 -------------- tests/Database/Seeders/TestingDataSeeder.php | 79 +++++++++++++++++++ tests/Filters/UserFilter.php | 22 ++++-- tests/Models/Post.php | 16 ++++ tests/Models/Profile.php | 20 +++++ tests/Models/User.php | 29 ++++--- tests/QueryFilterTest.php | 47 +++++++++++ tests/TestCase.php | 14 ++-- 11 files changed, 281 insertions(+), 88 deletions(-) create mode 100644 tests/Database/Migrations/CreateTestingPostsTable.php create mode 100644 tests/Database/Migrations/CreateTestingProfilesTable.php rename tests/Database/Migrations/{CreateTestUsersTable.php => CreateTestingUsersTable.php} (79%) delete mode 100644 tests/Database/Seeders/TestUserSeeder.php create mode 100644 tests/Database/Seeders/TestingDataSeeder.php create mode 100644 tests/Models/Post.php create mode 100644 tests/Models/Profile.php diff --git a/tests/Database/Migrations/CreateTestingPostsTable.php b/tests/Database/Migrations/CreateTestingPostsTable.php new file mode 100644 index 0000000..fdedeb2 --- /dev/null +++ b/tests/Database/Migrations/CreateTestingPostsTable.php @@ -0,0 +1,37 @@ +id(); + $table->unsignedBigInteger('user_id')->unique(); + $table->text('body'); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('posts'); + } +} diff --git a/tests/Database/Migrations/CreateTestingProfilesTable.php b/tests/Database/Migrations/CreateTestingProfilesTable.php new file mode 100644 index 0000000..12bfb3d --- /dev/null +++ b/tests/Database/Migrations/CreateTestingProfilesTable.php @@ -0,0 +1,39 @@ +id(); + $table->unsignedBigInteger('user_id')->unique(); + $table->boolean('gender')->nullable(); + $table->string('first_name')->nullable(); + $table->string('last_name')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('profiles'); + } +} diff --git a/tests/Database/Migrations/CreateTestUsersTable.php b/tests/Database/Migrations/CreateTestingUsersTable.php similarity index 79% rename from tests/Database/Migrations/CreateTestUsersTable.php rename to tests/Database/Migrations/CreateTestingUsersTable.php index 9dae9a4..e9eb248 100644 --- a/tests/Database/Migrations/CreateTestUsersTable.php +++ b/tests/Database/Migrations/CreateTestingUsersTable.php @@ -6,7 +6,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; -class CreateTestUsersTable extends Migration +class CreateTestingUsersTable extends Migration { /** * Run the migrations. @@ -18,9 +18,6 @@ public function up() Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('phone')->unique(); - $table->boolean('gender')->nullable(); - $table->string('first_name'); - $table->string('last_name'); $table->boolean('is_active')->default(true); $table->timestamps(); }); diff --git a/tests/Database/Seeders/TestUserSeeder.php b/tests/Database/Seeders/TestUserSeeder.php deleted file mode 100644 index fcea8f7..0000000 --- a/tests/Database/Seeders/TestUserSeeder.php +++ /dev/null @@ -1,61 +0,0 @@ - 1, - 'gender' => true, - 'phone' => '09123456789', - 'first_name' => 'Omid', - 'last_name' => 'Alizadeh', - 'is_active' => true, - 'created_at' => '2021-06-28 22:00:00', - 'updated_at' => '2021-07-01 23:33:00' - ], - [ - 'id' => 2, - 'gender' => true, - 'phone' => '09987654321', - 'first_name' => 'Ahmad', - 'last_name' => 'Mohammadi', - 'is_active' => false, - 'created_at' => '2021-07-01 19:30:00', - 'updated_at' => '2021-07-01 19:30:00' - ], - [ - 'id' => 3, - 'gender' => false, - 'phone' => '09983334444', - 'first_name' => 'Maryam', - 'last_name' => 'Saremi', - 'is_active' => true, - 'created_at' => '2021-07-02 11:20:00', - 'updated_at' => '2021-07-02 11:20:00' - ], - [ - 'id' => 4, - 'gender' => null, - 'phone' => '09983355555', - 'first_name' => 'Blue', - 'last_name' => 'Sky', - 'is_active' => true, - 'created_at' => '2021-07-02 14:40:00', - 'updated_at' => '2021-07-02 19:25:00' - ], - ]; - DB::table('users')->insertOrIgnore($data); - } -} diff --git a/tests/Database/Seeders/TestingDataSeeder.php b/tests/Database/Seeders/TestingDataSeeder.php new file mode 100644 index 0000000..84e4e6c --- /dev/null +++ b/tests/Database/Seeders/TestingDataSeeder.php @@ -0,0 +1,79 @@ + 1, + 'phone' => '09123456789', + 'is_active' => true, + 'created_at' => '2021-06-28 22:00:00', + 'updated_at' => '2021-07-01 23:33:00' + ]); + $user->profile()->create([ + 'gender' => true, + 'first_name' => 'Omid', + 'last_name' => 'Alizadeh', + ]); + $user->posts()->create([ + 'body' => 'hello world!' + ]); + + $user = User::create([ + 'id' => 2, + 'phone' => '09987654321', + 'is_active' => false, + 'created_at' => '2021-07-01 19:30:00', + 'updated_at' => '2021-07-01 19:30:00' + ]); + $user->profile()->create([ + 'first_name' => 'Ahmad', + 'last_name' => 'Mohammadi', + 'gender' => true, + ]); + $user->posts()->create([ + 'body' => 'hello' + ]); + + $user = User::create([ + 'id' => 3, + 'phone' => '09983334444', + 'is_active' => true, + 'created_at' => '2021-07-02 11:20:00', + 'updated_at' => '2021-07-02 11:20:00' + ]); + $user->profile()->create([ + 'gender' => false, + 'first_name' => 'Maryam', + 'last_name' => 'Saremi', + ]); + $user->posts()->create([ + 'body' => 'bye bye.' + ]); + + $user = User::create([ + 'id' => 4, + 'phone' => '09983355555', + 'is_active' => true, + 'created_at' => '2021-07-02 14:40:00', + 'updated_at' => '2021-07-02 19:25:00' + ]); + $user->profile()->create([ + 'gender' => null, + 'first_name' => 'Blue', + 'last_name' => 'Sky', + ]); + } +} diff --git a/tests/Filters/UserFilter.php b/tests/Filters/UserFilter.php index d4c17ce..60b8381 100644 --- a/tests/Filters/UserFilter.php +++ b/tests/Filters/UserFilter.php @@ -6,7 +6,7 @@ class UserFilter extends ModelFilter { - public function getSortableAttributes(): array + protected function getSortableAttributes(): array { return [ 'id', @@ -15,28 +15,34 @@ public function getSortableAttributes(): array ]; } - public function getSummableAttributes(): array + protected function getSummableAttributes(): array { return []; } - public function getFilterableAttributes(): array + protected function getFilterableAttributes(): array { return [ 'id', - 'gender', 'phone', - 'first_name', 'is_active' ]; } - public function getFilterableRelations(): array + protected function getFilterableRelations(): array { - return []; + return [ + 'profile' => [ + 'gender', + 'first_name' + ], + 'posts' => [ + 'post_body' => 'body' + ] + ]; } - public function getLoadableRelations(): array + protected function getLoadableRelations(): array { return []; } diff --git a/tests/Models/Post.php b/tests/Models/Post.php new file mode 100644 index 0000000..aa4483f --- /dev/null +++ b/tests/Models/Post.php @@ -0,0 +1,16 @@ +belongsTo(User::class); + } +} diff --git a/tests/Models/Profile.php b/tests/Models/Profile.php new file mode 100644 index 0000000..fa4e050 --- /dev/null +++ b/tests/Models/Profile.php @@ -0,0 +1,20 @@ + 'boolean' + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/tests/Models/User.php b/tests/Models/User.php index c8c927b..81faa2a 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -2,34 +2,43 @@ namespace Omalizadeh\QueryFilter\Tests\Models; -use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\HasOne; use Omalizadeh\QueryFilter\Traits\HasFilter; -class User extends Authenticatable +class User extends Model { use HasFilter; - protected $guarded = [ - 'id' - ]; + protected $guarded = []; protected $casts = [ - 'gender' => 'boolean', 'is_active' => 'boolean' ]; - public function isMale(): bool + public function profile(): HasOne { - return $this->gender === true; + return $this->hasOne(Profile::class); } - public function isFemale(): bool + public function posts(): HasMany { - return !is_null($this->gender) && $this->gender === false; + return $this->hasMany(Post::class); } public function isActive(): bool { return $this->is_active; } + + public function isFemale(): bool + { + return !empty($this->profile) && !is_null($this->profile->gender) && $this->profile->gender === false; + } + + public function isMale(): bool + { + return !empty($this->profile) && $this->profile->gender === true; + } } diff --git a/tests/QueryFilterTest.php b/tests/QueryFilterTest.php index e95cdd7..d8362c9 100644 --- a/tests/QueryFilterTest.php +++ b/tests/QueryFilterTest.php @@ -49,4 +49,51 @@ public function fieldEqualsFilterTest(): void $this->assertTrue($user->isActive()); } } + + /** @test */ + public function hasRelationFilterTest(): void + { + $filters = new Filter([ + [ + [ + 'field' => 'gender', + 'op' => '=', + 'value' => false + ] + ] + ]); + $request = new Request([ + 'filter' => $filters->toJson() + ]); + $filters = new UserFilter($request); + $filterResult = User::filter($filters); + $users = $filterResult->getData(); + foreach ($users as $user) { + $this->assertTrue($user->isFemale()); + } + } + + /** @test */ + public function doesntHaveRelationFilterTest(): void + { + $filters = new Filter([ + [ + [ + 'field' => 'post_body', + 'op' => 'like', + 'value' => 'hello', + 'has' => false + ] + ] + ]); + $request = new Request([ + 'filter' => $filters->toJson() + ]); + $filters = new UserFilter($request); + $filterResult = User::filter($filters); + $users = $filterResult->getData(); + foreach ($users as $user) { + $this->assertFalse($user->posts()->where('body', 'like', '%hello%')->exists()); + } + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index f1f576a..d28dfb2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -3,8 +3,10 @@ namespace Omalizadeh\QueryFilter\Tests; use Omalizadeh\QueryFilter\QueryFilterServiceProvider; -use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestUsersTable; -use Omalizadeh\QueryFilter\Tests\Database\Seeders\TestUserSeeder; +use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestingPostsTable; +use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestingProfilesTable; +use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestingUsersTable; +use Omalizadeh\QueryFilter\Tests\Database\Seeders\TestingDataSeeder; use Orchestra\Testbench\TestCase as BaseTestCase; class TestCase extends BaseTestCase @@ -34,16 +36,18 @@ protected function migrateAndSeed(): void protected function migrate(): void { - (new CreateTestUsersTable)->up(); + (new CreateTestingUsersTable)->up(); + (new CreateTestingProfilesTable)->up(); + (new CreateTestingPostsTable)->up(); } protected function seedTestData(): void { - (new TestUserSeeder)->run(); + (new TestingDataSeeder)->run(); } protected function getFilterPath(?string $filterFileName = null): string { - return app_path("Filters" . "\\{$filterFileName}"); + return app_path("Filters"."\\{$filterFileName}"); } } From d3b8ea8c8cac12cf44e8912d353913797b911e4d Mon Sep 17 00:00:00 2001 From: Omid Date: Thu, 28 Oct 2021 23:58:52 +0330 Subject: [PATCH 14/27] feat: select specific fields in query filter --- src/Console/stubs/filter.php.stub | 7 +++ .../InvalidSelectedAttributeException.php | 7 +++ src/Filter.php | 47 +++++++++++++++++-- src/ModelFilter.php | 24 ++++++++-- src/QueryFilter.php | 45 +++++++++++++----- 5 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 src/Exceptions/InvalidSelectedAttributeException.php diff --git a/src/Console/stubs/filter.php.stub b/src/Console/stubs/filter.php.stub index 56a6fa6..15f272c 100644 --- a/src/Console/stubs/filter.php.stub +++ b/src/Console/stubs/filter.php.stub @@ -6,6 +6,13 @@ use Omalizadeh\QueryFilter\ModelFilter; class {{ class }} extends ModelFilter { + protected function getSelectableAttributes(): array + { + return [ + // + ]; + } + protected function getSortableAttributes(): array { return [ diff --git a/src/Exceptions/InvalidSelectedAttributeException.php b/src/Exceptions/InvalidSelectedAttributeException.php new file mode 100644 index 0000000..bea83c4 --- /dev/null +++ b/src/Exceptions/InvalidSelectedAttributeException.php @@ -0,0 +1,7 @@ +setSelectedAttributes($selectedAttributes); $this->setFilterGroups($filterGroups); $this->setSorts($sorts); $this->setSums($sums); @@ -41,6 +46,29 @@ public function __construct( $this->setLimit($limit); } + /** + * @throws InvalidSelectedAttributeException + */ + public function setSelectedAttributes(array $attributes): Filter + { + foreach ($attributes as $attribute) { + if (!is_string($attribute)) { + throw new InvalidSelectedAttributeException('Selected attribute names must be string.'); + } + + $this->selectAttribute($attribute); + } + + return $this; + } + + public function selectAttribute(string $attribute): Filter + { + $this->selectedAttributes[] = $attribute; + + return $this; + } + /** * @throws InvalidFilterException */ @@ -196,6 +224,11 @@ public function getFilteredAttributes(): array return array_unique(Arr::flatten($filteredAttributes)); } + public function getSelectedAttributes(): array + { + return $this->selectedAttributes; + } + /** * @return array */ @@ -240,10 +273,15 @@ public function getSorts(): array return $this->sorts; } + public function hasSelectedAttribute(): bool + { + return !empty($this->getSelectedAttributes()); + } + /** * @return bool */ - public function hasAnyFilterGroup(): bool + public function hasFilterGroup(): bool { return !empty($this->getFilterGroups()); } @@ -296,7 +334,6 @@ public function hasOffset(): bool return !is_null($this->getOffset()); } - /** * Convert filter to JSON string. * @@ -308,6 +345,10 @@ public function toJson($options = 0): string { $data = []; + if (!empty($this->getSelectedAttributes())) { + $data['fields'] = $this->getSelectedAttributes(); + } + if (!empty($this->getFilterGroups())) { $data['filters'] = $this->getFilterGroups(); } @@ -317,7 +358,7 @@ public function toJson($options = 0): string } if (!empty($this->getRelations())) { - $data['relations'] = $this->getRelations(); + $data['with'] = $this->getRelations(); } if (!empty($this->getSums())) { diff --git a/src/ModelFilter.php b/src/ModelFilter.php index 0608462..4d5c871 100644 --- a/src/ModelFilter.php +++ b/src/ModelFilter.php @@ -18,6 +18,7 @@ abstract class ModelFilter * @throws Exceptions\InvalidSortException * @throws InvalidFilterException * @throws Exceptions\InvalidSumException + * @throws Exceptions\InvalidSelectedAttributeException */ public function __construct(Request $request) { @@ -25,6 +26,8 @@ public function __construct(Request $request) $this->filter = $this->createFilterFromRequest(); } + abstract protected function getSelectableAttributes(): array; + abstract protected function getSortableAttributes(): array; abstract protected function getSummableAttributes(): array; @@ -56,6 +59,11 @@ public function setFilter(Filter $filter): ModelFilter return $this; } + public function hasSelectableAttribute(string $attribute): bool + { + return in_array($attribute, $this->getSelectableAttributes(), true); + } + public function hasFilterableAttribute(string $attribute): bool { return in_array($attribute, $this->getFilterableAttributes(), true); @@ -97,13 +105,14 @@ public function hasLoadableRelation(string $relation): bool * @throws Exceptions\InvalidSortException * @throws Exceptions\InvalidRelationException * @throws InvalidFilterException + * @throws Exceptions\InvalidSelectedAttributeException * @throws Exceptions\InvalidSumException */ private function createFilterFromRequest(): Filter { try { $requestData = json_decode( - $this->getRequest()->input('filter', '{}'), + $this->getRequest()->input('q', '{}'), true, 512, JSON_THROW_ON_ERROR @@ -114,9 +123,14 @@ private function createFilterFromRequest(): Filter $filter = new Filter(); - $sortData = Arr::get($requestData, 'sorts'); - if (!empty($sortData)) { - $filter->setSorts($sortData); + $selectedFields = Arr::get($requestData, 'fields'); + if (!empty($selectedFields)) { + $filter->setSelectedAttributes($selectedFields); + } + + $sorts = Arr::get($requestData, 'sorts'); + if (!empty($sorts)) { + $filter->setSorts($sorts); } $limit = Arr::get($requestData, 'page.limit'); @@ -134,7 +148,7 @@ private function createFilterFromRequest(): Filter $filter->setFilterGroups($filterGroups); } - $relations = Arr::get($requestData, 'relations'); + $relations = Arr::get($requestData, 'with'); if (!empty($relations)) { $filter->setRelations($relations); } diff --git a/src/QueryFilter.php b/src/QueryFilter.php index 6d8fb23..0790fb1 100644 --- a/src/QueryFilter.php +++ b/src/QueryFilter.php @@ -20,7 +20,11 @@ public function __construct(Builder $builder, ModelFilter $modelFilter) */ public function applyFilter(): QueryFilterResult { - if ($this->getFilter()->hasAnyFilterGroup()) { + if ($this->getFilter()->hasSelectedAttribute()) { + $this->select(); + } + + if ($this->getFilter()->hasFilterGroup()) { $this->applyFilterGroups(); } @@ -41,22 +45,19 @@ public function applyFilter(): QueryFilterResult return new QueryFilterResult($this->getBuilder(), $this->getBuilder()->count(), $sums ?? []); } - protected function applyPagination(): Builder + protected function select(): void { - if (!$this->getFilter()->hasLimit() || $this->getFilter()->getLimit() > $this->getModelFilter()->getMaxPaginationLimit()) { - $this->getFilter()->setLimit($this->getModelFilter()->getMaxPaginationLimit()); - } + $validAttributes = []; - if (!$this->getFilter()->hasOffset()) { - $this->getFilter()->setOffset(0); + foreach ($this->getFilter()->getSelectedAttributes() as $attribute) { + if ($this->getModelFilter()->hasSelectableAttribute($attribute)) { + $validAttributes[] = $attribute; + } } - return $this->paginate(); - } - - protected function paginate(): Builder - { - return $this->getBuilder()->limit($this->getFilter()->getLimit())->offset($this->getFilter()->getOffset()); + if (!empty($validAttributes)) { + $this->getBuilder()->select($validAttributes); + } } protected function applyFilterGroups(): void @@ -232,6 +233,24 @@ protected function filterRelation( }); } + protected function applyPagination(): Builder + { + if (!$this->getFilter()->hasLimit() || $this->getFilter()->getLimit() > $this->getModelFilter()->getMaxPaginationLimit()) { + $this->getFilter()->setLimit($this->getModelFilter()->getMaxPaginationLimit()); + } + + if (!$this->getFilter()->hasOffset()) { + $this->getFilter()->setOffset(0); + } + + return $this->paginate(); + } + + protected function paginate(): Builder + { + return $this->getBuilder()->limit($this->getFilter()->getLimit())->offset($this->getFilter()->getOffset()); + } + protected function load(): void { foreach ($this->getFilter()->getRelations() as $relation) { From 655dbb714a367b1d2b9263192f1e959adc52752f Mon Sep 17 00:00:00 2001 From: Omid Date: Thu, 28 Oct 2021 23:59:32 +0330 Subject: [PATCH 15/27] tests: add new test for selectable attribute --- tests/Filters/UserFilter.php | 8 +++++ tests/QueryFilterTest.php | 64 ++++++++---------------------------- tests/RelationFilterTest.php | 63 +++++++++++++++++++++++++++++++++++ tests/TestCase.php | 7 ++++ 4 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 tests/RelationFilterTest.php diff --git a/tests/Filters/UserFilter.php b/tests/Filters/UserFilter.php index 60b8381..d9b42da 100644 --- a/tests/Filters/UserFilter.php +++ b/tests/Filters/UserFilter.php @@ -6,6 +6,14 @@ class UserFilter extends ModelFilter { + protected function getSelectableAttributes(): array + { + return [ + 'id', + 'phone' + ]; + } + protected function getSortableAttributes(): array { return [ diff --git a/tests/QueryFilterTest.php b/tests/QueryFilterTest.php index d8362c9..f1a59ea 100644 --- a/tests/QueryFilterTest.php +++ b/tests/QueryFilterTest.php @@ -4,6 +4,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Http\Request; +use Illuminate\Support\Arr; use Omalizadeh\QueryFilter\Filter; use Omalizadeh\QueryFilter\Tests\Filters\UserFilter; use Omalizadeh\QueryFilter\Tests\Models\User; @@ -12,13 +13,6 @@ class QueryFilterTest extends TestCase { use RefreshDatabase; - protected function setUp(): void - { - parent::setUp(); - - $this->migrateAndSeed(); - } - /** @test */ public function getDataWithoutFilterTest(): void { @@ -30,7 +24,8 @@ public function getDataWithoutFilterTest(): void /** @test */ public function fieldEqualsFilterTest(): void { - $filters = new Filter([ + $filter = new Filter(); + $filter->setFilterGroups([ [ [ 'field' => 'is_active', @@ -40,10 +35,10 @@ public function fieldEqualsFilterTest(): void ] ]); $request = new Request([ - 'filter' => $filters->toJson() + 'q' => $filter->toJson() ]); - $filters = new UserFilter($request); - $filterResult = User::filter($filters); + $modelFilter = new UserFilter($request); + $filterResult = User::filter($modelFilter); $users = $filterResult->getData(); foreach ($users as $user) { $this->assertTrue($user->isActive()); @@ -51,49 +46,18 @@ public function fieldEqualsFilterTest(): void } /** @test */ - public function hasRelationFilterTest(): void + public function selectSpecificFieldsTest(): void { - $filters = new Filter([ - [ - [ - 'field' => 'gender', - 'op' => '=', - 'value' => false - ] - ] - ]); + $filter = new Filter(); + $filter->setSelectedAttributes(['phone']); $request = new Request([ - 'filter' => $filters->toJson() + 'q' => $filter->toJson() ]); - $filters = new UserFilter($request); - $filterResult = User::filter($filters); - $users = $filterResult->getData(); - foreach ($users as $user) { - $this->assertTrue($user->isFemale()); - } - } - - /** @test */ - public function doesntHaveRelationFilterTest(): void - { - $filters = new Filter([ - [ - [ - 'field' => 'post_body', - 'op' => 'like', - 'value' => 'hello', - 'has' => false - ] - ] - ]); - $request = new Request([ - 'filter' => $filters->toJson() - ]); - $filters = new UserFilter($request); - $filterResult = User::filter($filters); - $users = $filterResult->getData(); + $modelFilter = new UserFilter($request); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData()->toArray(); foreach ($users as $user) { - $this->assertFalse($user->posts()->where('body', 'like', '%hello%')->exists()); + $this->assertEmpty(Arr::except($user, ['phone'])); } } } diff --git a/tests/RelationFilterTest.php b/tests/RelationFilterTest.php new file mode 100644 index 0000000..ac6ae19 --- /dev/null +++ b/tests/RelationFilterTest.php @@ -0,0 +1,63 @@ +setFilterGroups([ + [ + [ + 'field' => 'gender', + 'op' => '=', + 'value' => false + ] + ] + ]); + $request = new Request([ + 'q' => $filter->toJson() + ]); + $modelFilter = new UserFilter($request); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData(); + foreach ($users as $user) { + $this->assertTrue($user->isFemale()); + } + } + + /** @test */ + public function doesntHaveRelationFilterTest(): void + { + $filter = new Filter(); + $filter->setFilterGroups([ + [ + [ + 'field' => 'post_body', + 'op' => 'like', + 'value' => 'hello', + 'has' => false + ] + ] + ]); + $request = new Request([ + 'q' => $filter->toJson() + ]); + $modelFilter = new UserFilter($request); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData(); + foreach ($users as $user) { + $this->assertFalse($user->posts()->where('body', 'like', '%hello%')->exists()); + } + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index d28dfb2..7d66747 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -11,6 +11,13 @@ class TestCase extends BaseTestCase { + protected function setUp(): void + { + parent::setUp(); + + $this->migrateAndSeed(); + } + protected function getPackageProviders($app): array { return [ From b8f46e535caab47664e0cc30172553d5df9b87d0 Mon Sep 17 00:00:00 2001 From: Omid Date: Fri, 29 Oct 2021 20:55:33 +0330 Subject: [PATCH 16/27] fix: handle null op in filter --- src/Filter.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Filter.php b/src/Filter.php index fe0ecdb..30e05eb 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -107,6 +107,8 @@ public function addFilter(string $attribute, $op = null, $value = null, bool $ha if (func_num_args() === 2) { $value = $op; $op = '='; + } elseif (is_null($op) && func_num_args() === 1) { + $op = '='; } else { $this->validateOperator($op); } From 43900f17f5fd339c130a512162a6b5475dc4e316 Mon Sep 17 00:00:00 2001 From: Omid Date: Fri, 29 Oct 2021 20:56:20 +0330 Subject: [PATCH 17/27] chore: optional request arg --- src/ModelFilter.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/ModelFilter.php b/src/ModelFilter.php index 4d5c871..decd055 100644 --- a/src/ModelFilter.php +++ b/src/ModelFilter.php @@ -10,7 +10,6 @@ abstract class ModelFilter { protected int $maxPaginationLimit = 1000; - protected Request $request; protected Filter $filter; /** @@ -20,10 +19,13 @@ abstract class ModelFilter * @throws Exceptions\InvalidSumException * @throws Exceptions\InvalidSelectedAttributeException */ - public function __construct(Request $request) + public function __construct(?Filter $filter = null) { - $this->request = $request; - $this->filter = $this->createFilterFromRequest(); + if (is_null($filter)) { + $this->filter = $this->createFilterFromRequest(request()); + } else { + $this->setFilter($filter); + } } abstract protected function getSelectableAttributes(): array; @@ -43,11 +45,6 @@ public function getMaxPaginationLimit(): int return $this->maxPaginationLimit; } - public function getRequest(): Request - { - return $this->request; - } - public function getFilter(): Filter { return $this->filter; @@ -108,11 +105,11 @@ public function hasLoadableRelation(string $relation): bool * @throws Exceptions\InvalidSelectedAttributeException * @throws Exceptions\InvalidSumException */ - private function createFilterFromRequest(): Filter + private function createFilterFromRequest(Request $request): Filter { try { $requestData = json_decode( - $this->getRequest()->input('q', '{}'), + $request->input('q', '{}'), true, 512, JSON_THROW_ON_ERROR From 778f6d2989540747296cd169cb6f902c49ea0a85 Mon Sep 17 00:00:00 2001 From: Omid Date: Fri, 29 Oct 2021 22:08:31 +0330 Subject: [PATCH 18/27] refactor: lines & indents in tests --- tests/CommandTest.php | 2 ++ tests/QueryFilterTest.php | 23 +++++++++++++---------- tests/RelationFilterTest.php | 19 ++++++++++--------- tests/TestCase.php | 2 +- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/tests/CommandTest.php b/tests/CommandTest.php index ce22f5e..4eb9017 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -11,9 +11,11 @@ class CommandTest extends TestCase public function makeFilterCommandCreatesFilterClassTest(): void { $filterFileName = 'TestFilter.php'; + if (File::exists($this->getFilterPath($filterFileName))) { unlink($this->getFilterPath($filterFileName)); } + $this->assertFalse(File::exists($this->getFilterPath($filterFileName))); Artisan::call('make:filter TestFilter'); $this->assertTrue(File::exists($this->getFilterPath($filterFileName))); diff --git a/tests/QueryFilterTest.php b/tests/QueryFilterTest.php index f1a59ea..baebaff 100644 --- a/tests/QueryFilterTest.php +++ b/tests/QueryFilterTest.php @@ -3,7 +3,6 @@ namespace Omalizadeh\QueryFilter\Tests; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Http\Request; use Illuminate\Support\Arr; use Omalizadeh\QueryFilter\Filter; use Omalizadeh\QueryFilter\Tests\Filters\UserFilter; @@ -16,8 +15,10 @@ class QueryFilterTest extends TestCase /** @test */ public function getDataWithoutFilterTest(): void { - $filterResult = User::filter((new UserFilter(new Request()))); + $filterResult = User::filter((new UserFilter())); + $users = $filterResult->getData(); + $this->assertCount($filterResult->getCount(), $users); } @@ -34,12 +35,13 @@ public function fieldEqualsFilterTest(): void ] ] ]); - $request = new Request([ - 'q' => $filter->toJson() - ]); - $modelFilter = new UserFilter($request); + + $modelFilter = new UserFilter($filter); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData(); + foreach ($users as $user) { $this->assertTrue($user->isActive()); } @@ -50,12 +52,13 @@ public function selectSpecificFieldsTest(): void { $filter = new Filter(); $filter->setSelectedAttributes(['phone']); - $request = new Request([ - 'q' => $filter->toJson() - ]); - $modelFilter = new UserFilter($request); + + $modelFilter = new UserFilter($filter); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData()->toArray(); + foreach ($users as $user) { $this->assertEmpty(Arr::except($user, ['phone'])); } diff --git a/tests/RelationFilterTest.php b/tests/RelationFilterTest.php index ac6ae19..4276e85 100644 --- a/tests/RelationFilterTest.php +++ b/tests/RelationFilterTest.php @@ -3,7 +3,6 @@ namespace Omalizadeh\QueryFilter\Tests; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Http\Request; use Omalizadeh\QueryFilter\Filter; use Omalizadeh\QueryFilter\Tests\Filters\UserFilter; use Omalizadeh\QueryFilter\Tests\Models\User; @@ -25,12 +24,13 @@ public function hasRelationFilterTest(): void ] ] ]); - $request = new Request([ - 'q' => $filter->toJson() - ]); - $modelFilter = new UserFilter($request); + + $modelFilter = new UserFilter($filter); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData(); + foreach ($users as $user) { $this->assertTrue($user->isFemale()); } @@ -50,12 +50,13 @@ public function doesntHaveRelationFilterTest(): void ] ] ]); - $request = new Request([ - 'q' => $filter->toJson() - ]); - $modelFilter = new UserFilter($request); + + $modelFilter = new UserFilter($filter); + $filterResult = User::filter($modelFilter); + $users = $filterResult->getData(); + foreach ($users as $user) { $this->assertFalse($user->posts()->where('body', 'like', '%hello%')->exists()); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 7d66747..9b837c0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,7 +2,7 @@ namespace Omalizadeh\QueryFilter\Tests; -use Omalizadeh\QueryFilter\QueryFilterServiceProvider; +use Omalizadeh\QueryFilter\Providers\QueryFilterServiceProvider; use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestingPostsTable; use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestingProfilesTable; use Omalizadeh\QueryFilter\Tests\Database\Migrations\CreateTestingUsersTable; From 1d2371caaba94443f0287fdd471fc30078a646e5 Mon Sep 17 00:00:00 2001 From: Omid Date: Fri, 29 Oct 2021 22:09:41 +0330 Subject: [PATCH 19/27] chore: change provider namespace --- composer.json | 2 +- src/{ => Providers}/QueryFilterServiceProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{ => Providers}/QueryFilterServiceProvider.php (90%) diff --git a/composer.json b/composer.json index de427c4..a2581c2 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "extra": { "laravel": { "providers": [ - "Omalizadeh\\QueryFilter\\QueryFilterServiceProvider" + "Omalizadeh\\QueryFilter\\Providers\\QueryFilterServiceProvider" ] } }, diff --git a/src/QueryFilterServiceProvider.php b/src/Providers/QueryFilterServiceProvider.php similarity index 90% rename from src/QueryFilterServiceProvider.php rename to src/Providers/QueryFilterServiceProvider.php index fb78b62..deab142 100644 --- a/src/QueryFilterServiceProvider.php +++ b/src/Providers/QueryFilterServiceProvider.php @@ -1,6 +1,6 @@ Date: Fri, 29 Oct 2021 22:09:59 +0330 Subject: [PATCH 20/27] chore: change relation input name to withs --- src/Filter.php | 2 +- src/ModelFilter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Filter.php b/src/Filter.php index 30e05eb..543a8a2 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -360,7 +360,7 @@ public function toJson($options = 0): string } if (!empty($this->getRelations())) { - $data['with'] = $this->getRelations(); + $data['withs'] = $this->getRelations(); } if (!empty($this->getSums())) { diff --git a/src/ModelFilter.php b/src/ModelFilter.php index decd055..59ff94f 100644 --- a/src/ModelFilter.php +++ b/src/ModelFilter.php @@ -145,7 +145,7 @@ private function createFilterFromRequest(Request $request): Filter $filter->setFilterGroups($filterGroups); } - $relations = Arr::get($requestData, 'with'); + $relations = Arr::get($requestData, 'withs'); if (!empty($relations)) { $filter->setRelations($relations); } From f583d38ce55170f4e2fa5e638433ac7216dc2060 Mon Sep 17 00:00:00 2001 From: Omid Date: Fri, 29 Oct 2021 22:10:11 +0330 Subject: [PATCH 21/27] docs: update readme --- README.md | 190 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 126 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index e2f212a..190b6b1 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,129 @@ [![Latest Stable Version](https://poser.pugx.org/omalizadeh/laravel-query-filter/v)](https://packagist.org/packages/omalizadeh/laravel-query-filter) [![License](https://poser.pugx.org/omalizadeh/laravel-query-filter/license)](https://packagist.org/packages/omalizadeh/laravel-query-filter) [![Total Downloads](https://poser.pugx.org/omalizadeh/laravel-query-filter/downloads)](https://packagist.org/packages/omalizadeh/laravel-query-filter) + # Laravel Query Filter -Laravel query filter provides an elegant way to filter resources via request query string. -You can specify conditions in query string to filter eloquent models and resources. + +Laravel query filter provides an elegant way to filter resources via request query string. You can specify conditions in +query string to filter eloquent models and resources. ## Installation & Usage + Install via composer: + ``` composer require omalizadeh/laravel-query-filter ``` + Make a filter class: + ``` php artisan make:filter FilterClassName ``` + Add trait in model: + ```php +hasOne(Profile::class); } - public function posts() + public function posts(): HasMany { return $this->hasMany(Post::class); } } ``` -Set filterable attributes, relations and other options: + +Set filterable attributes, relations and other options in filter class: + ```php sortableAttributes = [ + return [ 'id', - 'created_at' + 'phone' + ]; + } + + protected function getSortableAttributes(): array + { + return [ + 'id', + 'created_at', 'updated_at' ]; - $this->filterableAttributes = [ - 'username', + } + + protected function getSummableAttributes(): array + { + return [ + 'views' + ]; + } + + protected function getFilterableAttributes(): array + { + return [ + 'id', + 'phone', 'is_active' ]; - $this->filterableRelations = [ - /* 'relation' => [ - * 'attribute1', - * 'attribute2' - * ] - */ + } + + protected function getFilterableRelations(): array + { + return [ 'profile' => [ 'gender', - 'first_name', - 'last_name', - 'phone', - 'email', - 'birth_date' + 'first_name' + ], + 'posts' => [ + 'post_body' => 'body' ] ]; - $this->loadableRelations = [ + } + + protected function getLoadableRelations(): array + { + return [ 'profile' ]; - $this->summableAttributes = [ - // total sold is a column in admins table - 'total_sold' - ]; } } ``` -Filtering resources from query string using json formatted filter parameter with pagination & sort: -```json -api/admins?filter={ + +Filtering resources via json formatted filter parameter with pagination & sort sent as `q` in query string: + +``` +api/users?q={ "page": { "limit": 20, "offset": 0 }, - "sort": [ + "sorts": [ { "field": "id", "dir": "desc" @@ -99,73 +134,100 @@ api/admins?filter={ { "field": "is_active", "op": "=", - "value": "=" + "value": true } ] ], - "with": ["profile"] + "sums": ["views"], + "withs": ["profile"] } ``` + In Controller: + ```php -use App\Http\Filters\AdminFilter; -public function index(AdminFilter $filters) +public function index(UserFilter $userFilter) { + $userFilterResult = User::filter($userFilter); + // count: total resources based on filters + $count = $userFilterResult->getCount(); + // sum: sum of given attributes in filter if there is any - list($admins, $count, $sum) = Admin::filter($filters); - $admins = $admins->with('posts')->get(); + $sums = $userFilterResult->getSums(); + + // Get query result as collection + $users = $userFilterResult->getData(); + // do stuff and return response } ``` + ### Available Operators + | Operators | Value | Description | | --------- | -------------- | ------------------------------------------------------ | -| = | string/numeric | Field is equal to value | +| = | string/numeric/bool | Field is equal to value | +| != | string/numeric/bool | Field is not equal to value | +| <> | string/numeric/bool | Field is not equal to value | | > | string/numeric | Field is greater than value | | >= | string/numeric | Field is greater than or equal to value | | < | string/numeric | Field is lower than value | | <= | string/numeric | Field is lower than or equal to value | -| != | string/numeric | Field is not equal to value | -| <> | string/numeric | Field is not equal to value | | like | string | Field is like string value | | not like | string | Field is not like string | | in | array | Field value is in given array | -| not | NULL/array | Field is not null (for null value)/ Not in given array | -| is | NULL | Field is null | +| not | null/array | Field is not null (for null value)/ Not in given array | +| is | null | Field is null | + ### Query String Format + Example conditions: + ``` -(`is_active` = 1 OR `username` like "%omalizadeh%") AND (`first_name` like "%omid%") +(`is_active` = 1 OR `phone` like "%912%") AND (`first_name` like "%omid%") ``` + Then json filter will be: ```json { - "page":{"limit":20,"offset":0}, - "sort":[ - {"field":"id","dir":"desc"} + "page": { + "limit": 20, + "offset": 0 + }, + "sorts": [ + { + "field": "id", + "dir": "desc" + } ], - "filters":[ + "filters": [ [ - {"field":"is_active","op":"=","value":1}, - {"field":"username","op":"like","value":"omalizadeh"}, + { + "field": "is_active", + "op": "=", + "value": 1 + }, + { + "field": "phone", + "op": "like", + "value": "912" + } ], - [ - {"field":"first_name","op":"like","value":"omid"}, + [ + { + "field": "first_name", + "op": "like", + "value": "omid", + "has": true + } ] - ], - "sum": [ - "total_sold" ] } ``` + ## License Laravel Query Filter is open-sourced software licensed under the [MIT license](LICENSE.md). - -## Acknowledgments - -This package is based on [Behamin BFilter Package](https://github.com/alirezabahram7/bfilter). -Thanks To [Alireza Bahrami](https://github.com/alirezabahram7) and [Hossein Ebrahimzadeh](https://github.com/Hebrahimzadeh) From 7d29d13f597e2177a22a9dd4f777277808929172 Mon Sep 17 00:00:00 2001 From: Omid Date: Fri, 29 Oct 2021 22:10:29 +0330 Subject: [PATCH 22/27] add Tests workflow --- .github/workflows/tests.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..43db105 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,31 @@ +name: Tests + +on: + push: + branches: [ main,develop ] + pull_request: + branches: [ main,develop ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Execute tests + run: vendor/bin/phpunit From 186279a6e6fcff0802b4a13dd965bf8eaca0bc8a Mon Sep 17 00:00:00 2001 From: Omid Date: Sat, 30 Oct 2021 19:43:01 +0330 Subject: [PATCH 23/27] chore: change method names & phpDoc --- src/Console/stubs/filter.php.stub | 29 +++++++++++++---- src/Filter.php | 19 ----------- src/ModelFilter.php | 54 +++++++++++++++++++------------ src/QueryFilterResult.php | 28 +++++++++++++--- tests/Filters/UserFilter.php | 12 +++---- tests/QueryFilterTest.php | 8 ++--- tests/RelationFilterTest.php | 4 +-- 7 files changed, 92 insertions(+), 62 deletions(-) diff --git a/src/Console/stubs/filter.php.stub b/src/Console/stubs/filter.php.stub index 15f272c..a4ac044 100644 --- a/src/Console/stubs/filter.php.stub +++ b/src/Console/stubs/filter.php.stub @@ -6,28 +6,40 @@ use Omalizadeh\QueryFilter\ModelFilter; class {{ class }} extends ModelFilter { - protected function getSelectableAttributes(): array + /** + * Model selectable attributes. these attributes can be selected alone. + */ + protected function selectableAttributes(): array { return [ // ]; } - protected function getSortableAttributes(): array + /** + * Model sortable attributes. + */ + protected function sortableAttributes(): array { return [ // ]; } - protected function getSummableAttributes(): array + /** + * Model summable attributes. + */ + protected function summableAttributes(): array { return [ // ]; } - protected function getFilterableAttributes(): array + /** + * Model filterable attributes. + */ + protected function filterableAttributes(): array { return [ // @@ -35,6 +47,8 @@ class {{ class }} extends ModelFilter } /** + * Attributes on relations that can be filtered. + * * 'relation_name' => [ * 'filter_key' => 'db_column_name', * ], @@ -42,14 +56,17 @@ class {{ class }} extends ModelFilter * 'filter_key_and_db_column_name', * ], */ - protected function getFilterableRelations(): array + protected function filterableRelations(): array { return [ // ]; } - protected function getLoadableRelations(): array + /** + * Relations data that can be requested with model objects. + */ + protected function loadableRelations(): array { return [ // diff --git a/src/Filter.php b/src/Filter.php index 543a8a2..3ea28b2 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -21,13 +21,6 @@ class Filter implements Jsonable protected ?int $offset = null; protected ?int $limit = null; - /** - * @throws InvalidSortException - * @throws InvalidRelationException - * @throws InvalidSumException - * @throws InvalidSelectedAttributeException - * @throws InvalidFilterException - */ public function __construct( array $selectedAttributes = [], array $filterGroups = [], @@ -46,9 +39,6 @@ public function __construct( $this->setLimit($limit); } - /** - * @throws InvalidSelectedAttributeException - */ public function setSelectedAttributes(array $attributes): Filter { foreach ($attributes as $attribute) { @@ -69,9 +59,6 @@ public function selectAttribute(string $attribute): Filter return $this; } - /** - * @throws InvalidFilterException - */ public function setFilterGroups(array $filterGroups): Filter { foreach ($filterGroups as $filterGroup) { @@ -85,9 +72,6 @@ public function setFilterGroups(array $filterGroups): Filter return $this; } - /** - * @throws InvalidFilterException - */ public function addFilterGroup(array $filterGroup): Filter { foreach ($filterGroup as &$filter) { @@ -99,9 +83,6 @@ public function addFilterGroup(array $filterGroup): Filter return $this; } - /** - * @throws InvalidFilterException - */ public function addFilter(string $attribute, $op = null, $value = null, bool $has = true): Filter { if (func_num_args() === 2) { diff --git a/src/ModelFilter.php b/src/ModelFilter.php index 59ff94f..be859ca 100644 --- a/src/ModelFilter.php +++ b/src/ModelFilter.php @@ -7,18 +7,12 @@ use JsonException; use Omalizadeh\QueryFilter\Exceptions\InvalidFilterException; -abstract class ModelFilter +class ModelFilter { - protected int $maxPaginationLimit = 1000; protected Filter $filter; - /** - * @throws Exceptions\InvalidRelationException - * @throws Exceptions\InvalidSortException - * @throws InvalidFilterException - * @throws Exceptions\InvalidSumException - * @throws Exceptions\InvalidSelectedAttributeException - */ + protected int $maxPaginationLimit = 200; + public function __construct(?Filter $filter = null) { if (is_null($filter)) { @@ -28,17 +22,35 @@ public function __construct(?Filter $filter = null) } } - abstract protected function getSelectableAttributes(): array; + protected function selectableAttributes(): array + { + return []; + } - abstract protected function getSortableAttributes(): array; + protected function sortableAttributes(): array + { + return []; + } - abstract protected function getSummableAttributes(): array; + protected function summableAttributes(): array + { + return []; + } - abstract protected function getFilterableAttributes(): array; + protected function filterableAttributes(): array + { + return []; + } - abstract protected function getFilterableRelations(): array; + protected function filterableRelations(): array + { + return []; + } - abstract protected function getLoadableRelations(): array; + protected function loadableRelations(): array + { + return []; + } public function getMaxPaginationLimit(): int { @@ -58,17 +70,17 @@ public function setFilter(Filter $filter): ModelFilter public function hasSelectableAttribute(string $attribute): bool { - return in_array($attribute, $this->getSelectableAttributes(), true); + return in_array($attribute, $this->selectableAttributes(), true); } public function hasFilterableAttribute(string $attribute): bool { - return in_array($attribute, $this->getFilterableAttributes(), true); + return in_array($attribute, $this->filterableAttributes(), true); } public function hasFilterableRelation(string $relationAttribute) { - foreach ($this->getFilterableRelations() as $relationName => $filterableRelationAttributes) { + foreach ($this->filterableRelations() as $relationName => $filterableRelationAttributes) { if (!is_array($filterableRelationAttributes) && $filterableRelationAttributes === $relationAttribute) { return [$relationName, $relationAttribute]; } @@ -85,17 +97,17 @@ public function hasFilterableRelation(string $relationAttribute) public function hasSortableAttribute(string $attribute): bool { - return in_array($attribute, $this->getSortableAttributes(), true); + return in_array($attribute, $this->sortableAttributes(), true); } public function hasSummableAttribute(string $attribute): bool { - return in_array($attribute, $this->getSummableAttributes(), true); + return in_array($attribute, $this->summableAttributes(), true); } public function hasLoadableRelation(string $relation): bool { - return in_array($relation, $this->getLoadableRelations(), true); + return in_array($relation, $this->loadableRelations(), true); } /** diff --git a/src/QueryFilterResult.php b/src/QueryFilterResult.php index ba1f22a..88120f9 100644 --- a/src/QueryFilterResult.php +++ b/src/QueryFilterResult.php @@ -18,22 +18,42 @@ public function __construct(Builder $builder, int $count, array $sums = []) $this->sums = $sums; } - public function getCount(): int + /** + * Total count of records based on filters. + * + * @return int + */ + public function count(): int { return $this->count; } - public function getSums(): array + /** + * Total sum of requested attributes based on filters. + * + * @return array + */ + public function sums(): array { return $this->sums; } - public function getBuilder(): Builder + /** + * Builder containing all filters & pagination. + * + * @return Builder + */ + public function builder(): Builder { return $this->builder; } - public function getData(): Collection + /** + * Execute query & return data. + * + * @return Collection + */ + public function data(): Collection { return $this->builder->get(); } diff --git a/tests/Filters/UserFilter.php b/tests/Filters/UserFilter.php index d9b42da..3b9e0de 100644 --- a/tests/Filters/UserFilter.php +++ b/tests/Filters/UserFilter.php @@ -6,7 +6,7 @@ class UserFilter extends ModelFilter { - protected function getSelectableAttributes(): array + protected function selectableAttributes(): array { return [ 'id', @@ -14,7 +14,7 @@ protected function getSelectableAttributes(): array ]; } - protected function getSortableAttributes(): array + protected function sortableAttributes(): array { return [ 'id', @@ -23,12 +23,12 @@ protected function getSortableAttributes(): array ]; } - protected function getSummableAttributes(): array + protected function summableAttributes(): array { return []; } - protected function getFilterableAttributes(): array + protected function filterableAttributes(): array { return [ 'id', @@ -37,7 +37,7 @@ protected function getFilterableAttributes(): array ]; } - protected function getFilterableRelations(): array + protected function filterableRelations(): array { return [ 'profile' => [ @@ -50,7 +50,7 @@ protected function getFilterableRelations(): array ]; } - protected function getLoadableRelations(): array + protected function loadableRelations(): array { return []; } diff --git a/tests/QueryFilterTest.php b/tests/QueryFilterTest.php index baebaff..caef65e 100644 --- a/tests/QueryFilterTest.php +++ b/tests/QueryFilterTest.php @@ -17,9 +17,9 @@ public function getDataWithoutFilterTest(): void { $filterResult = User::filter((new UserFilter())); - $users = $filterResult->getData(); + $users = $filterResult->data(); - $this->assertCount($filterResult->getCount(), $users); + $this->assertCount($filterResult->count(), $users); } /** @test */ @@ -40,7 +40,7 @@ public function fieldEqualsFilterTest(): void $filterResult = User::filter($modelFilter); - $users = $filterResult->getData(); + $users = $filterResult->data(); foreach ($users as $user) { $this->assertTrue($user->isActive()); @@ -57,7 +57,7 @@ public function selectSpecificFieldsTest(): void $filterResult = User::filter($modelFilter); - $users = $filterResult->getData()->toArray(); + $users = $filterResult->data()->toArray(); foreach ($users as $user) { $this->assertEmpty(Arr::except($user, ['phone'])); diff --git a/tests/RelationFilterTest.php b/tests/RelationFilterTest.php index 4276e85..42d4251 100644 --- a/tests/RelationFilterTest.php +++ b/tests/RelationFilterTest.php @@ -29,7 +29,7 @@ public function hasRelationFilterTest(): void $filterResult = User::filter($modelFilter); - $users = $filterResult->getData(); + $users = $filterResult->data(); foreach ($users as $user) { $this->assertTrue($user->isFemale()); @@ -55,7 +55,7 @@ public function doesntHaveRelationFilterTest(): void $filterResult = User::filter($modelFilter); - $users = $filterResult->getData(); + $users = $filterResult->data(); foreach ($users as $user) { $this->assertFalse($user->posts()->where('body', 'like', '%hello%')->exists()); From 90cc1fcdd80ad16684dce642aa905c463abd975f Mon Sep 17 00:00:00 2001 From: Omid Date: Sat, 30 Oct 2021 19:43:11 +0330 Subject: [PATCH 24/27] docs: update README --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 190b6b1..0a11273 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ use Omalizadeh\QueryFilter\ModelFilter; class UserFilter extends ModelFilter { - protected function getSelectableAttributes(): array + protected function selectableAttributes(): array { return [ 'id', @@ -68,7 +68,7 @@ class UserFilter extends ModelFilter ]; } - protected function getSortableAttributes(): array + protected function sortableAttributes(): array { return [ 'id', @@ -77,14 +77,14 @@ class UserFilter extends ModelFilter ]; } - protected function getSummableAttributes(): array + protected function summableAttributes(): array { return [ 'views' ]; } - protected function getFilterableAttributes(): array + protected function filterableAttributes(): array { return [ 'id', @@ -93,7 +93,7 @@ class UserFilter extends ModelFilter ]; } - protected function getFilterableRelations(): array + protected function filterableRelations(): array { return [ 'profile' => [ @@ -106,7 +106,7 @@ class UserFilter extends ModelFilter ]; } - protected function getLoadableRelations(): array + protected function loadableRelations(): array { return [ 'profile' @@ -151,14 +151,14 @@ public function index(UserFilter $userFilter) { $userFilterResult = User::filter($userFilter); - // count: total resources based on filters - $count = $userFilterResult->getCount(); + // total resources based on filters + $count = $userFilterResult->count(); - // sum: sum of given attributes in filter if there is any - $sums = $userFilterResult->getSums(); + // total sum of given attributes in filter if there is any + $sums = $userFilterResult->sums(); // Get query result as collection - $users = $userFilterResult->getData(); + $users = $userFilterResult->data(); // do stuff and return response } From b431122e51f07f9c2f1390bc6f865d3d7f677de6 Mon Sep 17 00:00:00 2001 From: Omid Date: Sat, 30 Oct 2021 19:53:53 +0330 Subject: [PATCH 25/27] docs: add workflow badge to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0a11273..6d6070e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Latest Stable Version](https://poser.pugx.org/omalizadeh/laravel-query-filter/v)](https://packagist.org/packages/omalizadeh/laravel-query-filter) +[![Tests](https://github.com/omalizadeh/laravel-query-filter/actions/workflows/tests.yml/badge.svg)](https://github.com/omalizadeh/laravel-query-filter/actions/workflows/tests.yml) [![License](https://poser.pugx.org/omalizadeh/laravel-query-filter/license)](https://packagist.org/packages/omalizadeh/laravel-query-filter) [![Total Downloads](https://poser.pugx.org/omalizadeh/laravel-query-filter/downloads)](https://packagist.org/packages/omalizadeh/laravel-query-filter) From 03f830de717b33967e3591538c0b37a6267e3eaf Mon Sep 17 00:00:00 2001 From: Omid Date: Sat, 30 Oct 2021 19:54:32 +0330 Subject: [PATCH 26/27] composer update --- composer.lock | 341 +++++++++++++++++++++++++++----------------------- 1 file changed, 187 insertions(+), 154 deletions(-) diff --git a/composer.lock b/composer.lock index 828d563..0e07427 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5b63bc540f2b233c7fd8ebd9ca691a75", + "content-hash": "90313d5b22a6aa7d7ad8f875ddc506ce", "packages": [ { "name": "brick/math", @@ -143,34 +143,30 @@ }, { "name": "doctrine/inflector", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210" + "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/9cf661f4eb38f7c881cac67c75ea9b00bf97b210", - "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", + "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^7.0", - "phpstan/phpstan": "^0.11", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-strict-rules": "^0.11", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "doctrine/coding-standard": "^8.2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "vimeo/psalm": "^4.10" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" @@ -218,7 +214,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.x" + "source": "https://github.com/doctrine/inflector/tree/2.0.4" }, "funding": [ { @@ -234,7 +230,7 @@ "type": "tidelift" } ], - "time": "2020-05-29T15:13:26+00:00" + "time": "2021-10-22T20:16:43+00:00" }, { "name": "doctrine/lexer", @@ -447,16 +443,16 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.0.2", + "version": "v1.0.3", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "84afea85c6841deeea872f36249a206e878a5de0" + "reference": "296c015dc30ec4322168c5ad3ee5cc11dae827ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/84afea85c6841deeea872f36249a206e878a5de0", - "reference": "84afea85c6841deeea872f36249a206e878a5de0", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/296c015dc30ec4322168c5ad3ee5cc11dae827ac", + "reference": "296c015dc30ec4322168c5ad3ee5cc11dae827ac", "shasum": "" }, "require": { @@ -492,7 +488,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.2" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.3" }, "funding": [ { @@ -504,20 +500,20 @@ "type": "tidelift" } ], - "time": "2021-08-28T21:34:50+00:00" + "time": "2021-10-17T19:48:54+00:00" }, { "name": "laravel/framework", - "version": "v8.62.0", + "version": "v8.68.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "60a7e00488167ce2babf3a2aeb3677e48aaf39be" + "reference": "abe985ff1fb82dd04aab03bc1dc56e83fe61a59f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/60a7e00488167ce2babf3a2aeb3677e48aaf39be", - "reference": "60a7e00488167ce2babf3a2aeb3677e48aaf39be", + "url": "https://api.github.com/repos/laravel/framework/zipball/abe985ff1fb82dd04aab03bc1dc56e83fe61a59f", + "reference": "abe985ff1fb82dd04aab03bc1dc56e83fe61a59f", "shasum": "" }, "require": { @@ -531,14 +527,14 @@ "league/commonmark": "^1.3|^2.0.2", "league/flysystem": "^1.1", "monolog/monolog": "^2.0", - "nesbot/carbon": "^2.31", + "nesbot/carbon": "^2.53.1", "opis/closure": "^3.6", "php": "^7.3|^8.0", "psr/container": "^1.0", "psr/log": "^1.0 || ^2.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.2.2", - "swiftmailer/swiftmailer": "^6.0", + "swiftmailer/swiftmailer": "^6.3", "symfony/console": "^5.1.4", "symfony/error-handler": "^5.1.4", "symfony/finder": "^5.1.4", @@ -593,22 +589,23 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.189.0", + "aws/aws-sdk-php": "^3.198.1", "doctrine/dbal": "^2.13.3|^3.1.2", - "filp/whoops": "^2.8", + "filp/whoops": "^2.14.3", "guzzlehttp/guzzle": "^6.5.5|^7.0.1", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.4.4", "orchestra/testbench-core": "^6.23", "pda/pheanstalk": "^4.0", "phpunit/phpunit": "^8.5.19|^9.5.8", - "predis/predis": "^1.1.2", + "predis/predis": "^1.1.9", "symfony/cache": "^5.1.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.198.1).", "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.2).", + "ext-bcmath": "Required to use the multiple_of validation rule.", "ext-ftp": "Required to use the Flysystem FTP driver.", "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", "ext-memcached": "Required to use the memcache cache driver.", @@ -616,7 +613,7 @@ "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", - "filp/whoops": "Required for friendly error pages in development (^2.8).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).", "laravel/tinker": "Required to use the tinker console command (^2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", @@ -626,7 +623,7 @@ "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", "phpunit/phpunit": "Required to use assertions and run tests (^8.5.19|^9.5.8).", - "predis/predis": "Required to use the predis connector (^1.1.2).", + "predis/predis": "Required to use the predis connector (^1.1.9).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0).", "symfony/cache": "Required to PSR-6 cache bridge (^5.1.4).", @@ -675,20 +672,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-09-28T13:30:25+00:00" + "time": "2021-10-27T12:31:46+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.0.2", + "version": "v1.0.3", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "679e24d36ff8b9be0e36f5222244ec8602e18867" + "reference": "6cfc678735f22ccedad761b8cae2bab14c3d8e5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/679e24d36ff8b9be0e36f5222244ec8602e18867", - "reference": "679e24d36ff8b9be0e36f5222244ec8602e18867", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/6cfc678735f22ccedad761b8cae2bab14c3d8e5b", + "reference": "6cfc678735f22ccedad761b8cae2bab14c3d8e5b", "shasum": "" }, "require": { @@ -734,7 +731,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2021-09-29T13:25:52+00:00" + "time": "2021-10-07T14:00:57+00:00" }, { "name": "league/commonmark", @@ -1274,21 +1271,21 @@ }, { "name": "nette/schema", - "version": "v1.2.1", + "version": "v1.2.2", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "f5ed39fc96358f922cedfd1e516f0dadf5d2be0d" + "reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/f5ed39fc96358f922cedfd1e516f0dadf5d2be0d", - "reference": "f5ed39fc96358f922cedfd1e516f0dadf5d2be0d", + "url": "https://api.github.com/repos/nette/schema/zipball/9a39cef03a5b34c7de64f551538cbba05c2be5df", + "reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df", "shasum": "" }, "require": { - "nette/utils": "^3.1.4 || ^4.0", - "php": ">=7.1 <8.1" + "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", + "php": ">=7.1 <8.2" }, "require-dev": { "nette/tester": "^2.3 || ^2.4", @@ -1330,9 +1327,9 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.2.1" + "source": "https://github.com/nette/schema/tree/v1.2.2" }, - "time": "2021-03-04T17:51:11+00:00" + "time": "2021-10-15T11:40:02+00:00" }, { "name": "nette/utils", @@ -1754,16 +1751,16 @@ }, { "name": "ramsey/collection", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa" + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa", - "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa", + "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a", + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a", "shasum": "" }, "require": { @@ -1817,7 +1814,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.2.1" + "source": "https://github.com/ramsey/collection/tree/1.2.2" }, "funding": [ { @@ -1829,7 +1826,7 @@ "type": "tidelift" } ], - "time": "2021-08-06T03:41:06+00:00" + "time": "2021-10-10T03:01:02+00:00" }, { "name": "ramsey/uuid", @@ -1931,16 +1928,16 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v6.2.7", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "15f7faf8508e04471f666633addacf54c0ab5933" + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/15f7faf8508e04471f666633addacf54c0ab5933", - "reference": "15f7faf8508e04471f666633addacf54c0ab5933", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", "shasum": "" }, "require": { @@ -1952,7 +1949,7 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.0" + "symfony/phpunit-bridge": "^4.4|^5.4" }, "suggest": { "ext-intl": "Needed to support internationalized email addresses" @@ -1990,7 +1987,7 @@ ], "support": { "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.7" + "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" }, "funding": [ { @@ -2002,20 +1999,20 @@ "type": "tidelift" } ], - "time": "2021-03-09T12:30:35+00:00" + "time": "2021-10-18T15:26:12+00:00" }, { "name": "symfony/console", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" + "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", + "url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", + "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", "shasum": "" }, "require": { @@ -2085,7 +2082,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.7" + "source": "https://github.com/symfony/console/tree/v5.3.10" }, "funding": [ { @@ -2101,7 +2098,7 @@ "type": "tidelift" } ], - "time": "2021-08-25T20:02:16+00:00" + "time": "2021-10-26T09:30:15+00:00" }, { "name": "symfony/css-selector", @@ -2610,16 +2607,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5" + "reference": "9f34f02e8a5fdc7a56bafe011cea1ce97300e54c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", - "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9f34f02e8a5fdc7a56bafe011cea1ce97300e54c", + "reference": "9f34f02e8a5fdc7a56bafe011cea1ce97300e54c", "shasum": "" }, "require": { @@ -2663,7 +2660,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.3.7" + "source": "https://github.com/symfony/http-foundation/tree/v5.3.10" }, "funding": [ { @@ -2679,20 +2676,20 @@ "type": "tidelift" } ], - "time": "2021-08-27T11:20:35+00:00" + "time": "2021-10-11T15:41:55+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.3.9", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "ceaf46a992f60e90645e7279825a830f733a17c5" + "reference": "703e4079920468e9522b72cf47fd76ce8d795e86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ceaf46a992f60e90645e7279825a830f733a17c5", - "reference": "ceaf46a992f60e90645e7279825a830f733a17c5", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/703e4079920468e9522b72cf47fd76ce8d795e86", + "reference": "703e4079920468e9522b72cf47fd76ce8d795e86", "shasum": "" }, "require": { @@ -2775,7 +2772,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.3.9" + "source": "https://github.com/symfony/http-kernel/tree/v5.3.10" }, "funding": [ { @@ -2791,7 +2788,7 @@ "type": "tidelift" } ], - "time": "2021-09-28T10:25:11+00:00" + "time": "2021-10-29T08:36:48+00:00" }, { "name": "symfony/mime", @@ -3917,16 +3914,16 @@ }, { "name": "symfony/string", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" + "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", + "url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", + "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", "shasum": "" }, "require": { @@ -3980,7 +3977,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.7" + "source": "https://github.com/symfony/string/tree/v5.3.10" }, "funding": [ { @@ -3996,20 +3993,20 @@ "type": "tidelift" } ], - "time": "2021-08-26T08:00:08+00:00" + "time": "2021-10-27T18:21:46+00:00" }, { "name": "symfony/translation", - "version": "v5.3.9", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "6e69f3551c1a3356cf6ea8d019bf039a0f8b6886" + "reference": "6ef197aea2ac8b9cd63e0da7522b3771714035aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/6e69f3551c1a3356cf6ea8d019bf039a0f8b6886", - "reference": "6e69f3551c1a3356cf6ea8d019bf039a0f8b6886", + "url": "https://api.github.com/repos/symfony/translation/zipball/6ef197aea2ac8b9cd63e0da7522b3771714035aa", + "reference": "6ef197aea2ac8b9cd63e0da7522b3771714035aa", "shasum": "" }, "require": { @@ -4075,7 +4072,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.3.9" + "source": "https://github.com/symfony/translation/tree/v5.3.10" }, "funding": [ { @@ -4091,7 +4088,7 @@ "type": "tidelift" } ], - "time": "2021-08-26T08:22:53+00:00" + "time": "2021-10-10T06:43:24+00:00" }, { "name": "symfony/translation-contracts", @@ -4173,16 +4170,16 @@ }, { "name": "symfony/var-dumper", - "version": "v5.3.8", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "eaaea4098be1c90c8285543e1356a09c8aa5c8da" + "reference": "875432adb5f5570fff21036fd22aee244636b7d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/eaaea4098be1c90c8285543e1356a09c8aa5c8da", - "reference": "eaaea4098be1c90c8285543e1356a09c8aa5c8da", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/875432adb5f5570fff21036fd22aee244636b7d1", + "reference": "875432adb5f5570fff21036fd22aee244636b7d1", "shasum": "" }, "require": { @@ -4241,7 +4238,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.3.8" + "source": "https://github.com/symfony/var-dumper/tree/v5.3.10" }, "funding": [ { @@ -4257,7 +4254,7 @@ "type": "tidelift" } ], - "time": "2021-09-24T15:59:58+00:00" + "time": "2021-10-26T09:30:15+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4660,16 +4657,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7" + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/1dc8d9cba3897165e16d12bb13d813afb1eb3fe7", - "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", "shasum": "" }, "require": { @@ -4693,7 +4690,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -4706,13 +4703,34 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, { "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", "homepage": "https://github.com/Tobion" }, { @@ -4734,9 +4752,23 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.0.0" + "source": "https://github.com/guzzle/psr7/tree/2.1.0" }, - "time": "2021-06-30T20:03:07+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2021-10-06T17:43:30+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -4977,24 +5009,24 @@ }, { "name": "orchestra/testbench", - "version": "v6.21.1", + "version": "v6.22.0", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "f61383c001a97f0a116b0c58f74385424aa9de33" + "reference": "e91dbf9402f1f635c00bd0b3bc4d6501beff76ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/f61383c001a97f0a116b0c58f74385424aa9de33", - "reference": "f61383c001a97f0a116b0c58f74385424aa9de33", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/e91dbf9402f1f635c00bd0b3bc4d6501beff76ad", + "reference": "e91dbf9402f1f635c00bd0b3bc4d6501beff76ad", "shasum": "" }, "require": { - "laravel/framework": "^8.54", - "mockery/mockery": "^1.4.2", - "orchestra/testbench-core": "^6.25.2", + "laravel/framework": "^8.65", + "mockery/mockery": "^1.4.4", + "orchestra/testbench-core": "^6.26", "php": "^7.3 || ^8.0", - "phpunit/phpunit": "^8.4 || ^9.3.3", + "phpunit/phpunit": "^8.5.21 || ^9.5.10", "spatie/laravel-ray": "^1.18" }, "type": "library", @@ -5026,7 +5058,7 @@ ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v6.21.1" + "source": "https://github.com/orchestral/testbench/tree/v6.22.0" }, "funding": [ { @@ -5038,20 +5070,20 @@ "type": "liberapay" } ], - "time": "2021-09-18T09:37:03+00:00" + "time": "2021-10-21T06:32:17+00:00" }, { "name": "orchestra/testbench-core", - "version": "v6.25.2", + "version": "v6.26.0", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "03d8cce6e500a9c64da4cbaa776236c91b2572a1" + "reference": "d4df6eda45104043da7a99e0a272b1507c6d4fe0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/03d8cce6e500a9c64da4cbaa776236c91b2572a1", - "reference": "03d8cce6e500a9c64da4cbaa776236c91b2572a1", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/d4df6eda45104043da7a99e0a272b1507c6d4fe0", + "reference": "d4df6eda45104043da7a99e0a272b1507c6d4fe0", "shasum": "" }, "require": { @@ -5061,20 +5093,20 @@ "vlucas/phpdotenv": "^5.1" }, "require-dev": { - "laravel/framework": "^8.54", + "laravel/framework": "^8.65", "laravel/laravel": "8.x-dev", - "mockery/mockery": "^1.4.2", + "mockery/mockery": "^1.4.4", "orchestra/canvas": "^6.1", - "phpunit/phpunit": "^8.4 || ^9.3.3 || ^10.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10 || ^10.0", "spatie/laravel-ray": "^1.7.1", "symfony/process": "^5.0" }, "suggest": { - "laravel/framework": "Required for testing (^8.54).", - "mockery/mockery": "Allow using Mockery for testing (^1.4.2).", + "laravel/framework": "Required for testing (^8.65).", + "mockery/mockery": "Allow using Mockery for testing (^1.4.4).", "orchestra/testbench-browser-kit": "Allow using legacy Laravel BrowserKit for testing (^6.0).", "orchestra/testbench-dusk": "Allow using Laravel Dusk for testing (^6.0).", - "phpunit/phpunit": "Allow using PHPUnit for testing (^8.4|^9.3.3)." + "phpunit/phpunit": "Allow using PHPUnit for testing (^8.5.21|^9.5.10|^10.0)." }, "bin": [ "testbench" @@ -5128,7 +5160,7 @@ "type": "liberapay" } ], - "time": "2021-09-18T01:47:58+00:00" + "time": "2021-10-21T06:20:26+00:00" }, { "name": "phar-io/manifest", @@ -5296,16 +5328,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { @@ -5316,7 +5348,8 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2" + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -5346,9 +5379,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" }, - "time": "2020-09-03T19:13:55+00:00" + "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -5469,23 +5502,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.7", + "version": "9.2.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.12.0", + "nikic/php-parser": "^4.13.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -5534,7 +5567,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8" }, "funding": [ { @@ -5542,7 +5575,7 @@ "type": "github" } ], - "time": "2021-09-17T05:39:03+00:00" + "time": "2021-10-30T08:01:38+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5890,24 +5923,24 @@ }, { "name": "pimple/pimple", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/silexphp/Pimple.git", - "reference": "86406047271859ffc13424a048541f4531f53601" + "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/86406047271859ffc13424a048541f4531f53601", - "reference": "86406047271859ffc13424a048541f4531f53601", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.1" + "psr/container": "^1.1 || ^2.0" }, "require-dev": { - "symfony/phpunit-bridge": "^5.0" + "symfony/phpunit-bridge": "^5.4@dev" }, "type": "library", "extra": { @@ -5937,9 +5970,9 @@ "dependency injection" ], "support": { - "source": "https://github.com/silexphp/Pimple/tree/v3.4.0" + "source": "https://github.com/silexphp/Pimple/tree/v3.5.0" }, - "time": "2021-03-06T08:28:00+00:00" + "time": "2021-10-28T11:13:42+00:00" }, { "name": "psr/http-factory", @@ -7253,16 +7286,16 @@ }, { "name": "spatie/ray", - "version": "1.30.2", + "version": "1.30.3", "source": { "type": "git", "url": "https://github.com/spatie/ray.git", - "reference": "f6344f8abf3ede60c963d9d3f7f35fb526b6138c" + "reference": "5ec8449def9735d58b66d8024776becb3b020288" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/f6344f8abf3ede60c963d9d3f7f35fb526b6138c", - "reference": "f6344f8abf3ede60c963d9d3f7f35fb526b6138c", + "url": "https://api.github.com/repos/spatie/ray/zipball/5ec8449def9735d58b66d8024776becb3b020288", + "reference": "5ec8449def9735d58b66d8024776becb3b020288", "shasum": "" }, "require": { @@ -7312,7 +7345,7 @@ ], "support": { "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.30.2" + "source": "https://github.com/spatie/ray/tree/1.30.3" }, "funding": [ { @@ -7324,7 +7357,7 @@ "type": "other" } ], - "time": "2021-09-10T07:22:57+00:00" + "time": "2021-10-07T22:07:04+00:00" }, { "name": "symfony/stopwatch", From 26ac909d4a0cfe9c9d5e7110967c70ced16e59a0 Mon Sep 17 00:00:00 2001 From: Omid Date: Sat, 30 Oct 2021 20:00:26 +0330 Subject: [PATCH 27/27] fix: make filter command file path --- tests/TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 9b837c0..8016088 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -55,6 +55,6 @@ protected function seedTestData(): void protected function getFilterPath(?string $filterFileName = null): string { - return app_path("Filters"."\\{$filterFileName}"); + return app_path("Filters"."/$filterFileName"); } }