From a932ddfc655cd368b48629fae5ccb93d8bd17075 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 2 Sep 2020 15:01:26 +0200 Subject: [PATCH 001/194] update dockblock --- src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php index e20c331f3cb2..77f71d1df836 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php @@ -16,7 +16,7 @@ trait GuardsAttributes /** * The attributes that aren't mass assignable. * - * @var array + * @var array|bool */ protected $guarded = ['*']; From 27065599b5bb4f701de5e7f256bf863141b1d06a Mon Sep 17 00:00:00 2001 From: Hazem Nassr Date: Thu, 3 Sep 2020 13:11:45 +0300 Subject: [PATCH 002/194] Remove unnecessary comma --- src/Illuminate/View/Concerns/ManagesComponents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/View/Concerns/ManagesComponents.php b/src/Illuminate/View/Concerns/ManagesComponents.php index e752a7993348..6dd3c66d7aff 100644 --- a/src/Illuminate/View/Concerns/ManagesComponents.php +++ b/src/Illuminate/View/Concerns/ManagesComponents.php @@ -114,7 +114,7 @@ protected function componentData() $this->componentData[count($this->componentStack)], ['slot' => $defaultSlot], $this->slots[count($this->componentStack)], - ['__laravel_slots' => $slots], + ['__laravel_slots' => $slots] ); } From a00c5238155dccca1c19bc36e9091c5105fec05e Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 3 Sep 2020 17:04:38 +0100 Subject: [PATCH 003/194] Fixed current branch variable --- bin/release.sh | 2 +- bin/split.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/release.sh b/bin/release.sh index 6ff44b88663f..9f40db21a010 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -10,7 +10,7 @@ then exit 1 fi -RELEASE_BRANCH="8.x" +RELEASE_BRANCH="master" CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) VERSION=$1 diff --git a/bin/split.sh b/bin/split.sh index f27bdf8d1a3b..1e2ea0e98e93 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="8.x" +CURRENT_BRANCH="master" function split() { From a3d8c5a34cb8502b5bb00c69c745489cfc3dc96c Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 3 Sep 2020 17:07:48 +0100 Subject: [PATCH 004/194] Bumped version to 9 --- composer.json | 2 +- src/Illuminate/Auth/composer.json | 20 ++++++++++---------- src/Illuminate/Broadcasting/composer.json | 12 ++++++------ src/Illuminate/Bus/composer.json | 10 +++++----- src/Illuminate/Cache/composer.json | 16 ++++++++-------- src/Illuminate/Collections/composer.json | 6 +++--- src/Illuminate/Config/composer.json | 6 +++--- src/Illuminate/Console/composer.json | 18 +++++++++--------- src/Illuminate/Container/composer.json | 4 ++-- src/Illuminate/Contracts/composer.json | 2 +- src/Illuminate/Cookie/composer.json | 10 +++++----- src/Illuminate/Database/composer.json | 20 ++++++++++---------- src/Illuminate/Encryption/composer.json | 6 +++--- src/Illuminate/Events/composer.json | 14 +++++++------- src/Illuminate/Filesystem/composer.json | 10 +++++----- src/Illuminate/Foundation/Application.php | 2 +- src/Illuminate/Hashing/composer.json | 6 +++--- src/Illuminate/Http/composer.json | 10 +++++----- src/Illuminate/Log/composer.json | 6 +++--- src/Illuminate/Macroable/composer.json | 2 +- src/Illuminate/Mail/composer.json | 12 ++++++------ src/Illuminate/Notifications/composer.json | 22 +++++++++++----------- src/Illuminate/Pagination/composer.json | 8 ++++---- src/Illuminate/Pipeline/composer.json | 6 +++--- src/Illuminate/Queue/composer.json | 20 ++++++++++---------- src/Illuminate/Redis/composer.json | 10 +++++----- src/Illuminate/Routing/composer.json | 20 ++++++++++---------- src/Illuminate/Session/composer.json | 12 ++++++------ src/Illuminate/Support/composer.json | 10 +++++----- src/Illuminate/Testing/composer.json | 16 ++++++++-------- src/Illuminate/Translation/composer.json | 12 ++++++------ src/Illuminate/Validation/composer.json | 16 ++++++++-------- src/Illuminate/View/composer.json | 16 ++++++++-------- 33 files changed, 181 insertions(+), 181 deletions(-) diff --git a/composer.json b/composer.json index 62a9ea4cb90c..bb0490d2efa8 100644 --- a/composer.json +++ b/composer.json @@ -118,7 +118,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Auth/composer.json b/src/Illuminate/Auth/composer.json index 8c994018164c..74b824f909ee 100644 --- a/src/Illuminate/Auth/composer.json +++ b/src/Illuminate/Auth/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/http": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/queue": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/http": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/queue": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -29,13 +29,13 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/console": "Required to use the auth:clear-resets command (^8.0).", - "illuminate/queue": "Required to fire login / logout events (^8.0).", - "illuminate/session": "Required to use the session based guard (^8.0)." + "illuminate/console": "Required to use the auth:clear-resets command (^9.0).", + "illuminate/queue": "Required to fire login / logout events (^9.0).", + "illuminate/session": "Required to use the session based guard (^9.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index 13fd662f1d81..1a4a0fcdf01a 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -17,11 +17,11 @@ "php": "^7.3", "ext-json": "*", "psr/log": "^1.0", - "illuminate/bus": "^8.0", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/queue": "^8.0", - "illuminate/support": "^8.0" + "illuminate/bus": "^9.0", + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/queue": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index 68620dc5a10c..60f3de730e0d 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/pipeline": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/pipeline": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index 746d582569fd..65afdb2236f4 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -27,14 +27,14 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { "ext-memcached": "Required to use the memcache cache driver.", - "illuminate/database": "Required to use the database cache driver (^8.0).", - "illuminate/filesystem": "Required to use the file cache driver (^8.0).", - "illuminate/redis": "Required to use the redis cache driver (^8.0).", + "illuminate/database": "Required to use the database cache driver (^9.0).", + "illuminate/filesystem": "Required to use the file cache driver (^9.0).", + "illuminate/redis": "Required to use the redis cache driver (^9.0).", "symfony/cache": "Required to PSR-6 cache bridge (^5.1)." }, "config": { diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index c25598559212..913a9f8f0700 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.3", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0" + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0" }, "autoload": { "psr-4": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Config/composer.json b/src/Illuminate/Config/composer.json index 69cb909a0376..8c223cc9bbe2 100755 --- a/src/Illuminate/Config/composer.json +++ b/src/Illuminate/Config/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index f9fb8b5b4343..cc5437c8015f 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0", "symfony/console": "^5.1", "symfony/process": "^5.1" }, @@ -29,16 +29,16 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { "dragonmantank/cron-expression": "Required to use scheduler (^3.0).", "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^6.5.5|^7.0.1).", - "illuminate/bus": "Required to use the scheduled job dispatcher (^8.0).", - "illuminate/container": "Required to use the scheduler (^8.0).", - "illuminate/filesystem": "Required to use the generator command (^8.0).", - "illuminate/queue": "Required to use closures for scheduled jobs (^8.0)." + "illuminate/bus": "Required to use the scheduled job dispatcher (^9.0).", + "illuminate/container": "Required to use the scheduler (^9.0).", + "illuminate/filesystem": "Required to use the generator command (^9.0).", + "illuminate/queue": "Required to use closures for scheduled jobs (^9.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index ce6d44868e16..d00793aaa231 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": "^7.3", - "illuminate/contracts": "^8.0", + "illuminate/contracts": "^9.0", "psr/container": "^1.0" }, "provide": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index 3eda3b0ba1d7..c7bdc674742e 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 3c524f05af0e..5d1d1198e710 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0", "symfony/http-foundation": "^5.1", "symfony/http-kernel": "^5.1" }, @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index a807f59a3fc0..a5f60863d8c9 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -17,11 +17,11 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0", "symfony/console": "^5.1" }, "autoload": { @@ -31,16 +31,16 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", "fzaninotto/faker": "Required to use the eloquent factory builder (^1.9.1).", - "illuminate/console": "Required to use the database commands (^8.0).", - "illuminate/events": "Required to use the observers with Eloquent (^8.0).", - "illuminate/filesystem": "Required to use the migrations (^8.0).", - "illuminate/pagination": "Required to paginate the result set (^8.0).", + "illuminate/console": "Required to use the database commands (^9.0).", + "illuminate/events": "Required to use the observers with Eloquent (^9.0).", + "illuminate/filesystem": "Required to use the migrations (^9.0).", + "illuminate/pagination": "Required to paginate the result set (^9.0).", "symfony/finder": "Required to use Eloquent model factories (^5.1)." }, "config": { diff --git a/src/Illuminate/Encryption/composer.json b/src/Illuminate/Encryption/composer.json index daeae948b240..536b92eb4358 100644 --- a/src/Illuminate/Encryption/composer.json +++ b/src/Illuminate/Encryption/composer.json @@ -18,8 +18,8 @@ "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "illuminate/contracts": "^8.0", - "illuminate/support": "^8.0" + "illuminate/contracts": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Events/composer.json b/src/Illuminate/Events/composer.json index 0db639289cb8..5a6a87f1816a 100755 --- a/src/Illuminate/Events/composer.json +++ b/src/Illuminate/Events/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.3", - "illuminate/bus": "^8.0", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0" + "illuminate/bus": "^9.0", + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index b45d18461fa5..ca007ee7ef93 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0", "symfony/finder": "^5.1" }, "autoload": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 88dc0c7ea5c2..61152cd8cad1 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.x-dev'; + const VERSION = '9.x-dev'; /** * The base path for the Laravel installation. diff --git a/src/Illuminate/Hashing/composer.json b/src/Illuminate/Hashing/composer.json index 370e4897ae79..faf22803ba22 100755 --- a/src/Illuminate/Hashing/composer.json +++ b/src/Illuminate/Hashing/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.3", - "illuminate/contracts": "^8.0", - "illuminate/support": "^8.0" + "illuminate/contracts": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 9a510f0e8071..40a98ef38d6d 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -16,10 +16,10 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/session": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/session": "^9.0", + "illuminate/support": "^9.0", "symfony/http-foundation": "^5.1", "symfony/http-kernel": "^5.1", "symfony/mime": "^5.1" @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index 822cb950275f..1239373d24d4 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.3", - "illuminate/contracts": "^8.0", - "illuminate/support": "^8.0", + "illuminate/contracts": "^9.0", + "illuminate/support": "^9.0", "monolog/monolog": "^2.0" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Macroable/composer.json b/src/Illuminate/Macroable/composer.json index ba9bb77d604c..38be7c2b705b 100644 --- a/src/Illuminate/Macroable/composer.json +++ b/src/Illuminate/Macroable/composer.json @@ -23,7 +23,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 9842c22f6fee..839eb0bb15cb 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -16,11 +16,11 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0", "league/commonmark": "^1.3", "psr/log": "^1.0", "swiftmailer/swiftmailer": "^6.0", @@ -33,7 +33,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index df6c180a327f..47852af79752 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -15,15 +15,15 @@ ], "require": { "php": "^7.3", - "illuminate/broadcasting": "^8.0", - "illuminate/bus": "^8.0", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/mail": "^8.0", - "illuminate/queue": "^8.0", - "illuminate/support": "^8.0" + "illuminate/broadcasting": "^9.0", + "illuminate/bus": "^9.0", + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/filesystem": "^9.0", + "illuminate/mail": "^9.0", + "illuminate/queue": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -32,11 +32,11 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/database": "Required to use the database transport (^8.0)." + "illuminate/database": "Required to use the database transport (^9.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Pagination/composer.json b/src/Illuminate/Pagination/composer.json index 30f0b1d04fe4..94fe8e9810a2 100755 --- a/src/Illuminate/Pagination/composer.json +++ b/src/Illuminate/Pagination/composer.json @@ -16,9 +16,9 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Pipeline/composer.json b/src/Illuminate/Pipeline/composer.json index cda7e7b96ea1..7ebd9fe0b59d 100644 --- a/src/Illuminate/Pipeline/composer.json +++ b/src/Illuminate/Pipeline/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.3", - "illuminate/contracts": "^8.0", - "illuminate/support": "^8.0" + "illuminate/contracts": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index b97ab3d5a8bf..e888e06a4731 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -16,14 +16,14 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/console": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/database": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/pipeline": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/console": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/database": "^9.0", + "illuminate/filesystem": "^9.0", + "illuminate/pipeline": "^9.0", + "illuminate/support": "^9.0", "opis/closure": "^3.5.3", "ramsey/uuid": "^4.0", "symfony/process": "^5.1" @@ -35,14 +35,14 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", "aws/aws-sdk-php": "Required to use the SQS queue driver and DynamoDb failed job storage (^3.0).", - "illuminate/redis": "Required to use the Redis queue driver (^8.0).", + "illuminate/redis": "Required to use the Redis queue driver (^9.0).", "pda/pheanstalk": "Required to use the Beanstalk queue driver (^4.0)." }, "config": { diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index a1def20cb6c5..a3cfae403b22 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 5dda88459238..0d0d19937833 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -16,14 +16,14 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/http": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/pipeline": "^8.0", - "illuminate/session": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/http": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/pipeline": "^9.0", + "illuminate/session": "^9.0", + "illuminate/support": "^9.0", "symfony/http-foundation": "^5.1", "symfony/http-kernel": "^5.1", "symfony/routing": "^5.1" @@ -35,11 +35,11 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/console": "Required to use the make commands (^8.0).", + "illuminate/console": "Required to use the make commands (^9.0).", "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0)." }, diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 42b9a178de7a..078e608bf3b6 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -16,10 +16,10 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/support": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/filesystem": "^9.0", + "illuminate/support": "^9.0", "symfony/finder": "^5.1", "symfony/http-foundation": "^5.1" }, @@ -30,11 +30,11 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/console": "Required to use the session:table command (^8.0)." + "illuminate/console": "Required to use the session:table command (^9.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index bd8e702bf9e4..15f3aab8be8d 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -18,9 +18,9 @@ "ext-json": "*", "ext-mbstring": "*", "doctrine/inflector": "^1.4|^2.0", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", "nesbot/carbon": "^2.17", "voku/portable-ascii": "^1.4.8" }, @@ -37,11 +37,11 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (^8.0).", + "illuminate/filesystem": "Required to use the composer class (^9.0).", "ramsey/uuid": "Required to use Str::uuid() (^4.0).", "symfony/process": "Required to use the composer class (^5.1).", "symfony/var-dumper": "Required to use the dd function (^5.1).", diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index 427a73a0a954..6fccf60efbca 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.3", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -27,13 +27,13 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/console": "Required to assert console commands (^8.0).", - "illuminate/database": "Required to assert databases (^8.0).", - "illuminate/http": "Required to assert responses (^8.0).", + "illuminate/console": "Required to assert console commands (^9.0).", + "illuminate/database": "Required to assert databases (^9.0).", + "illuminate/http": "Required to assert responses (^9.0).", "mockery/mockery": "Required to use mocking (^1.3.1).", "phpunit/phpunit": "Required to use assertions and run tests (^8.4|^9.0)." }, diff --git a/src/Illuminate/Translation/composer.json b/src/Illuminate/Translation/composer.json index f353ce0ed70f..6b9c34b4a57f 100755 --- a/src/Illuminate/Translation/composer.json +++ b/src/Illuminate/Translation/composer.json @@ -16,11 +16,11 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/filesystem": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 276a81123b74..11a4d3da4121 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -17,12 +17,12 @@ "php": "^7.3", "ext-json": "*", "egulias/email-validator": "^2.1.10", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0", - "illuminate/translation": "^8.0", + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0", + "illuminate/translation": "^9.0", "symfony/http-foundation": "^5.1", "symfony/mime": "^5.1" }, @@ -33,11 +33,11 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "suggest": { - "illuminate/database": "Required to use the database presence verifier (^8.0)." + "illuminate/database": "Required to use the database presence verifier (^9.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index cfb93729258a..46999f25200b 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -16,13 +16,13 @@ "require": { "php": "^7.3", "ext-json": "*", - "illuminate/collections": "^8.0", - "illuminate/container": "^8.0", - "illuminate/contracts": "^8.0", - "illuminate/events": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/macroable": "^8.0", - "illuminate/support": "^8.0" + "illuminate/collections": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/events": "^9.0", + "illuminate/filesystem": "^9.0", + "illuminate/macroable": "^9.0", + "illuminate/support": "^9.0" }, "autoload": { "psr-4": { @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "9.x-dev" } }, "config": { From 3a60d71a9ea52dc1f6b83f2b8adc731a8a57dd1b Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 3 Sep 2020 20:36:26 +0200 Subject: [PATCH 005/194] Update PHPUnit and Testbench (#34122) --- composer.json | 4 ++-- src/Illuminate/Testing/composer.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index bb0490d2efa8..544fc177ec17 100644 --- a/composer.json +++ b/composer.json @@ -84,9 +84,9 @@ "guzzlehttp/guzzle": "^6.5.5|^7.0.1", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.3.1", - "orchestra/testbench-core": "^6.0", + "orchestra/testbench-core": "^7.0", "pda/pheanstalk": "^4.0", - "phpunit/phpunit": "^8.4|^9.0", + "phpunit/phpunit": "^9.0", "predis/predis": "^1.1.1", "symfony/cache": "^5.1" }, diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index 6fccf60efbca..0fd7fbf774fc 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -35,7 +35,7 @@ "illuminate/database": "Required to assert databases (^9.0).", "illuminate/http": "Required to assert responses (^9.0).", "mockery/mockery": "Required to use mocking (^1.3.1).", - "phpunit/phpunit": "Required to use assertions and run tests (^8.4|^9.0)." + "phpunit/phpunit": "Required to use assertions and run tests (^9.0)." }, "config": { "sort-packages": true From 0f0f883cc181c7ccdcf4b9eb740c796e0944e696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Thu, 10 Sep 2020 15:46:30 +0300 Subject: [PATCH 006/194] Improve signature for HasFactory::factory() (#34203) --- .../Database/Eloquent/Factories/HasFactory.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/HasFactory.php b/src/Illuminate/Database/Eloquent/Factories/HasFactory.php index 496f00f3f0fc..ad3063e47d67 100644 --- a/src/Illuminate/Database/Eloquent/Factories/HasFactory.php +++ b/src/Illuminate/Database/Eloquent/Factories/HasFactory.php @@ -7,13 +7,14 @@ trait HasFactory /** * Get a new factory instance for the model. * - * @param mixed $parameters + * @param callable|array|int|null $count + * @param callable|array $state * @return \Illuminate\Database\Eloquent\Factories\Factory */ - public static function factory(...$parameters) + public static function factory($count = null, $state = []) { return Factory::factoryForModel(get_called_class()) - ->count(is_numeric($parameters[0] ?? null) ? $parameters[0] : null) - ->state(is_array($parameters[0] ?? null) ? $parameters[0] : ($parameters[1] ?? [])); + ->count(is_numeric($count) ? $count : null) + ->state(is_callable($count) || is_array($count) ? $count : $state); } } From 3e66eb75ae379f14eb760a19071a07134de797e3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 24 Sep 2020 15:03:01 -0500 Subject: [PATCH 007/194] use related model for methods --- .../Database/Eloquent/Relations/BelongsToMany.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 97306dee1d3c..8c589b39418d 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -585,7 +585,7 @@ public function findOrNew($id, $columns = ['*']) */ public function firstOrNew(array $attributes) { - if (is_null($instance = $this->where($attributes)->first())) { + if (is_null($instance = $this->related->where($attributes)->first())) { $instance = $this->related->newInstance($attributes); } @@ -602,7 +602,7 @@ public function firstOrNew(array $attributes) */ public function firstOrCreate(array $attributes, array $joining = [], $touch = true) { - if (is_null($instance = $this->where($attributes)->first())) { + if (is_null($instance = $this->related->where($attributes)->first())) { $instance = $this->create($attributes, $joining, $touch); } @@ -620,7 +620,7 @@ public function firstOrCreate(array $attributes, array $joining = [], $touch = t */ public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true) { - if (is_null($instance = $this->where($attributes)->first())) { + if (is_null($instance = $this->related->where($attributes)->first())) { return $this->create($values, $joining, $touch); } From 7713cb74a8127598560fb60f3c982f3b7a953738 Mon Sep 17 00:00:00 2001 From: Nikolay Gagarinov Date: Mon, 5 Oct 2020 17:51:27 +0500 Subject: [PATCH 008/194] [9.x] Strict comparison for Str::replaceFirst and Str::is (#34670) * strict types for replaceFirst * add strict str_is * Update Str.php Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Str.php | 6 ++++-- tests/Support/SupportStrTest.php | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 59158f4c6ee7..86f0537139b5 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -251,7 +251,7 @@ public static function is($pattern, $value) // If the given value is an exact match we can of course return true right // from the beginning. Otherwise, we will translate asterisks and do an // actual pattern match against the two strings to see if they match. - if ($pattern == $value) { + if ($pattern === $value) { return true; } @@ -501,7 +501,9 @@ public static function replaceArray($search, array $replace, $subject) */ public static function replaceFirst($search, $replace, $subject) { - if ($search == '') { + $search = (string) $search; + + if ($search === '') { return $subject; } diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 87bc3c0956c4..c39a65ea4ab9 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -264,6 +264,10 @@ public function testIs() // empty patterns $this->assertFalse(Str::is([], 'test')); + + $this->assertFalse(Str::is('', 0)); + $this->assertFalse(Str::is([null], 0)); + $this->assertTrue(Str::is([null], null)); } /** @@ -348,6 +352,7 @@ public function testReplaceFirst() $this->assertSame('foo foobar', Str::replaceFirst('bar', '', 'foobar foobar')); $this->assertSame('foobar foobar', Str::replaceFirst('xxx', 'yyy', 'foobar foobar')); $this->assertSame('foobar foobar', Str::replaceFirst('', 'yyy', 'foobar foobar')); + $this->assertSame('1', Str::replaceFirst(0, '1', '0')); // Test for multibyte string support $this->assertSame('Jxxxnköping Malmö', Str::replaceFirst('ö', 'xxx', 'Jönköping Malmö')); $this->assertSame('Jönköping Malmö', Str::replaceFirst('', 'yyy', 'Jönköping Malmö')); From 0aca5a9bb2f8fc9ee3d22ca854bc84d3f9524036 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Sun, 18 Oct 2020 04:46:39 +0530 Subject: [PATCH 009/194] [9.x] Add support for lazy loading commands --- src/Illuminate/Console/Application.php | 27 ++++++- .../Console/ContainerCommandLoader.php | 72 +++++++++++++++++++ src/Illuminate/Foundation/Console/Kernel.php | 6 +- .../Foundation/Console/stubs/console.stub | 7 ++ 4 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Console/ContainerCommandLoader.php diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 7066c8485425..e496dcd49977 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -46,6 +46,13 @@ class Application extends SymfonyApplication implements ApplicationContract */ protected static $bootstrappers = []; + /** + * A map of command names to classes. + * + * @var array + */ + protected $commandMap = []; + /** * The Event Dispatcher. * @@ -254,10 +261,16 @@ protected function addToParent(SymfonyCommand $command) * Add a command, resolving through the application. * * @param string $command - * @return \Symfony\Component\Console\Command\Command + * @return \Symfony\Component\Console\Command\Command|null */ public function resolve($command) { + if (class_exists($command) && ($commandName = $command::getDefaultName())) { + $this->commandMap[$commandName] = $command; + + return null; + } + return $this->add($this->laravel->make($command)); } @@ -278,6 +291,18 @@ public function resolveCommands($commands) return $this; } + /** + * Set the Container Command Loader + * + * @return $this + */ + public function setContainerCommandLoader() + { + $this->setCommandLoader(new ContainerCommandLoader($this->laravel, $this->commandMap)); + + return $this; + } + /** * Get the default input definition for the application. * diff --git a/src/Illuminate/Console/ContainerCommandLoader.php b/src/Illuminate/Console/ContainerCommandLoader.php new file mode 100644 index 000000000000..3826d7482edb --- /dev/null +++ b/src/Illuminate/Console/ContainerCommandLoader.php @@ -0,0 +1,72 @@ +container = $container; + $this->commandMap = $commandMap; + } + + /** + * Loads a command. + * + * @param string $name + * @return \Symfony\Component\Console\Command\Command + * + * @throws \Symfony\Component\Console\Exception\CommandNotFoundException + */ + public function get(string $name) + { + if (!$this->has($name)) { + throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + } + + return $this->container->get($this->commandMap[$name]); + } + + /** + * Checks if a command exists. + * + * @param string $name + * @return bool + */ + public function has(string $name) + { + return $name && isset($this->commandMap[$name]); + } + + /** + * Get the command names. + * + * @return string[] + */ + public function getNames() + { + return array_keys($this->commandMap); + } +} \ No newline at end of file diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index e6b0798490e7..0f9534c06c66 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -327,8 +327,10 @@ public function bootstrap() protected function getArtisan() { if (is_null($this->artisan)) { - return $this->artisan = (new Artisan($this->app, $this->events, $this->app->version())) - ->resolveCommands($this->commands); + $this->artisan = (new Artisan($this->app, $this->events, $this->app->version())) + ->resolveCommands($this->commands); + + return $this->artisan->setContainerCommandLoader(); } return $this->artisan; diff --git a/src/Illuminate/Foundation/Console/stubs/console.stub b/src/Illuminate/Foundation/Console/stubs/console.stub index 0f751a3c75fd..98b48662cdef 100644 --- a/src/Illuminate/Foundation/Console/stubs/console.stub +++ b/src/Illuminate/Foundation/Console/stubs/console.stub @@ -13,6 +13,13 @@ class {{ class }} extends Command */ protected $signature = '{{ command }}'; + /** + * The default command name for lazy loading. + * + * @var string|null + */ + protected static $defaultName = '{{ command }}'; + /** * The console command description. * From 958d02b6c6a0921e783c8bd46d95fe67ce2853a7 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Sun, 18 Oct 2020 05:02:10 +0530 Subject: [PATCH 010/194] fix styleci --- src/Illuminate/Console/Application.php | 2 +- src/Illuminate/Console/ContainerCommandLoader.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index e496dcd49977..4f6944369a6e 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -292,7 +292,7 @@ public function resolveCommands($commands) } /** - * Set the Container Command Loader + * Set the Container Command Loader. * * @return $this */ diff --git a/src/Illuminate/Console/ContainerCommandLoader.php b/src/Illuminate/Console/ContainerCommandLoader.php index 3826d7482edb..443409dc015c 100644 --- a/src/Illuminate/Console/ContainerCommandLoader.php +++ b/src/Illuminate/Console/ContainerCommandLoader.php @@ -17,7 +17,7 @@ class ContainerCommandLoader implements CommandLoaderInterface /** * A map of command names to classes. - * + * * @var array */ protected $commandMap; @@ -42,7 +42,7 @@ public function __construct(ContainerInterface $container, array $commandMap) */ public function get(string $name) { - if (!$this->has($name)) { + if (! $this->has($name)) { throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); } @@ -62,11 +62,11 @@ public function has(string $name) /** * Get the command names. - * + * * @return string[] */ public function getNames() { return array_keys($this->commandMap); } -} \ No newline at end of file +} From 03567731113811933823d37282e01f0820914a2a Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 20 Oct 2020 13:20:54 +0100 Subject: [PATCH 011/194] Bump to Symfony 5.2 (#34895) --- composer.json | 24 ++++++++++++------------ src/Illuminate/Cache/composer.json | 2 +- src/Illuminate/Collections/composer.json | 2 +- src/Illuminate/Console/composer.json | 4 ++-- src/Illuminate/Cookie/composer.json | 4 ++-- src/Illuminate/Database/composer.json | 4 ++-- src/Illuminate/Filesystem/composer.json | 6 +++--- src/Illuminate/Http/composer.json | 6 +++--- src/Illuminate/Queue/composer.json | 2 +- src/Illuminate/Routing/composer.json | 6 +++--- src/Illuminate/Session/composer.json | 4 ++-- src/Illuminate/Support/composer.json | 4 ++-- src/Illuminate/Validation/composer.json | 4 ++-- 13 files changed, 36 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index 79e67f1efdab..c2cc2debbe24 100644 --- a/composer.json +++ b/composer.json @@ -31,15 +31,15 @@ "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", "swiftmailer/swiftmailer": "^6.0", - "symfony/console": "^5.1", - "symfony/error-handler": "^5.1", - "symfony/finder": "^5.1", - "symfony/http-foundation": "^5.1", - "symfony/http-kernel": "^5.1", - "symfony/mime": "^5.1", - "symfony/process": "^5.1", - "symfony/routing": "^5.1", - "symfony/var-dumper": "^5.1", + "symfony/console": "^5.2", + "symfony/error-handler": "^5.2", + "symfony/finder": "^5.2", + "symfony/http-foundation": "^5.2", + "symfony/http-kernel": "^5.2", + "symfony/mime": "^5.2", + "symfony/process": "^5.2", + "symfony/routing": "^5.2", + "symfony/var-dumper": "^5.2", "tijsverkoyen/css-to-inline-styles": "^2.2.2", "vlucas/phpdotenv": "^5.2", "voku/portable-ascii": "^1.4.8" @@ -88,7 +88,7 @@ "pda/pheanstalk": "^4.0", "phpunit/phpunit": "^9.4", "predis/predis": "^1.1.1", - "symfony/cache": "^5.1" + "symfony/cache": "^5.2" }, "provide": { "psr/container-implementation": "1.0" @@ -144,8 +144,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).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.1).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.1).", + "symfony/cache": "Required to PSR-6 cache bridge (^5.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^5.2).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index 65afdb2236f4..eaa8d6f69bf6 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -35,7 +35,7 @@ "illuminate/database": "Required to use the database cache driver (^9.0).", "illuminate/filesystem": "Required to use the file cache driver (^9.0).", "illuminate/redis": "Required to use the redis cache driver (^9.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.1)." + "symfony/cache": "Required to PSR-6 cache bridge (^5.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index 5dc465f203a6..c15372eaabf4 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -32,7 +32,7 @@ } }, "suggest": { - "symfony/var-dumper": "Required to use the dump method (^5.1)." + "symfony/var-dumper": "Required to use the dump method (^5.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 281adc946074..33c1115adc7c 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -19,8 +19,8 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/console": "^5.1", - "symfony/process": "^5.1" + "symfony/console": "^5.2", + "symfony/process": "^5.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 5d1d1198e710..c6acdc764c22 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -19,8 +19,8 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.1", - "symfony/http-kernel": "^5.1" + "symfony/http-foundation": "^5.2", + "symfony/http-kernel": "^5.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index a5f60863d8c9..75fd7c2ca341 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -22,7 +22,7 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/console": "^5.1" + "symfony/console": "^5.2" }, "autoload": { "psr-4": { @@ -41,7 +41,7 @@ "illuminate/events": "Required to use the observers with Eloquent (^9.0).", "illuminate/filesystem": "Required to use the migrations (^9.0).", "illuminate/pagination": "Required to paginate the result set (^9.0).", - "symfony/finder": "Required to use Eloquent model factories (^5.1)." + "symfony/finder": "Required to use Eloquent model factories (^5.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index fd8b1f3b920f..e3d0a6053db4 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -19,7 +19,7 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/finder": "^5.1" + "symfony/finder": "^5.2" }, "autoload": { "psr-4": { @@ -39,8 +39,8 @@ "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.1).", - "symfony/mime": "Required to enable support for guessing extensions (^5.1)." + "symfony/filesystem": "Required to enable support for relative symbolic links (^5.2).", + "symfony/mime": "Required to enable support for guessing extensions (^5.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 40a98ef38d6d..ef0ee9be06df 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -20,9 +20,9 @@ "illuminate/macroable": "^9.0", "illuminate/session": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.1", - "symfony/http-kernel": "^5.1", - "symfony/mime": "^5.1" + "symfony/http-foundation": "^5.2", + "symfony/http-kernel": "^5.2", + "symfony/mime": "^5.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 5ff4baf3c801..03e505b51e91 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -26,7 +26,7 @@ "illuminate/support": "^9.0", "opis/closure": "^3.6", "ramsey/uuid": "^4.0", - "symfony/process": "^5.1" + "symfony/process": "^5.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 0d0d19937833..4ab4ba888f27 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -24,9 +24,9 @@ "illuminate/pipeline": "^9.0", "illuminate/session": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.1", - "symfony/http-kernel": "^5.1", - "symfony/routing": "^5.1" + "symfony/http-foundation": "^5.2", + "symfony/http-kernel": "^5.2", + "symfony/routing": "^5.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 078e608bf3b6..408542806708 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -20,8 +20,8 @@ "illuminate/contracts": "^9.0", "illuminate/filesystem": "^9.0", "illuminate/support": "^9.0", - "symfony/finder": "^5.1", - "symfony/http-foundation": "^5.1" + "symfony/finder": "^5.2", + "symfony/http-foundation": "^5.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index ec31c7493bda..a30bebb65335 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -43,8 +43,8 @@ "suggest": { "illuminate/filesystem": "Required to use the composer class (^9.0).", "ramsey/uuid": "Required to use Str::uuid() (^4.0).", - "symfony/process": "Required to use the composer class (^5.1).", - "symfony/var-dumper": "Required to use the dd function (^5.1).", + "symfony/process": "Required to use the composer class (^5.2).", + "symfony/var-dumper": "Required to use the dd function (^5.2).", "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.2)." }, "config": { diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 11a4d3da4121..a3f7239d61b7 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -23,8 +23,8 @@ "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", "illuminate/translation": "^9.0", - "symfony/http-foundation": "^5.1", - "symfony/mime": "^5.1" + "symfony/http-foundation": "^5.2", + "symfony/mime": "^5.2" }, "autoload": { "psr-4": { From 8b34191467d41d3d9c0d14db842440707f8a4c5f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Oct 2020 08:17:28 -0500 Subject: [PATCH 012/194] formatting --- src/Illuminate/Console/Application.php | 16 ++++++++-------- .../Console/ContainerCommandLoader.php | 9 ++++++--- src/Illuminate/Foundation/Console/Kernel.php | 5 ++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 4f6944369a6e..db1f9ac403aa 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -32,6 +32,13 @@ class Application extends SymfonyApplication implements ApplicationContract */ protected $laravel; + /** + * The event dispatcher instance. + * + * @var \Illuminate\Contracts\Events\Dispatcher + */ + protected $events; + /** * The output from the previous command. * @@ -53,13 +60,6 @@ class Application extends SymfonyApplication implements ApplicationContract */ protected $commandMap = []; - /** - * The Event Dispatcher. - * - * @var \Illuminate\Contracts\Events\Dispatcher - */ - protected $events; - /** * Create a new Artisan console application. * @@ -292,7 +292,7 @@ public function resolveCommands($commands) } /** - * Set the Container Command Loader. + * Set the container command loader for lazy resolution. * * @return $this */ diff --git a/src/Illuminate/Console/ContainerCommandLoader.php b/src/Illuminate/Console/ContainerCommandLoader.php index 443409dc015c..3ac26fe345da 100644 --- a/src/Illuminate/Console/ContainerCommandLoader.php +++ b/src/Illuminate/Console/ContainerCommandLoader.php @@ -23,8 +23,11 @@ class ContainerCommandLoader implements CommandLoaderInterface protected $commandMap; /** - * @param \Psr\Container\ContainerInterface $container + * Create a new command loader instance. + * + * @param \Psr\Container\ContainerInterface $container * @param array $commandMap + * @return void */ public function __construct(ContainerInterface $container, array $commandMap) { @@ -33,7 +36,7 @@ public function __construct(ContainerInterface $container, array $commandMap) } /** - * Loads a command. + * Resolve a command from the container. * * @param string $name * @return \Symfony\Component\Console\Command\Command @@ -50,7 +53,7 @@ public function get(string $name) } /** - * Checks if a command exists. + * Determines if a command exists. * * @param string $name * @return bool diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index 0f9534c06c66..729d6edaa1ee 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -328,9 +328,8 @@ protected function getArtisan() { if (is_null($this->artisan)) { $this->artisan = (new Artisan($this->app, $this->events, $this->app->version())) - ->resolveCommands($this->commands); - - return $this->artisan->setContainerCommandLoader(); + ->resolveCommands($this->commands) + ->setContainerCommandLoader(); } return $this->artisan; From 29e17b983f43751a2118bba9343904ac1219ba1f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Oct 2020 08:37:33 -0500 Subject: [PATCH 013/194] formatting --- src/Illuminate/Foundation/Console/stubs/console.stub | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/stubs/console.stub b/src/Illuminate/Foundation/Console/stubs/console.stub index 98b48662cdef..90fd300842c0 100644 --- a/src/Illuminate/Foundation/Console/stubs/console.stub +++ b/src/Illuminate/Foundation/Console/stubs/console.stub @@ -14,7 +14,9 @@ class {{ class }} extends Command protected $signature = '{{ command }}'; /** - * The default command name for lazy loading. + * The name of the console command. + * + * This name is used to identify the command during lazy loading. * * @var string|null */ From 82b212c1d797e73f658ef461b11796ca75707361 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Thu, 22 Oct 2020 18:51:28 +0530 Subject: [PATCH 014/194] [9.x] Lazy load Laravel commands (#34925) * [9.x] Lazy load commands shipped with Laravel * Lazy load migration commands --- .../Auth/Console/ClearResetsCommand.php | 9 + .../Cache/Console/CacheTableCommand.php | 9 + src/Illuminate/Cache/Console/ClearCommand.php | 9 + .../Cache/Console/ForgetCommand.php | 9 + .../Scheduling/ScheduleFinishCommand.php | 9 + .../Console/Scheduling/ScheduleRunCommand.php | 9 + .../Scheduling/ScheduleWorkCommand.php | 9 + .../Database/Console/DumpCommand.php | 9 + .../Console/Factories/FactoryMakeCommand.php | 9 + .../Database/Console/Seeds/SeedCommand.php | 9 + .../Console/Seeds/SeederMakeCommand.php | 9 + .../Database/Console/WipeCommand.php | 9 + .../Database/MigrationServiceProvider.php | 36 +- .../Foundation/Console/CastMakeCommand.php | 9 + .../Foundation/Console/ChannelMakeCommand.php | 9 + .../Console/ClearCompiledCommand.php | 9 + .../Console/ComponentMakeCommand.php | 9 + .../Foundation/Console/ConfigCacheCommand.php | 9 + .../Foundation/Console/ConfigClearCommand.php | 9 + .../Foundation/Console/ConsoleMakeCommand.php | 9 + .../Foundation/Console/DownCommand.php | 9 + .../Foundation/Console/EnvironmentCommand.php | 9 + .../Foundation/Console/EventCacheCommand.php | 9 + .../Foundation/Console/EventClearCommand.php | 9 + .../Console/EventGenerateCommand.php | 9 + .../Foundation/Console/EventListCommand.php | 9 + .../Foundation/Console/EventMakeCommand.php | 9 + .../Console/ExceptionMakeCommand.php | 9 + .../Foundation/Console/JobMakeCommand.php | 9 + .../Foundation/Console/KeyGenerateCommand.php | 9 + .../Console/ListenerMakeCommand.php | 9 + .../Foundation/Console/MailMakeCommand.php | 9 + .../Foundation/Console/ModelMakeCommand.php | 9 + .../Console/NotificationMakeCommand.php | 9 + .../Console/ObserverMakeCommand.php | 9 + .../Console/OptimizeClearCommand.php | 9 + .../Foundation/Console/OptimizeCommand.php | 9 + .../Console/PackageDiscoverCommand.php | 9 + .../Foundation/Console/PolicyMakeCommand.php | 9 + .../Console/ProviderMakeCommand.php | 9 + .../Foundation/Console/RequestMakeCommand.php | 9 + .../Console/ResourceMakeCommand.php | 9 + .../Foundation/Console/RouteCacheCommand.php | 9 + .../Foundation/Console/RouteClearCommand.php | 9 + .../Foundation/Console/RouteListCommand.php | 9 + .../Foundation/Console/RuleMakeCommand.php | 9 + .../Foundation/Console/ServeCommand.php | 9 + .../Foundation/Console/StorageLinkCommand.php | 9 + .../Foundation/Console/StubPublishCommand.php | 9 + .../Foundation/Console/TestMakeCommand.php | 9 + .../Foundation/Console/UpCommand.php | 9 + .../Console/VendorPublishCommand.php | 9 + .../Foundation/Console/ViewCacheCommand.php | 9 + .../Foundation/Console/ViewClearCommand.php | 9 + .../Providers/ArtisanServiceProvider.php | 312 ++++++++---------- .../Console/NotificationTableCommand.php | 9 + .../Queue/Console/BatchesTableCommand.php | 9 + src/Illuminate/Queue/Console/ClearCommand.php | 9 + .../Queue/Console/FailedTableCommand.php | 9 + .../Queue/Console/FlushFailedCommand.php | 9 + .../Queue/Console/ForgetFailedCommand.php | 9 + .../Queue/Console/ListFailedCommand.php | 9 + .../Queue/Console/ListenCommand.php | 9 + .../Queue/Console/RestartCommand.php | 9 + .../Queue/Console/RetryBatchCommand.php | 9 + src/Illuminate/Queue/Console/RetryCommand.php | 9 + src/Illuminate/Queue/Console/TableCommand.php | 9 + src/Illuminate/Queue/Console/WorkCommand.php | 9 + .../Routing/Console/ControllerMakeCommand.php | 9 + .../Routing/Console/MiddlewareMakeCommand.php | 9 + .../Session/Console/SessionTableCommand.php | 9 + 71 files changed, 769 insertions(+), 200 deletions(-) diff --git a/src/Illuminate/Auth/Console/ClearResetsCommand.php b/src/Illuminate/Auth/Console/ClearResetsCommand.php index 57c3bd506b54..43da0da4e945 100644 --- a/src/Illuminate/Auth/Console/ClearResetsCommand.php +++ b/src/Illuminate/Auth/Console/ClearResetsCommand.php @@ -13,6 +13,15 @@ class ClearResetsCommand extends Command */ protected $signature = 'auth:clear-resets {name? : The name of the password broker}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'auth:clear-resets'; + /** * The console command description. * diff --git a/src/Illuminate/Cache/Console/CacheTableCommand.php b/src/Illuminate/Cache/Console/CacheTableCommand.php index a8c78c9e08f0..56bf2dd1c39f 100644 --- a/src/Illuminate/Cache/Console/CacheTableCommand.php +++ b/src/Illuminate/Cache/Console/CacheTableCommand.php @@ -15,6 +15,15 @@ class CacheTableCommand extends Command */ protected $name = 'cache:table'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'cache:table'; + /** * The console command description. * diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index aa88964d729f..566ae7078b91 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -17,6 +17,15 @@ class ClearCommand extends Command */ protected $name = 'cache:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'cache:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Cache/Console/ForgetCommand.php b/src/Illuminate/Cache/Console/ForgetCommand.php index eb0c0666887d..22677837e4d3 100755 --- a/src/Illuminate/Cache/Console/ForgetCommand.php +++ b/src/Illuminate/Cache/Console/ForgetCommand.php @@ -14,6 +14,15 @@ class ForgetCommand extends Command */ protected $signature = 'cache:forget {key : The key to remove} {store? : The store to remove the key from}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'cache:forget'; + /** * The console command description. * diff --git a/src/Illuminate/Console/Scheduling/ScheduleFinishCommand.php b/src/Illuminate/Console/Scheduling/ScheduleFinishCommand.php index c19381f08a51..2bfbcd90560d 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleFinishCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleFinishCommand.php @@ -13,6 +13,15 @@ class ScheduleFinishCommand extends Command */ protected $signature = 'schedule:finish {id} {code=0}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'schedule:finish'; + /** * The console command description. * diff --git a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php index 926585a7b060..3255a7ac785a 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php @@ -21,6 +21,15 @@ class ScheduleRunCommand extends Command */ protected $name = 'schedule:run'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'schedule:run'; + /** * The console command description. * diff --git a/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php b/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php index ec296ebd4972..c159349d4a62 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php @@ -15,6 +15,15 @@ class ScheduleWorkCommand extends Command */ protected $name = 'schedule:work'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'schedule:work'; + /** * The console command description. * diff --git a/src/Illuminate/Database/Console/DumpCommand.php b/src/Illuminate/Database/Console/DumpCommand.php index ef4c0beb593b..e2fce09ec5cc 100644 --- a/src/Illuminate/Database/Console/DumpCommand.php +++ b/src/Illuminate/Database/Console/DumpCommand.php @@ -21,6 +21,15 @@ class DumpCommand extends Command {--path= : The path where the schema dump file should be stored} {--prune : Delete all existing migration files}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'schema:dump'; + /** * The console command description. * diff --git a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php index 88b9b4a0bba4..4080206d2379 100644 --- a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php +++ b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php @@ -15,6 +15,15 @@ class FactoryMakeCommand extends GeneratorCommand */ protected $name = 'make:factory'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:factory'; + /** * The console command description. * diff --git a/src/Illuminate/Database/Console/Seeds/SeedCommand.php b/src/Illuminate/Database/Console/Seeds/SeedCommand.php index ccca6fd5eeda..5235ccd71542 100644 --- a/src/Illuminate/Database/Console/Seeds/SeedCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeedCommand.php @@ -19,6 +19,15 @@ class SeedCommand extends Command */ protected $name = 'db:seed'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'db:seed'; + /** * The console command description. * diff --git a/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php b/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php index aef7a77e6b1d..716f18729dd6 100644 --- a/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php @@ -13,6 +13,15 @@ class SeederMakeCommand extends GeneratorCommand */ protected $name = 'make:seeder'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:seeder'; + /** * The console command description. * diff --git a/src/Illuminate/Database/Console/WipeCommand.php b/src/Illuminate/Database/Console/WipeCommand.php index 30825ed7c567..2a7c1e5adbd4 100644 --- a/src/Illuminate/Database/Console/WipeCommand.php +++ b/src/Illuminate/Database/Console/WipeCommand.php @@ -17,6 +17,15 @@ class WipeCommand extends Command */ protected $name = 'db:wipe'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'db:wipe'; + /** * The console command description. * diff --git a/src/Illuminate/Database/MigrationServiceProvider.php b/src/Illuminate/Database/MigrationServiceProvider.php index 9ae768577361..d61f4423240c 100755 --- a/src/Illuminate/Database/MigrationServiceProvider.php +++ b/src/Illuminate/Database/MigrationServiceProvider.php @@ -25,14 +25,14 @@ class MigrationServiceProvider extends ServiceProvider implements DeferrableProv * @var array */ protected $commands = [ - 'Migrate' => 'command.migrate', - 'MigrateFresh' => 'command.migrate.fresh', - 'MigrateInstall' => 'command.migrate.install', - 'MigrateRefresh' => 'command.migrate.refresh', - 'MigrateReset' => 'command.migrate.reset', - 'MigrateRollback' => 'command.migrate.rollback', - 'MigrateStatus' => 'command.migrate.status', - 'MigrateMake' => 'command.migrate.make', + 'Migrate' => MigrateCommand::class, + 'MigrateFresh' => FreshCommand::class, + 'MigrateInstall' => InstallCommand::class, + 'MigrateRefresh' => RefreshCommand::class, + 'MigrateReset' => ResetCommand::class, + 'MigrateRollback' => RollbackCommand::class, + 'MigrateStatus' => StatusCommand::class, + 'MigrateMake' => MigrateMakeCommand::class, ]; /** @@ -116,7 +116,7 @@ protected function registerCommands(array $commands) */ protected function registerMigrateCommand() { - $this->app->singleton('command.migrate', function ($app) { + $this->app->singleton(MigrateCommand::class, function ($app) { return new MigrateCommand($app['migrator'], $app[Dispatcher::class]); }); } @@ -128,9 +128,7 @@ protected function registerMigrateCommand() */ protected function registerMigrateFreshCommand() { - $this->app->singleton('command.migrate.fresh', function () { - return new FreshCommand; - }); + $this->app->singleton(FreshCommand::class); } /** @@ -140,7 +138,7 @@ protected function registerMigrateFreshCommand() */ protected function registerMigrateInstallCommand() { - $this->app->singleton('command.migrate.install', function ($app) { + $this->app->singleton(InstallCommand::class, function ($app) { return new InstallCommand($app['migration.repository']); }); } @@ -152,7 +150,7 @@ protected function registerMigrateInstallCommand() */ protected function registerMigrateMakeCommand() { - $this->app->singleton('command.migrate.make', function ($app) { + $this->app->singleton(MigrateMakeCommand::class, function ($app) { // Once we have the migration creator registered, we will create the command // and inject the creator. The creator is responsible for the actual file // creation of the migrations, and may be extended by these developers. @@ -171,9 +169,7 @@ protected function registerMigrateMakeCommand() */ protected function registerMigrateRefreshCommand() { - $this->app->singleton('command.migrate.refresh', function () { - return new RefreshCommand; - }); + $this->app->singleton(RefreshCommand::class); } /** @@ -183,7 +179,7 @@ protected function registerMigrateRefreshCommand() */ protected function registerMigrateResetCommand() { - $this->app->singleton('command.migrate.reset', function ($app) { + $this->app->singleton(ResetCommand::class, function ($app) { return new ResetCommand($app['migrator']); }); } @@ -195,7 +191,7 @@ protected function registerMigrateResetCommand() */ protected function registerMigrateRollbackCommand() { - $this->app->singleton('command.migrate.rollback', function ($app) { + $this->app->singleton(RollbackCommand::class, function ($app) { return new RollbackCommand($app['migrator']); }); } @@ -207,7 +203,7 @@ protected function registerMigrateRollbackCommand() */ protected function registerMigrateStatusCommand() { - $this->app->singleton('command.migrate.status', function ($app) { + $this->app->singleton(StatusCommand::class, function ($app) { return new StatusCommand($app['migrator']); }); } diff --git a/src/Illuminate/Foundation/Console/CastMakeCommand.php b/src/Illuminate/Foundation/Console/CastMakeCommand.php index fd390de10406..d406fc94d583 100644 --- a/src/Illuminate/Foundation/Console/CastMakeCommand.php +++ b/src/Illuminate/Foundation/Console/CastMakeCommand.php @@ -13,6 +13,15 @@ class CastMakeCommand extends GeneratorCommand */ protected $name = 'make:cast'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:cast'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ChannelMakeCommand.php b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php index 202d81cfd685..5c80d422d980 100644 --- a/src/Illuminate/Foundation/Console/ChannelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php @@ -13,6 +13,15 @@ class ChannelMakeCommand extends GeneratorCommand */ protected $name = 'make:channel'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:channel'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ClearCompiledCommand.php b/src/Illuminate/Foundation/Console/ClearCompiledCommand.php index 87ea044b823a..94cbe931af87 100644 --- a/src/Illuminate/Foundation/Console/ClearCompiledCommand.php +++ b/src/Illuminate/Foundation/Console/ClearCompiledCommand.php @@ -13,6 +13,15 @@ class ClearCompiledCommand extends Command */ protected $name = 'clear-compiled'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'clear-compiled'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ComponentMakeCommand.php b/src/Illuminate/Foundation/Console/ComponentMakeCommand.php index b0f64908965f..473bf10d4bbc 100644 --- a/src/Illuminate/Foundation/Console/ComponentMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ComponentMakeCommand.php @@ -16,6 +16,15 @@ class ComponentMakeCommand extends GeneratorCommand */ protected $name = 'make:component'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:component'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ConfigCacheCommand.php b/src/Illuminate/Foundation/Console/ConfigCacheCommand.php index 2703ec7acb18..625074849521 100644 --- a/src/Illuminate/Foundation/Console/ConfigCacheCommand.php +++ b/src/Illuminate/Foundation/Console/ConfigCacheCommand.php @@ -17,6 +17,15 @@ class ConfigCacheCommand extends Command */ protected $name = 'config:cache'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'config:cache'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ConfigClearCommand.php b/src/Illuminate/Foundation/Console/ConfigClearCommand.php index d20e2d8583c0..3d39c4b78d02 100644 --- a/src/Illuminate/Foundation/Console/ConfigClearCommand.php +++ b/src/Illuminate/Foundation/Console/ConfigClearCommand.php @@ -14,6 +14,15 @@ class ConfigClearCommand extends Command */ protected $name = 'config:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'config:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php b/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php index cada887f91a9..b738cb074035 100644 --- a/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php @@ -15,6 +15,15 @@ class ConsoleMakeCommand extends GeneratorCommand */ protected $name = 'make:command'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:command'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/DownCommand.php b/src/Illuminate/Foundation/Console/DownCommand.php index 94c5906531d6..b91287b22f46 100644 --- a/src/Illuminate/Foundation/Console/DownCommand.php +++ b/src/Illuminate/Foundation/Console/DownCommand.php @@ -20,6 +20,15 @@ class DownCommand extends Command {--secret= : The secret phrase that may be used to bypass maintenance mode} {--status=503 : The status code that should be used when returning the maintenance mode response}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'down'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/EnvironmentCommand.php b/src/Illuminate/Foundation/Console/EnvironmentCommand.php index ab3bb3202e1a..32ce48c770bf 100644 --- a/src/Illuminate/Foundation/Console/EnvironmentCommand.php +++ b/src/Illuminate/Foundation/Console/EnvironmentCommand.php @@ -13,6 +13,15 @@ class EnvironmentCommand extends Command */ protected $name = 'env'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'env'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/EventCacheCommand.php b/src/Illuminate/Foundation/Console/EventCacheCommand.php index 310b40ac3a24..44800afbcef0 100644 --- a/src/Illuminate/Foundation/Console/EventCacheCommand.php +++ b/src/Illuminate/Foundation/Console/EventCacheCommand.php @@ -14,6 +14,15 @@ class EventCacheCommand extends Command */ protected $signature = 'event:cache'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'event:cache'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/EventClearCommand.php b/src/Illuminate/Foundation/Console/EventClearCommand.php index a5fe4e67c187..95546fa1b135 100644 --- a/src/Illuminate/Foundation/Console/EventClearCommand.php +++ b/src/Illuminate/Foundation/Console/EventClearCommand.php @@ -14,6 +14,15 @@ class EventClearCommand extends Command */ protected $name = 'event:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'event:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/EventGenerateCommand.php b/src/Illuminate/Foundation/Console/EventGenerateCommand.php index 529b198fa34a..4d2d0cd50300 100644 --- a/src/Illuminate/Foundation/Console/EventGenerateCommand.php +++ b/src/Illuminate/Foundation/Console/EventGenerateCommand.php @@ -15,6 +15,15 @@ class EventGenerateCommand extends Command */ protected $name = 'event:generate'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'event:generate'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index 4b11ebb4614c..1337f62d69e7 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -15,6 +15,15 @@ class EventListCommand extends Command */ protected $signature = 'event:list {--event= : Filter the events by name}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'event:list'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/EventMakeCommand.php b/src/Illuminate/Foundation/Console/EventMakeCommand.php index af7bf52611e9..3360278ada79 100644 --- a/src/Illuminate/Foundation/Console/EventMakeCommand.php +++ b/src/Illuminate/Foundation/Console/EventMakeCommand.php @@ -13,6 +13,15 @@ class EventMakeCommand extends GeneratorCommand */ protected $name = 'make:event'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:event'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php b/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php index 2bc0e6c32ea0..dd4bd09cf8fb 100644 --- a/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php @@ -14,6 +14,15 @@ class ExceptionMakeCommand extends GeneratorCommand */ protected $name = 'make:exception'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:exception'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/JobMakeCommand.php b/src/Illuminate/Foundation/Console/JobMakeCommand.php index 57c9a93b2f74..99a8e9a2f8b8 100644 --- a/src/Illuminate/Foundation/Console/JobMakeCommand.php +++ b/src/Illuminate/Foundation/Console/JobMakeCommand.php @@ -14,6 +14,15 @@ class JobMakeCommand extends GeneratorCommand */ protected $name = 'make:job'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:job'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/KeyGenerateCommand.php b/src/Illuminate/Foundation/Console/KeyGenerateCommand.php index 030ca2137403..6d5b02c79c4b 100644 --- a/src/Illuminate/Foundation/Console/KeyGenerateCommand.php +++ b/src/Illuminate/Foundation/Console/KeyGenerateCommand.php @@ -19,6 +19,15 @@ class KeyGenerateCommand extends Command {--show : Display the key instead of modifying files} {--force : Force the operation to run when in production}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'key:generate'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php index 0ded743aa7c7..e345d52d2c9d 100644 --- a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php @@ -15,6 +15,15 @@ class ListenerMakeCommand extends GeneratorCommand */ protected $name = 'make:listener'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:listener'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/MailMakeCommand.php b/src/Illuminate/Foundation/Console/MailMakeCommand.php index 19bef8db3c33..6fb255950c06 100644 --- a/src/Illuminate/Foundation/Console/MailMakeCommand.php +++ b/src/Illuminate/Foundation/Console/MailMakeCommand.php @@ -14,6 +14,15 @@ class MailMakeCommand extends GeneratorCommand */ protected $name = 'make:mail'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:mail'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ModelMakeCommand.php b/src/Illuminate/Foundation/Console/ModelMakeCommand.php index ceee516bb959..2a9a2269ccfd 100644 --- a/src/Illuminate/Foundation/Console/ModelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ModelMakeCommand.php @@ -15,6 +15,15 @@ class ModelMakeCommand extends GeneratorCommand */ protected $name = 'make:model'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:model'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/NotificationMakeCommand.php b/src/Illuminate/Foundation/Console/NotificationMakeCommand.php index 6eb66e282e3c..59312f4c9b28 100644 --- a/src/Illuminate/Foundation/Console/NotificationMakeCommand.php +++ b/src/Illuminate/Foundation/Console/NotificationMakeCommand.php @@ -14,6 +14,15 @@ class NotificationMakeCommand extends GeneratorCommand */ protected $name = 'make:notification'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:notification'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ObserverMakeCommand.php b/src/Illuminate/Foundation/Console/ObserverMakeCommand.php index a2661f3fabde..56e4d673b025 100644 --- a/src/Illuminate/Foundation/Console/ObserverMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ObserverMakeCommand.php @@ -15,6 +15,15 @@ class ObserverMakeCommand extends GeneratorCommand */ protected $name = 'make:observer'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:observer'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php index 0bd92dfee368..0af3cee2f852 100644 --- a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php +++ b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php @@ -13,6 +13,15 @@ class OptimizeClearCommand extends Command */ protected $name = 'optimize:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'optimize:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/OptimizeCommand.php b/src/Illuminate/Foundation/Console/OptimizeCommand.php index f42b75552016..8447b41e9b27 100644 --- a/src/Illuminate/Foundation/Console/OptimizeCommand.php +++ b/src/Illuminate/Foundation/Console/OptimizeCommand.php @@ -13,6 +13,15 @@ class OptimizeCommand extends Command */ protected $name = 'optimize'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'optimize'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/PackageDiscoverCommand.php b/src/Illuminate/Foundation/Console/PackageDiscoverCommand.php index 3ef8f01f302c..1129649b76e3 100644 --- a/src/Illuminate/Foundation/Console/PackageDiscoverCommand.php +++ b/src/Illuminate/Foundation/Console/PackageDiscoverCommand.php @@ -14,6 +14,15 @@ class PackageDiscoverCommand extends Command */ protected $signature = 'package:discover'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'package:discover'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php index 0fe6964d5940..e0a3d1041053 100644 --- a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php +++ b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php @@ -16,6 +16,15 @@ class PolicyMakeCommand extends GeneratorCommand */ protected $name = 'make:policy'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:policy'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ProviderMakeCommand.php b/src/Illuminate/Foundation/Console/ProviderMakeCommand.php index fa887edb6251..0427f6e2bc4c 100644 --- a/src/Illuminate/Foundation/Console/ProviderMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ProviderMakeCommand.php @@ -13,6 +13,15 @@ class ProviderMakeCommand extends GeneratorCommand */ protected $name = 'make:provider'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:provider'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/RequestMakeCommand.php b/src/Illuminate/Foundation/Console/RequestMakeCommand.php index 4605c818527a..3ed7b343fcd0 100644 --- a/src/Illuminate/Foundation/Console/RequestMakeCommand.php +++ b/src/Illuminate/Foundation/Console/RequestMakeCommand.php @@ -13,6 +13,15 @@ class RequestMakeCommand extends GeneratorCommand */ protected $name = 'make:request'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:request'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ResourceMakeCommand.php b/src/Illuminate/Foundation/Console/ResourceMakeCommand.php index abaf6f04a35f..513a8f8cee64 100644 --- a/src/Illuminate/Foundation/Console/ResourceMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ResourceMakeCommand.php @@ -15,6 +15,15 @@ class ResourceMakeCommand extends GeneratorCommand */ protected $name = 'make:resource'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:resource'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/RouteCacheCommand.php b/src/Illuminate/Foundation/Console/RouteCacheCommand.php index 05e52670ffdd..9fc94ad1f1e4 100644 --- a/src/Illuminate/Foundation/Console/RouteCacheCommand.php +++ b/src/Illuminate/Foundation/Console/RouteCacheCommand.php @@ -16,6 +16,15 @@ class RouteCacheCommand extends Command */ protected $name = 'route:cache'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'route:cache'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/RouteClearCommand.php b/src/Illuminate/Foundation/Console/RouteClearCommand.php index 03fab1d9fc90..757bafaff452 100644 --- a/src/Illuminate/Foundation/Console/RouteClearCommand.php +++ b/src/Illuminate/Foundation/Console/RouteClearCommand.php @@ -14,6 +14,15 @@ class RouteClearCommand extends Command */ protected $name = 'route:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'route:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index d14e58cf6315..5629d0877ca8 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -19,6 +19,15 @@ class RouteListCommand extends Command */ protected $name = 'route:list'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'route:list'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/RuleMakeCommand.php b/src/Illuminate/Foundation/Console/RuleMakeCommand.php index 111facb53ffc..5520cab6bd55 100644 --- a/src/Illuminate/Foundation/Console/RuleMakeCommand.php +++ b/src/Illuminate/Foundation/Console/RuleMakeCommand.php @@ -13,6 +13,15 @@ class RuleMakeCommand extends GeneratorCommand */ protected $name = 'make:rule'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:rule'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ServeCommand.php b/src/Illuminate/Foundation/Console/ServeCommand.php index e9ae5f11cdcd..84626fedf1d1 100644 --- a/src/Illuminate/Foundation/Console/ServeCommand.php +++ b/src/Illuminate/Foundation/Console/ServeCommand.php @@ -17,6 +17,15 @@ class ServeCommand extends Command */ protected $name = 'serve'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'serve'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/StorageLinkCommand.php b/src/Illuminate/Foundation/Console/StorageLinkCommand.php index a0419bf6c077..832e4bb742c2 100644 --- a/src/Illuminate/Foundation/Console/StorageLinkCommand.php +++ b/src/Illuminate/Foundation/Console/StorageLinkCommand.php @@ -13,6 +13,15 @@ class StorageLinkCommand extends Command */ protected $signature = 'storage:link {--relative : Create the symbolic link using relative paths}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'storage:link'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/StubPublishCommand.php b/src/Illuminate/Foundation/Console/StubPublishCommand.php index 901f99fe1f47..cc2fae2ed0d9 100644 --- a/src/Illuminate/Foundation/Console/StubPublishCommand.php +++ b/src/Illuminate/Foundation/Console/StubPublishCommand.php @@ -14,6 +14,15 @@ class StubPublishCommand extends Command */ protected $signature = 'stub:publish {--force : Overwrite any existing files}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'stub:publish'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/TestMakeCommand.php b/src/Illuminate/Foundation/Console/TestMakeCommand.php index c353819290ff..bae86c7729a7 100644 --- a/src/Illuminate/Foundation/Console/TestMakeCommand.php +++ b/src/Illuminate/Foundation/Console/TestMakeCommand.php @@ -15,6 +15,15 @@ class TestMakeCommand extends GeneratorCommand */ protected $name = 'make:test'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:test'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/UpCommand.php b/src/Illuminate/Foundation/Console/UpCommand.php index e81329c25311..4c1922021da1 100644 --- a/src/Illuminate/Foundation/Console/UpCommand.php +++ b/src/Illuminate/Foundation/Console/UpCommand.php @@ -14,6 +14,15 @@ class UpCommand extends Command */ protected $name = 'up'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'up'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/VendorPublishCommand.php b/src/Illuminate/Foundation/Console/VendorPublishCommand.php index 17a459e72834..842c3759da8a 100644 --- a/src/Illuminate/Foundation/Console/VendorPublishCommand.php +++ b/src/Illuminate/Foundation/Console/VendorPublishCommand.php @@ -43,6 +43,15 @@ class VendorPublishCommand extends Command {--provider= : The service provider that has assets you want to publish} {--tag=* : One or many tags that have assets you want to publish}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'vendor:publish'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ViewCacheCommand.php b/src/Illuminate/Foundation/Console/ViewCacheCommand.php index 19e0ab596f8f..515df790bb00 100644 --- a/src/Illuminate/Foundation/Console/ViewCacheCommand.php +++ b/src/Illuminate/Foundation/Console/ViewCacheCommand.php @@ -16,6 +16,15 @@ class ViewCacheCommand extends Command */ protected $signature = 'view:cache'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'view:cache'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Console/ViewClearCommand.php b/src/Illuminate/Foundation/Console/ViewClearCommand.php index 449ebe4b2a93..1276091d1ea9 100644 --- a/src/Illuminate/Foundation/Console/ViewClearCommand.php +++ b/src/Illuminate/Foundation/Console/ViewClearCommand.php @@ -15,6 +15,15 @@ class ViewClearCommand extends Command */ protected $name = 'view:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'view:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index dc82ba1df83c..4c4f8644d045 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -82,43 +82,43 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid * @var array */ protected $commands = [ - 'CacheClear' => 'command.cache.clear', - 'CacheForget' => 'command.cache.forget', - 'ClearCompiled' => 'command.clear-compiled', - 'ClearResets' => 'command.auth.resets.clear', - 'ConfigCache' => 'command.config.cache', - 'ConfigClear' => 'command.config.clear', - 'DbWipe' => 'command.db.wipe', - 'Down' => 'command.down', - 'Environment' => 'command.environment', - 'EventCache' => 'command.event.cache', - 'EventClear' => 'command.event.clear', - 'EventList' => 'command.event.list', - 'KeyGenerate' => 'command.key.generate', - 'Optimize' => 'command.optimize', - 'OptimizeClear' => 'command.optimize.clear', - 'PackageDiscover' => 'command.package.discover', - 'QueueClear' => 'command.queue.clear', - 'QueueFailed' => 'command.queue.failed', - 'QueueFlush' => 'command.queue.flush', - 'QueueForget' => 'command.queue.forget', - 'QueueListen' => 'command.queue.listen', - 'QueueRestart' => 'command.queue.restart', - 'QueueRetry' => 'command.queue.retry', - 'QueueRetryBatch' => 'command.queue.retry-batch', - 'QueueWork' => 'command.queue.work', - 'RouteCache' => 'command.route.cache', - 'RouteClear' => 'command.route.clear', - 'RouteList' => 'command.route.list', - 'SchemaDump' => 'command.schema.dump', - 'Seed' => 'command.seed', + 'CacheClear' => CacheClearCommand::class, + 'CacheForget' => CacheForgetCommand::class, + 'ClearCompiled' => ClearCompiledCommand::class, + 'ClearResets' => ClearResetsCommand::class, + 'ConfigCache' => ConfigCacheCommand::class, + 'ConfigClear' => ConfigClearCommand::class, + 'DbWipe' => WipeCommand::class, + 'Down' => DownCommand::class, + 'Environment' => EnvironmentCommand::class, + 'EventCache' => EventCacheCommand::class, + 'EventClear' => EventClearCommand::class, + 'EventList' => EventListCommand::class, + 'KeyGenerate' => KeyGenerateCommand::class, + 'Optimize' => OptimizeCommand::class, + 'OptimizeClear' => OptimizeClearCommand::class, + 'PackageDiscover' => PackageDiscoverCommand::class, + 'QueueClear' => QueueClearCommand::class, + 'QueueFailed' => ListFailedQueueCommand::class, + 'QueueFlush' => FlushFailedQueueCommand::class, + 'QueueForget' => ForgetFailedQueueCommand::class, + 'QueueListen' => QueueListenCommand::class, + 'QueueRestart' => QueueRestartCommand::class, + 'QueueRetry' => QueueRetryCommand::class, + 'QueueRetryBatch' => QueueRetryBatchCommand::class, + 'QueueWork' => QueueWorkCommand::class, + 'RouteCache' => RouteCacheCommand::class, + 'RouteClear' => RouteClearCommand::class, + 'RouteList' => RouteListCommand::class, + 'SchemaDump' => DumpCommand::class, + 'Seed' => SeedCommand::class, 'ScheduleFinish' => ScheduleFinishCommand::class, 'ScheduleRun' => ScheduleRunCommand::class, 'ScheduleWork' => ScheduleWorkCommand::class, - 'StorageLink' => 'command.storage.link', - 'Up' => 'command.up', - 'ViewCache' => 'command.view.cache', - 'ViewClear' => 'command.view.clear', + 'StorageLink' => StorageLinkCommand::class, + 'Up' => UpCommand::class, + 'ViewCache' => ViewCacheCommand::class, + 'ViewClear' => ViewClearCommand::class, ]; /** @@ -127,38 +127,38 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid * @var array */ protected $devCommands = [ - 'CacheTable' => 'command.cache.table', - 'CastMake' => 'command.cast.make', - 'ChannelMake' => 'command.channel.make', - 'ComponentMake' => 'command.component.make', - 'ConsoleMake' => 'command.console.make', - 'ControllerMake' => 'command.controller.make', - 'EventGenerate' => 'command.event.generate', - 'EventMake' => 'command.event.make', - 'ExceptionMake' => 'command.exception.make', - 'FactoryMake' => 'command.factory.make', - 'JobMake' => 'command.job.make', - 'ListenerMake' => 'command.listener.make', - 'MailMake' => 'command.mail.make', - 'MiddlewareMake' => 'command.middleware.make', - 'ModelMake' => 'command.model.make', - 'NotificationMake' => 'command.notification.make', - 'NotificationTable' => 'command.notification.table', - 'ObserverMake' => 'command.observer.make', - 'PolicyMake' => 'command.policy.make', - 'ProviderMake' => 'command.provider.make', - 'QueueFailedTable' => 'command.queue.failed-table', - 'QueueTable' => 'command.queue.table', - 'QueueBatchesTable' => 'command.queue.batches-table', - 'RequestMake' => 'command.request.make', - 'ResourceMake' => 'command.resource.make', - 'RuleMake' => 'command.rule.make', - 'SeederMake' => 'command.seeder.make', - 'SessionTable' => 'command.session.table', - 'Serve' => 'command.serve', - 'StubPublish' => 'command.stub.publish', - 'TestMake' => 'command.test.make', - 'VendorPublish' => 'command.vendor.publish', + 'CacheTable' => CacheTableCommand::class, + 'CastMake' => CastMakeCommand::class, + 'ChannelMake' => ChannelMakeCommand::class, + 'ComponentMake' => ComponentMakeCommand::class, + 'ConsoleMake' => ConsoleMakeCommand::class, + 'ControllerMake' => ControllerMakeCommand::class, + 'EventGenerate' => EventGenerateCommand::class, + 'EventMake' => EventMakeCommand::class, + 'ExceptionMake' => ExceptionMakeCommand::class, + 'FactoryMake' => FactoryMakeCommand::class, + 'JobMake' => JobMakeCommand::class, + 'ListenerMake' => ListenerMakeCommand::class, + 'MailMake' => MailMakeCommand::class, + 'MiddlewareMake' => MiddlewareMakeCommand::class, + 'ModelMake' => ModelMakeCommand::class, + 'NotificationMake' => NotificationMakeCommand::class, + 'NotificationTable' => NotificationTableCommand::class, + 'ObserverMake' => ObserverMakeCommand::class, + 'PolicyMake' => PolicyMakeCommand::class, + 'ProviderMake' => ProviderMakeCommand::class, + 'QueueFailedTable' => FailedTableCommand::class, + 'QueueTable' => TableCommand::class, + 'QueueBatchesTable' => BatchesTableCommand::class, + 'RequestMake' => RequestMakeCommand::class, + 'ResourceMake' => ResourceMakeCommand::class, + 'RuleMake' => RuleMakeCommand::class, + 'SeederMake' => SeederMakeCommand::class, + 'SessionTable' => SessionTableCommand::class, + 'Serve' => ServeCommand::class, + 'StubPublish' => StubPublishCommand::class, + 'TestMake' => TestMakeCommand::class, + 'VendorPublish' => VendorPublishCommand::class, ]; /** @@ -195,7 +195,7 @@ protected function registerCommands(array $commands) */ protected function registerCacheClearCommand() { - $this->app->singleton('command.cache.clear', function ($app) { + $this->app->singleton(CacheClearCommand::class, function ($app) { return new CacheClearCommand($app['cache'], $app['files']); }); } @@ -207,7 +207,7 @@ protected function registerCacheClearCommand() */ protected function registerCacheForgetCommand() { - $this->app->singleton('command.cache.forget', function ($app) { + $this->app->singleton(CacheForgetCommand::class, function ($app) { return new CacheForgetCommand($app['cache']); }); } @@ -219,7 +219,7 @@ protected function registerCacheForgetCommand() */ protected function registerCacheTableCommand() { - $this->app->singleton('command.cache.table', function ($app) { + $this->app->singleton(CacheTableCommand::class, function ($app) { return new CacheTableCommand($app['files'], $app['composer']); }); } @@ -231,7 +231,7 @@ protected function registerCacheTableCommand() */ protected function registerCastMakeCommand() { - $this->app->singleton('command.cast.make', function ($app) { + $this->app->singleton(CastMakeCommand::class, function ($app) { return new CastMakeCommand($app['files']); }); } @@ -243,7 +243,7 @@ protected function registerCastMakeCommand() */ protected function registerChannelMakeCommand() { - $this->app->singleton('command.channel.make', function ($app) { + $this->app->singleton(ChannelMakeCommand::class, function ($app) { return new ChannelMakeCommand($app['files']); }); } @@ -255,9 +255,7 @@ protected function registerChannelMakeCommand() */ protected function registerClearCompiledCommand() { - $this->app->singleton('command.clear-compiled', function () { - return new ClearCompiledCommand; - }); + $this->app->singleton(ClearCompiledCommand::class); } /** @@ -267,9 +265,7 @@ protected function registerClearCompiledCommand() */ protected function registerClearResetsCommand() { - $this->app->singleton('command.auth.resets.clear', function () { - return new ClearResetsCommand; - }); + $this->app->singleton(ClearResetsCommand::class); } /** @@ -279,7 +275,7 @@ protected function registerClearResetsCommand() */ protected function registerComponentMakeCommand() { - $this->app->singleton('command.component.make', function ($app) { + $this->app->singleton(ComponentMakeCommand::class, function ($app) { return new ComponentMakeCommand($app['files']); }); } @@ -291,7 +287,7 @@ protected function registerComponentMakeCommand() */ protected function registerConfigCacheCommand() { - $this->app->singleton('command.config.cache', function ($app) { + $this->app->singleton(ConfigCacheCommand::class, function ($app) { return new ConfigCacheCommand($app['files']); }); } @@ -303,7 +299,7 @@ protected function registerConfigCacheCommand() */ protected function registerConfigClearCommand() { - $this->app->singleton('command.config.clear', function ($app) { + $this->app->singleton(ConfigClearCommand::class, function ($app) { return new ConfigClearCommand($app['files']); }); } @@ -315,7 +311,7 @@ protected function registerConfigClearCommand() */ protected function registerConsoleMakeCommand() { - $this->app->singleton('command.console.make', function ($app) { + $this->app->singleton(ConsoleMakeCommand::class, function ($app) { return new ConsoleMakeCommand($app['files']); }); } @@ -327,7 +323,7 @@ protected function registerConsoleMakeCommand() */ protected function registerControllerMakeCommand() { - $this->app->singleton('command.controller.make', function ($app) { + $this->app->singleton(ControllerMakeCommand::class, function ($app) { return new ControllerMakeCommand($app['files']); }); } @@ -339,9 +335,7 @@ protected function registerControllerMakeCommand() */ protected function registerDbWipeCommand() { - $this->app->singleton('command.db.wipe', function () { - return new WipeCommand; - }); + $this->app->singleton(WipeCommand::class); } /** @@ -351,9 +345,7 @@ protected function registerDbWipeCommand() */ protected function registerEventGenerateCommand() { - $this->app->singleton('command.event.generate', function () { - return new EventGenerateCommand; - }); + $this->app->singleton(EventGenerateCommand::class); } /** @@ -363,7 +355,7 @@ protected function registerEventGenerateCommand() */ protected function registerEventMakeCommand() { - $this->app->singleton('command.event.make', function ($app) { + $this->app->singleton(EventMakeCommand::class, function ($app) { return new EventMakeCommand($app['files']); }); } @@ -375,7 +367,7 @@ protected function registerEventMakeCommand() */ protected function registerExceptionMakeCommand() { - $this->app->singleton('command.exception.make', function ($app) { + $this->app->singleton(ExceptionMakeCommand::class, function ($app) { return new ExceptionMakeCommand($app['files']); }); } @@ -387,7 +379,7 @@ protected function registerExceptionMakeCommand() */ protected function registerFactoryMakeCommand() { - $this->app->singleton('command.factory.make', function ($app) { + $this->app->singleton(FactoryMakeCommand::class, function ($app) { return new FactoryMakeCommand($app['files']); }); } @@ -399,9 +391,7 @@ protected function registerFactoryMakeCommand() */ protected function registerDownCommand() { - $this->app->singleton('command.down', function () { - return new DownCommand; - }); + $this->app->singleton(DownCommand::class); } /** @@ -411,9 +401,7 @@ protected function registerDownCommand() */ protected function registerEnvironmentCommand() { - $this->app->singleton('command.environment', function () { - return new EnvironmentCommand; - }); + $this->app->singleton(EnvironmentCommand::class); } /** @@ -423,9 +411,7 @@ protected function registerEnvironmentCommand() */ protected function registerEventCacheCommand() { - $this->app->singleton('command.event.cache', function () { - return new EventCacheCommand; - }); + $this->app->singleton(EventCacheCommand::class); } /** @@ -435,7 +421,7 @@ protected function registerEventCacheCommand() */ protected function registerEventClearCommand() { - $this->app->singleton('command.event.clear', function ($app) { + $this->app->singleton(EventClearCommand::class, function ($app) { return new EventClearCommand($app['files']); }); } @@ -447,9 +433,7 @@ protected function registerEventClearCommand() */ protected function registerEventListCommand() { - $this->app->singleton('command.event.list', function () { - return new EventListCommand(); - }); + $this->app->singleton(EventListCommand::class); } /** @@ -459,7 +443,7 @@ protected function registerEventListCommand() */ protected function registerJobMakeCommand() { - $this->app->singleton('command.job.make', function ($app) { + $this->app->singleton(JobMakeCommand::class, function ($app) { return new JobMakeCommand($app['files']); }); } @@ -471,9 +455,7 @@ protected function registerJobMakeCommand() */ protected function registerKeyGenerateCommand() { - $this->app->singleton('command.key.generate', function () { - return new KeyGenerateCommand; - }); + $this->app->singleton(KeyGenerateCommand::class); } /** @@ -483,7 +465,7 @@ protected function registerKeyGenerateCommand() */ protected function registerListenerMakeCommand() { - $this->app->singleton('command.listener.make', function ($app) { + $this->app->singleton(ListenerMakeCommand::class, function ($app) { return new ListenerMakeCommand($app['files']); }); } @@ -495,7 +477,7 @@ protected function registerListenerMakeCommand() */ protected function registerMailMakeCommand() { - $this->app->singleton('command.mail.make', function ($app) { + $this->app->singleton(MailMakeCommand::class, function ($app) { return new MailMakeCommand($app['files']); }); } @@ -507,7 +489,7 @@ protected function registerMailMakeCommand() */ protected function registerMiddlewareMakeCommand() { - $this->app->singleton('command.middleware.make', function ($app) { + $this->app->singleton(MiddlewareMakeCommand::class, function ($app) { return new MiddlewareMakeCommand($app['files']); }); } @@ -519,7 +501,7 @@ protected function registerMiddlewareMakeCommand() */ protected function registerModelMakeCommand() { - $this->app->singleton('command.model.make', function ($app) { + $this->app->singleton(ModelMakeCommand::class, function ($app) { return new ModelMakeCommand($app['files']); }); } @@ -531,7 +513,7 @@ protected function registerModelMakeCommand() */ protected function registerNotificationMakeCommand() { - $this->app->singleton('command.notification.make', function ($app) { + $this->app->singleton(NotificationMakeCommand::class, function ($app) { return new NotificationMakeCommand($app['files']); }); } @@ -543,7 +525,7 @@ protected function registerNotificationMakeCommand() */ protected function registerNotificationTableCommand() { - $this->app->singleton('command.notification.table', function ($app) { + $this->app->singleton(NotificationTableCommand::class, function ($app) { return new NotificationTableCommand($app['files'], $app['composer']); }); } @@ -555,9 +537,7 @@ protected function registerNotificationTableCommand() */ protected function registerOptimizeCommand() { - $this->app->singleton('command.optimize', function () { - return new OptimizeCommand; - }); + $this->app->singleton(OptimizeCommand::class); } /** @@ -567,7 +547,7 @@ protected function registerOptimizeCommand() */ protected function registerObserverMakeCommand() { - $this->app->singleton('command.observer.make', function ($app) { + $this->app->singleton(ObserverMakeCommand::class, function ($app) { return new ObserverMakeCommand($app['files']); }); } @@ -579,9 +559,7 @@ protected function registerObserverMakeCommand() */ protected function registerOptimizeClearCommand() { - $this->app->singleton('command.optimize.clear', function () { - return new OptimizeClearCommand; - }); + $this->app->singleton(OptimizeClearCommand::class); } /** @@ -591,9 +569,7 @@ protected function registerOptimizeClearCommand() */ protected function registerPackageDiscoverCommand() { - $this->app->singleton('command.package.discover', function () { - return new PackageDiscoverCommand; - }); + $this->app->singleton(PackageDiscoverCommand::class); } /** @@ -603,7 +579,7 @@ protected function registerPackageDiscoverCommand() */ protected function registerPolicyMakeCommand() { - $this->app->singleton('command.policy.make', function ($app) { + $this->app->singleton(PolicyMakeCommand::class, function ($app) { return new PolicyMakeCommand($app['files']); }); } @@ -615,7 +591,7 @@ protected function registerPolicyMakeCommand() */ protected function registerProviderMakeCommand() { - $this->app->singleton('command.provider.make', function ($app) { + $this->app->singleton(ProviderMakeCommand::class, function ($app) { return new ProviderMakeCommand($app['files']); }); } @@ -627,9 +603,7 @@ protected function registerProviderMakeCommand() */ protected function registerQueueFailedCommand() { - $this->app->singleton('command.queue.failed', function () { - return new ListFailedQueueCommand; - }); + $this->app->singleton(ListFailedQueueCommand::class); } /** @@ -639,9 +613,7 @@ protected function registerQueueFailedCommand() */ protected function registerQueueForgetCommand() { - $this->app->singleton('command.queue.forget', function () { - return new ForgetFailedQueueCommand; - }); + $this->app->singleton(ForgetFailedQueueCommand::class); } /** @@ -651,9 +623,7 @@ protected function registerQueueForgetCommand() */ protected function registerQueueFlushCommand() { - $this->app->singleton('command.queue.flush', function () { - return new FlushFailedQueueCommand; - }); + $this->app->singleton(FlushFailedQueueCommand::class); } /** @@ -663,7 +633,7 @@ protected function registerQueueFlushCommand() */ protected function registerQueueListenCommand() { - $this->app->singleton('command.queue.listen', function ($app) { + $this->app->singleton(QueueListenCommand::class, function ($app) { return new QueueListenCommand($app['queue.listener']); }); } @@ -675,7 +645,7 @@ protected function registerQueueListenCommand() */ protected function registerQueueRestartCommand() { - $this->app->singleton('command.queue.restart', function ($app) { + $this->app->singleton(QueueRestartCommand::class, function ($app) { return new QueueRestartCommand($app['cache.store']); }); } @@ -687,9 +657,7 @@ protected function registerQueueRestartCommand() */ protected function registerQueueRetryCommand() { - $this->app->singleton('command.queue.retry', function () { - return new QueueRetryCommand; - }); + $this->app->singleton(QueueRetryCommand::class); } /** @@ -699,9 +667,7 @@ protected function registerQueueRetryCommand() */ protected function registerQueueRetryBatchCommand() { - $this->app->singleton('command.queue.retry-batch', function () { - return new QueueRetryBatchCommand; - }); + $this->app->singleton(QueueRetryBatchCommand::class); } /** @@ -711,7 +677,7 @@ protected function registerQueueRetryBatchCommand() */ protected function registerQueueWorkCommand() { - $this->app->singleton('command.queue.work', function ($app) { + $this->app->singleton(QueueWorkCommand::class, function ($app) { return new QueueWorkCommand($app['queue.worker'], $app['cache.store']); }); } @@ -723,9 +689,7 @@ protected function registerQueueWorkCommand() */ protected function registerQueueClearCommand() { - $this->app->singleton('command.queue.clear', function () { - return new QueueClearCommand; - }); + $this->app->singleton(QueueClearCommand::class); } /** @@ -735,7 +699,7 @@ protected function registerQueueClearCommand() */ protected function registerQueueFailedTableCommand() { - $this->app->singleton('command.queue.failed-table', function ($app) { + $this->app->singleton(FailedTableCommand::class, function ($app) { return new FailedTableCommand($app['files'], $app['composer']); }); } @@ -747,7 +711,7 @@ protected function registerQueueFailedTableCommand() */ protected function registerQueueTableCommand() { - $this->app->singleton('command.queue.table', function ($app) { + $this->app->singleton(TableCommand::class, function ($app) { return new TableCommand($app['files'], $app['composer']); }); } @@ -759,7 +723,7 @@ protected function registerQueueTableCommand() */ protected function registerQueueBatchesTableCommand() { - $this->app->singleton('command.queue.batches-table', function ($app) { + $this->app->singleton(BatchesTableCommand::class, function ($app) { return new BatchesTableCommand($app['files'], $app['composer']); }); } @@ -771,7 +735,7 @@ protected function registerQueueBatchesTableCommand() */ protected function registerRequestMakeCommand() { - $this->app->singleton('command.request.make', function ($app) { + $this->app->singleton(RequestMakeCommand::class, function ($app) { return new RequestMakeCommand($app['files']); }); } @@ -783,7 +747,7 @@ protected function registerRequestMakeCommand() */ protected function registerResourceMakeCommand() { - $this->app->singleton('command.resource.make', function ($app) { + $this->app->singleton(ResourceMakeCommand::class, function ($app) { return new ResourceMakeCommand($app['files']); }); } @@ -795,7 +759,7 @@ protected function registerResourceMakeCommand() */ protected function registerRuleMakeCommand() { - $this->app->singleton('command.rule.make', function ($app) { + $this->app->singleton(RuleMakeCommand::class, function ($app) { return new RuleMakeCommand($app['files']); }); } @@ -807,7 +771,7 @@ protected function registerRuleMakeCommand() */ protected function registerSeederMakeCommand() { - $this->app->singleton('command.seeder.make', function ($app) { + $this->app->singleton(SeederMakeCommand::class, function ($app) { return new SeederMakeCommand($app['files'], $app['composer']); }); } @@ -819,7 +783,7 @@ protected function registerSeederMakeCommand() */ protected function registerSessionTableCommand() { - $this->app->singleton('command.session.table', function ($app) { + $this->app->singleton(SessionTableCommand::class, function ($app) { return new SessionTableCommand($app['files'], $app['composer']); }); } @@ -831,9 +795,7 @@ protected function registerSessionTableCommand() */ protected function registerStorageLinkCommand() { - $this->app->singleton('command.storage.link', function () { - return new StorageLinkCommand; - }); + $this->app->singleton(StorageLinkCommand::class); } /** @@ -843,7 +805,7 @@ protected function registerStorageLinkCommand() */ protected function registerRouteCacheCommand() { - $this->app->singleton('command.route.cache', function ($app) { + $this->app->singleton(RouteCacheCommand::class, function ($app) { return new RouteCacheCommand($app['files']); }); } @@ -855,7 +817,7 @@ protected function registerRouteCacheCommand() */ protected function registerRouteClearCommand() { - $this->app->singleton('command.route.clear', function ($app) { + $this->app->singleton(RouteClearCommand::class, function ($app) { return new RouteClearCommand($app['files']); }); } @@ -867,7 +829,7 @@ protected function registerRouteClearCommand() */ protected function registerRouteListCommand() { - $this->app->singleton('command.route.list', function ($app) { + $this->app->singleton(RouteListCommand::class, function ($app) { return new RouteListCommand($app['router']); }); } @@ -879,9 +841,7 @@ protected function registerRouteListCommand() */ protected function registerSchemaDumpCommand() { - $this->app->singleton('command.schema.dump', function () { - return new DumpCommand; - }); + $this->app->singleton(DumpCommand::class); } /** @@ -891,7 +851,7 @@ protected function registerSchemaDumpCommand() */ protected function registerSeedCommand() { - $this->app->singleton('command.seed', function ($app) { + $this->app->singleton(SeedCommand::class, function ($app) { return new SeedCommand($app['db']); }); } @@ -933,9 +893,7 @@ protected function registerScheduleWorkCommand() */ protected function registerServeCommand() { - $this->app->singleton('command.serve', function () { - return new ServeCommand; - }); + $this->app->singleton(ServeCommand::class); } /** @@ -945,9 +903,7 @@ protected function registerServeCommand() */ protected function registerStubPublishCommand() { - $this->app->singleton('command.stub.publish', function () { - return new StubPublishCommand; - }); + $this->app->singleton(StubPublishCommand::class); } /** @@ -957,7 +913,7 @@ protected function registerStubPublishCommand() */ protected function registerTestMakeCommand() { - $this->app->singleton('command.test.make', function ($app) { + $this->app->singleton(TestMakeCommand::class, function ($app) { return new TestMakeCommand($app['files']); }); } @@ -969,9 +925,7 @@ protected function registerTestMakeCommand() */ protected function registerUpCommand() { - $this->app->singleton('command.up', function () { - return new UpCommand; - }); + $this->app->singleton(UpCommand::class); } /** @@ -981,7 +935,7 @@ protected function registerUpCommand() */ protected function registerVendorPublishCommand() { - $this->app->singleton('command.vendor.publish', function ($app) { + $this->app->singleton(VendorPublishCommand::class, function ($app) { return new VendorPublishCommand($app['files']); }); } @@ -993,9 +947,7 @@ protected function registerVendorPublishCommand() */ protected function registerViewCacheCommand() { - $this->app->singleton('command.view.cache', function () { - return new ViewCacheCommand; - }); + $this->app->singleton(ViewCacheCommand::class); } /** @@ -1005,7 +957,7 @@ protected function registerViewCacheCommand() */ protected function registerViewClearCommand() { - $this->app->singleton('command.view.clear', function ($app) { + $this->app->singleton(ViewClearCommand::class, function ($app) { return new ViewClearCommand($app['files']); }); } diff --git a/src/Illuminate/Notifications/Console/NotificationTableCommand.php b/src/Illuminate/Notifications/Console/NotificationTableCommand.php index f447fc180ad7..31c63bcbef4c 100644 --- a/src/Illuminate/Notifications/Console/NotificationTableCommand.php +++ b/src/Illuminate/Notifications/Console/NotificationTableCommand.php @@ -15,6 +15,15 @@ class NotificationTableCommand extends Command */ protected $name = 'notifications:table'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'notifications:table'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/BatchesTableCommand.php b/src/Illuminate/Queue/Console/BatchesTableCommand.php index 1edee033e483..86c9d928fb90 100644 --- a/src/Illuminate/Queue/Console/BatchesTableCommand.php +++ b/src/Illuminate/Queue/Console/BatchesTableCommand.php @@ -16,6 +16,15 @@ class BatchesTableCommand extends Command */ protected $name = 'queue:batches-table'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:batches-table'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/ClearCommand.php b/src/Illuminate/Queue/Console/ClearCommand.php index ff9f936021f8..0131181d006b 100644 --- a/src/Illuminate/Queue/Console/ClearCommand.php +++ b/src/Illuminate/Queue/Console/ClearCommand.php @@ -20,6 +20,15 @@ class ClearCommand extends Command */ protected $name = 'queue:clear'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:clear'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/FailedTableCommand.php b/src/Illuminate/Queue/Console/FailedTableCommand.php index 09d3986dbb8a..aab84d21a5dd 100644 --- a/src/Illuminate/Queue/Console/FailedTableCommand.php +++ b/src/Illuminate/Queue/Console/FailedTableCommand.php @@ -16,6 +16,15 @@ class FailedTableCommand extends Command */ protected $name = 'queue:failed-table'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:failed-table'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/FlushFailedCommand.php b/src/Illuminate/Queue/Console/FlushFailedCommand.php index 550b86004ba3..302278af9bed 100644 --- a/src/Illuminate/Queue/Console/FlushFailedCommand.php +++ b/src/Illuminate/Queue/Console/FlushFailedCommand.php @@ -13,6 +13,15 @@ class FlushFailedCommand extends Command */ protected $name = 'queue:flush'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:flush'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/ForgetFailedCommand.php b/src/Illuminate/Queue/Console/ForgetFailedCommand.php index b8eecb96dfcd..b72a81278b55 100644 --- a/src/Illuminate/Queue/Console/ForgetFailedCommand.php +++ b/src/Illuminate/Queue/Console/ForgetFailedCommand.php @@ -13,6 +13,15 @@ class ForgetFailedCommand extends Command */ protected $signature = 'queue:forget {id : The ID of the failed job}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:forget'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/ListFailedCommand.php b/src/Illuminate/Queue/Console/ListFailedCommand.php index 66b5ddd52d86..904c529c6b9c 100644 --- a/src/Illuminate/Queue/Console/ListFailedCommand.php +++ b/src/Illuminate/Queue/Console/ListFailedCommand.php @@ -14,6 +14,15 @@ class ListFailedCommand extends Command */ protected $name = 'queue:failed'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:failed'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/ListenCommand.php b/src/Illuminate/Queue/Console/ListenCommand.php index f650e43195e3..a5a626db4e97 100755 --- a/src/Illuminate/Queue/Console/ListenCommand.php +++ b/src/Illuminate/Queue/Console/ListenCommand.php @@ -25,6 +25,15 @@ class ListenCommand extends Command {--timeout=60 : The number of seconds a child process can run} {--tries=1 : Number of times to attempt a job before logging it failed}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:listen'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/RestartCommand.php b/src/Illuminate/Queue/Console/RestartCommand.php index 9c610d924c07..cb1c91d6f7da 100644 --- a/src/Illuminate/Queue/Console/RestartCommand.php +++ b/src/Illuminate/Queue/Console/RestartCommand.php @@ -17,6 +17,15 @@ class RestartCommand extends Command */ protected $name = 'queue:restart'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:restart'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/RetryBatchCommand.php b/src/Illuminate/Queue/Console/RetryBatchCommand.php index 828278a48b92..6888b53f2e32 100644 --- a/src/Illuminate/Queue/Console/RetryBatchCommand.php +++ b/src/Illuminate/Queue/Console/RetryBatchCommand.php @@ -14,6 +14,15 @@ class RetryBatchCommand extends Command */ protected $signature = 'queue:retry-batch {id : The ID of the batch whose failed jobs should be retried}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:retry-batch'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index e9120a976962..35e7c0c46502 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -16,6 +16,15 @@ class RetryCommand extends Command {id?* : The ID of the failed job or "all" to retry all jobs} {--range=* : Range of job IDs (numeric) to be retried}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:retry'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/TableCommand.php b/src/Illuminate/Queue/Console/TableCommand.php index cc949d4890c9..3a083d487ccf 100644 --- a/src/Illuminate/Queue/Console/TableCommand.php +++ b/src/Illuminate/Queue/Console/TableCommand.php @@ -16,6 +16,15 @@ class TableCommand extends Command */ protected $name = 'queue:table'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:table'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index c8c815eefe24..681d297f9c73 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -36,6 +36,15 @@ class WorkCommand extends Command {--timeout=60 : The number of seconds a child process can run} {--tries=1 : Number of times to attempt a job before logging it failed}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:work'; + /** * The console command description. * diff --git a/src/Illuminate/Routing/Console/ControllerMakeCommand.php b/src/Illuminate/Routing/Console/ControllerMakeCommand.php index 6c78e4a959e5..7e7b780a23ef 100755 --- a/src/Illuminate/Routing/Console/ControllerMakeCommand.php +++ b/src/Illuminate/Routing/Console/ControllerMakeCommand.php @@ -15,6 +15,15 @@ class ControllerMakeCommand extends GeneratorCommand */ protected $name = 'make:controller'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:controller'; + /** * The console command description. * diff --git a/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php b/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php index cd53582b4d61..229f1a169f7f 100644 --- a/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php +++ b/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php @@ -13,6 +13,15 @@ class MiddlewareMakeCommand extends GeneratorCommand */ protected $name = 'make:middleware'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'make:middleware'; + /** * The console command description. * diff --git a/src/Illuminate/Session/Console/SessionTableCommand.php b/src/Illuminate/Session/Console/SessionTableCommand.php index 1675c19c2a47..5deacd011e31 100644 --- a/src/Illuminate/Session/Console/SessionTableCommand.php +++ b/src/Illuminate/Session/Console/SessionTableCommand.php @@ -15,6 +15,15 @@ class SessionTableCommand extends Command */ protected $name = 'session:table'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'session:table'; + /** * The console command description. * From 186a1c3c60a4352e6c11b8877e5c5dba2c88bba4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 22 Oct 2020 08:43:55 -0500 Subject: [PATCH 015/194] remove defaultName by default --- src/Illuminate/Foundation/Console/stubs/console.stub | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/console.stub b/src/Illuminate/Foundation/Console/stubs/console.stub index 90fd300842c0..0f751a3c75fd 100644 --- a/src/Illuminate/Foundation/Console/stubs/console.stub +++ b/src/Illuminate/Foundation/Console/stubs/console.stub @@ -13,15 +13,6 @@ class {{ class }} extends Command */ protected $signature = '{{ command }}'; - /** - * The name of the console command. - * - * This name is used to identify the command during lazy loading. - * - * @var string|null - */ - protected static $defaultName = '{{ command }}'; - /** * The console command description. * From 7c1fbb32ed9f2cdb6b20ea79d5bc83db32411e6a Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Thu, 22 Oct 2020 14:49:12 -0400 Subject: [PATCH 016/194] Add expects to built-in Facade testing methods (#34936) --- src/Illuminate/Support/Facades/Facade.php | 16 ++++++++++++++++ tests/Support/SupportFacadeTest.php | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Illuminate/Support/Facades/Facade.php b/src/Illuminate/Support/Facades/Facade.php index 64c39b43340e..87e308042347 100755 --- a/src/Illuminate/Support/Facades/Facade.php +++ b/src/Illuminate/Support/Facades/Facade.php @@ -90,6 +90,22 @@ public static function shouldReceive() return $mock->shouldReceive(...func_get_args()); } + /** + * Initiate a mock expectation on the facade. + * + * @return \Mockery\Expectation + */ + public static function expects() + { + $name = static::getFacadeAccessor(); + + $mock = static::isMock() + ? static::$resolvedInstance[$name] + : static::createFreshMockInstance(); + + return $mock->expects(...func_get_args()); + } + /** * Create a fresh mock instance for the given class. * diff --git a/tests/Support/SupportFacadeTest.php b/tests/Support/SupportFacadeTest.php index 0daa265d5fb4..d960c1d6e1f8 100755 --- a/tests/Support/SupportFacadeTest.php +++ b/tests/Support/SupportFacadeTest.php @@ -70,6 +70,16 @@ public function testCanBeMockedWithoutUnderlyingInstance() FacadeStub::shouldReceive('foo')->once()->andReturn('bar'); $this->assertSame('bar', FacadeStub::foo()); } + + public function testExpectsReturnsAMockeryMockWithExpectationRequired() + { + $app = new ApplicationStub; + $app->setAttributes(['foo' => new stdClass]); + FacadeStub::setFacadeApplication($app); + + $this->assertInstanceOf(MockInterface::class, $mock = FacadeStub::expects('foo')->with('bar')->andReturn('baz')->getMock()); + $this->assertSame('baz', $app['foo']->foo('bar')); + } } class FacadeStub extends Facade From 9717c195fa4ab1edb489041b82563c28d7edb52a Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 27 Oct 2020 19:53:47 +0000 Subject: [PATCH 017/194] Apply fixes from StyleCI (#35002) --- src/Illuminate/Console/Scheduling/Event.php | 2 +- src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 3f68f167ddc8..0bfaeaf8c429 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -12,8 +12,8 @@ use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Date; -use Illuminate\Support\Stringable; use Illuminate\Support\Reflector; +use Illuminate\Support\Stringable; use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\ReflectsClosures; use Psr\Http\Client\ClientExceptionInterface; diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 47d6e810ede6..52e4c40ea732 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -20,8 +20,8 @@ use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\View; -use Illuminate\Support\Traits\ReflectsClosures; use Illuminate\Support\Reflector; +use Illuminate\Support\Traits\ReflectsClosures; use Illuminate\Support\ViewErrorBag; use Illuminate\Validation\ValidationException; use InvalidArgumentException; From 84f4a4b447dfb16885d3e0aeaa815f2de381c5ff Mon Sep 17 00:00:00 2001 From: imanghafoori Date: Thu, 5 Nov 2020 01:19:54 +0330 Subject: [PATCH 018/194] tweak event:list command --- src/Illuminate/Events/Dispatcher.php | 38 +++++++++++-- .../Foundation/Console/EventListCommand.php | 55 +++++++++++++++++++ 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 91214b457188..64eaffd9aca4 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -87,7 +87,7 @@ public function listen($events, $listener = null) if (Str::contains($event, '*')) { $this->setupWildcardListen($event, $listener); } else { - $this->listeners[$event][] = $this->makeListener($listener); + $this->listeners[$event][] = $listener; } } } @@ -101,7 +101,7 @@ public function listen($events, $listener = null) */ protected function setupWildcardListen($event, $listener) { - $this->wildcards[$event][] = $this->makeListener($listener, true); + $this->wildcards[$event][] = $listener; $this->wildcardsCache = []; } @@ -307,6 +307,16 @@ protected function broadcastEvent($event) $this->container->make(BroadcastFactory::class)->queue($event); } + /** + * Gets the raw version of listeners. + * + * @return array + */ + protected function getRawListeners() + { + return $this->listeners; + } + /** * Get all of the listeners for a given event name. * @@ -315,7 +325,7 @@ protected function broadcastEvent($event) */ public function getListeners($eventName) { - $listeners = $this->listeners[$eventName] ?? []; + $listeners = $this->prepareListeners($eventName); $listeners = array_merge( $listeners, @@ -339,7 +349,9 @@ protected function getWildcardListeners($eventName) foreach ($this->wildcards as $key => $listeners) { if (Str::is($key, $eventName)) { - $wildcards = array_merge($wildcards, $listeners); + foreach ($listeners as $listener) { + $wildcards[] = $this->makeListener($listener, true); + } } } @@ -357,7 +369,7 @@ protected function addInterfaceListeners($eventName, array $listeners = []) { foreach (class_implements($eventName) as $interface) { if (isset($this->listeners[$interface])) { - foreach ($this->listeners[$interface] as $names) { + foreach ($this->prepareListeners($interface) as $names) { $listeners = array_merge($listeners, (array) $names); } } @@ -619,4 +631,20 @@ public function setQueueResolver(callable $resolver) return $this; } + + /** + * prepares the listeners of an event. + * + * @param string $eventName + * @return \Closure[] + */ + protected function prepareListeners(string $eventName) + { + $listeners = []; + foreach ($this->listeners[$eventName] ?? [] as $listener) { + $listeners[] = $this->makeListener($listener); + } + + return $listeners; + } } diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index 1337f62d69e7..88e7f1a7038f 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -2,9 +2,11 @@ namespace Illuminate\Foundation\Console; +use Closure; use Illuminate\Console\Command; use Illuminate\Foundation\Support\Providers\EventServiceProvider; use Illuminate\Support\Str; +use ReflectionFunction; class EventListCommand extends Command { @@ -62,6 +64,8 @@ protected function getEvents() $events = array_merge_recursive($events, $providerEvents); } + $events = $this->addListenersOnDispatcher($events); + if ($this->filteringByEvent()) { $events = $this->filterEvents($events); } @@ -97,4 +101,55 @@ protected function filteringByEvent() { return ! empty($this->option('event')); } + + /** + * Adds the event/listeners on the dispatcher object to the given list. + * + * @param array $events + * + * @return array + */ + protected function addListenersOnDispatcher(array $events) + { + foreach ($this->getRawListeners() as $event => $rawListeners) { + foreach ($rawListeners as $rawListener) { + if (is_string($rawListener)) { + $events[$event][] = $rawListener; + } elseif ($rawListener instanceof Closure) { + $events[$event][] = $this->stringifyClosure($rawListener); + } + } + } + + return $events; + } + + /** + * Creates a printable string version of a closure. + * + * @param Closure $rawListener + * + * @return string + */ + protected function stringifyClosure(Closure $rawListener) + { + $reflection = new ReflectionFunction($rawListener); + $path = str_replace(base_path(), '', $reflection->getFileName() ?: ''); + + return 'Closure at: '.$path.':'.$reflection->getStartLine(); + } + + /** + * Gets the raw version of event listeners from dispatcher object. + * + * @return array + */ + protected function getRawListeners() + { + try { + return $this->getLaravel()->make('events')->getRawListeners(); + } catch (\Throwable $e) { + return []; + } + } } From 21e2629287392d163043651f5b6bb4fb88c63d36 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 6 Nov 2020 10:03:21 -0600 Subject: [PATCH 019/194] formatting and fixes --- src/Illuminate/Events/Dispatcher.php | 48 ++++++------- .../Foundation/Console/EventListCommand.php | 69 +++++++++---------- 2 files changed, 57 insertions(+), 60 deletions(-) diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 64eaffd9aca4..454d2a6e56c6 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -307,16 +307,6 @@ protected function broadcastEvent($event) $this->container->make(BroadcastFactory::class)->queue($event); } - /** - * Gets the raw version of listeners. - * - * @return array - */ - protected function getRawListeners() - { - return $this->listeners; - } - /** * Get all of the listeners for a given event name. * @@ -325,10 +315,8 @@ protected function getRawListeners() */ public function getListeners($eventName) { - $listeners = $this->prepareListeners($eventName); - $listeners = array_merge( - $listeners, + $this->prepareListeners($eventName), $this->wildcardsCache[$eventName] ?? $this->getWildcardListeners($eventName) ); @@ -378,6 +366,23 @@ protected function addInterfaceListeners($eventName, array $listeners = []) return $listeners; } + /** + * Prepare the listeners for a given event. + * + * @param string $eventName + * @return \Closure[] + */ + protected function prepareListeners(string $eventName) + { + $listeners = []; + + foreach ($this->listeners[$eventName] ?? [] as $listener) { + $listeners[] = $this->makeListener($listener); + } + + return $listeners; + } + /** * Register an event listener with the dispatcher. * @@ -566,9 +571,12 @@ protected function propagateListenerOptions($listener, $job) { return tap($job, function ($job) use ($listener) { $job->tries = $listener->tries ?? null; + $job->backoff = method_exists($listener, 'backoff') ? $listener->backoff() : ($listener->backoff ?? null); + $job->timeout = $listener->timeout ?? null; + $job->retryUntil = method_exists($listener, 'retryUntil') ? $listener->retryUntil() : null; }); @@ -633,18 +641,12 @@ public function setQueueResolver(callable $resolver) } /** - * prepares the listeners of an event. + * Gets the raw, unprepared listeners. * - * @param string $eventName - * @return \Closure[] + * @return array */ - protected function prepareListeners(string $eventName) + public function getRawListeners() { - $listeners = []; - foreach ($this->listeners[$eventName] ?? [] as $listener) { - $listeners[] = $this->makeListener($listener); - } - - return $listeners; + return $this->listeners; } } diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index 88e7f1a7038f..28e25478e0fb 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -76,39 +76,11 @@ protected function getEvents() } /** - * Filter the given events using the provided event name filter. + * Adds the event / listeners on the dispatcher object to the given list. * * @param array $events * @return array */ - protected function filterEvents(array $events) - { - if (! $eventName = $this->option('event')) { - return $events; - } - - return collect($events)->filter(function ($listeners, $event) use ($eventName) { - return Str::contains($event, $eventName); - })->toArray(); - } - - /** - * Determine whether the user is filtering by an event name. - * - * @return bool - */ - protected function filteringByEvent() - { - return ! empty($this->option('event')); - } - - /** - * Adds the event/listeners on the dispatcher object to the given list. - * - * @param array $events - * - * @return array - */ protected function addListenersOnDispatcher(array $events) { foreach ($this->getRawListeners() as $event => $rawListeners) { @@ -125,20 +97,47 @@ protected function addListenersOnDispatcher(array $events) } /** - * Creates a printable string version of a closure. - * - * @param Closure $rawListener + * Get a displayable string representation of a Closure listener. * + * @param \Closure $rawListener * @return string */ protected function stringifyClosure(Closure $rawListener) { $reflection = new ReflectionFunction($rawListener); + $path = str_replace(base_path(), '', $reflection->getFileName() ?: ''); return 'Closure at: '.$path.':'.$reflection->getStartLine(); } + /** + * Filter the given events using the provided event name filter. + * + * @param array $events + * @return array + */ + protected function filterEvents(array $events) + { + if (! $eventName = $this->option('event')) { + return $events; + } + + return collect($events)->filter(function ($listeners, $event) use ($eventName) { + return Str::contains($event, $eventName); + })->toArray(); + } + + /** + * Determine whether the user is filtering by an event name. + * + * @return bool + */ + protected function filteringByEvent() + { + return ! empty($this->option('event')); + } + /** * Gets the raw version of event listeners from dispatcher object. * @@ -146,10 +145,6 @@ protected function stringifyClosure(Closure $rawListener) */ protected function getRawListeners() { - try { - return $this->getLaravel()->make('events')->getRawListeners(); - } catch (\Throwable $e) { - return []; - } + return $this->getLaravel()->make('events')->getRawListeners(); } } From 7780cd2c04bc611355216c89625313905b07f94b Mon Sep 17 00:00:00 2001 From: Roman Nix Date: Fri, 13 Nov 2020 21:14:08 +0700 Subject: [PATCH 020/194] [9.x] Add path to post create hooks in MigrationCreator (#35213) * add path to post create hooks in MigrationCreator * Update MigrationCreator.php Co-authored-by: Dries Vints --- .../Database/Migrations/MigrationCreator.php | 7 ++++--- tests/Database/DatabaseMigrationCreatorTest.php | 14 +++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Migrations/MigrationCreator.php b/src/Illuminate/Database/Migrations/MigrationCreator.php index a79039a7a20b..78223f7dff4d 100755 --- a/src/Illuminate/Database/Migrations/MigrationCreator.php +++ b/src/Illuminate/Database/Migrations/MigrationCreator.php @@ -74,7 +74,7 @@ public function create($name, $path, $table = null, $create = false) // Next, we will fire any hooks that are supposed to fire after a migration is // created. Once that is done we'll be ready to return the full path to the // migration file so it can be used however it's needed by the developer. - $this->firePostCreateHooks($table); + $this->firePostCreateHooks($table, $path); return $path; } @@ -184,12 +184,13 @@ protected function getPath($name, $path) * Fire the registered post create hooks. * * @param string|null $table + * @param string $path * @return void */ - protected function firePostCreateHooks($table) + protected function firePostCreateHooks($table, $path) { foreach ($this->postCreate as $callback) { - $callback($table); + $callback($table, $path); } } diff --git a/tests/Database/DatabaseMigrationCreatorTest.php b/tests/Database/DatabaseMigrationCreatorTest.php index e262443c697e..491be54c3eba 100755 --- a/tests/Database/DatabaseMigrationCreatorTest.php +++ b/tests/Database/DatabaseMigrationCreatorTest.php @@ -35,9 +35,11 @@ public function testBasicCreateMethodCallsPostCreateHooks() $table = 'baz'; $creator = $this->getCreator(); - unset($_SERVER['__migration.creator']); - $creator->afterCreate(function ($table) { - $_SERVER['__migration.creator'] = $table; + unset($_SERVER['__migration.creator.table']); + unset($_SERVER['__migration.creator.path']); + $creator->afterCreate(function ($table, $path) { + $_SERVER['__migration.creator.table'] = $table; + $_SERVER['__migration.creator.path'] = $path; }); $creator->expects($this->any())->method('getDatePrefix')->willReturn('foo'); @@ -50,9 +52,11 @@ public function testBasicCreateMethodCallsPostCreateHooks() $creator->create('create_bar', 'foo', $table); - $this->assertEquals($_SERVER['__migration.creator'], $table); + $this->assertEquals($_SERVER['__migration.creator.table'], $table); + $this->assertEquals($_SERVER['__migration.creator.path'], 'foo/foo_create_bar.php'); - unset($_SERVER['__migration.creator']); + unset($_SERVER['__migration.creator.table']); + unset($_SERVER['__migration.creator.path']); } public function testTableUpdateMigrationStoresMigrationFile() From e2dea14e0573d9b4293d2eef13b03ec038c203ea Mon Sep 17 00:00:00 2001 From: Iman Date: Sun, 15 Nov 2020 18:29:09 +0330 Subject: [PATCH 021/194] Remove extra code from event list (#35221) --- src/Illuminate/Foundation/Console/EventListCommand.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index 28e25478e0fb..275924e8c6d5 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -4,7 +4,6 @@ use Closure; use Illuminate\Console\Command; -use Illuminate\Foundation\Support\Providers\EventServiceProvider; use Illuminate\Support\Str; use ReflectionFunction; @@ -58,12 +57,6 @@ protected function getEvents() { $events = []; - foreach ($this->laravel->getProviders(EventServiceProvider::class) as $provider) { - $providerEvents = array_merge_recursive($provider->shouldDiscoverEvents() ? $provider->discoverEvents() : [], $provider->listens()); - - $events = array_merge_recursive($events, $providerEvents); - } - $events = $this->addListenersOnDispatcher($events); if ($this->filteringByEvent()) { From 7ddfd4f8732b0690d40ca1e75dec6537561c8e60 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 21 Nov 2020 14:42:15 +0000 Subject: [PATCH 022/194] Drop Guzzle <7.2 --- .github/workflows/tests.yml | 16 ---------------- composer.json | 4 ++-- src/Illuminate/Console/composer.json | 2 +- src/Illuminate/Http/composer.json | 2 +- src/Illuminate/Mail/composer.json | 2 +- 5 files changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 42fe7239751e..9062d28dbd93 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,14 +50,6 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Set Minimum Guzzle Version - uses: nick-invision/retry@v1 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update - if: matrix.php >= 8 - - name: Install dependencies uses: nick-invision/retry@v1 with: @@ -102,14 +94,6 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Set Minimum Guzzle Version - uses: nick-invision/retry@v1 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update - if: matrix.php >= 8 - - name: Install dependencies uses: nick-invision/retry@v1 with: diff --git a/composer.json b/composer.json index 033f878c7b54..7aa57c27ffa8 100644 --- a/composer.json +++ b/composer.json @@ -81,7 +81,7 @@ "aws/aws-sdk-php": "^3.155", "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", - "guzzlehttp/guzzle": "^6.5.5|^7.0.1", + "guzzlehttp/guzzle": "^7.2", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.4.2", "orchestra/testbench-core": "^7.0", @@ -132,7 +132,7 @@ "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", - "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^7.2).", "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).", "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index d954bf195656..b3fae079a42c 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -34,7 +34,7 @@ }, "suggest": { "dragonmantank/cron-expression": "Required to use scheduler (^3.0.2).", - "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^7.2).", "illuminate/bus": "Required to use the scheduled job dispatcher (^9.0).", "illuminate/container": "Required to use the scheduler (^9.0).", "illuminate/filesystem": "Required to use the generator command (^9.0).", diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 59dc22c6727d..24092e35692d 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -31,7 +31,7 @@ }, "suggest": { "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", - "guzzlehttp/guzzle": "Required to use the HTTP Client (^6.5.5|^7.0.1)." + "guzzlehttp/guzzle": "Required to use the HTTP Client (^7.2)." }, "extra": { "branch-alias": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 379cc1f113b2..5f782e13dc5c 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -38,7 +38,7 @@ }, "suggest": { "aws/aws-sdk-php": "Required to use the SES mail driver (^3.155).", - "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^7.2).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, "config": { From 167d1b73ef6bea6ee36f1b78cd87715641862c0d Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 21 Nov 2020 14:42:54 +0000 Subject: [PATCH 023/194] Revert "Drop Guzzle <7.2" This reverts commit 7ddfd4f8732b0690d40ca1e75dec6537561c8e60. --- .github/workflows/tests.yml | 16 ++++++++++++++++ composer.json | 4 ++-- src/Illuminate/Console/composer.json | 2 +- src/Illuminate/Http/composer.json | 2 +- src/Illuminate/Mail/composer.json | 2 +- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9062d28dbd93..42fe7239751e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,6 +50,14 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Set Minimum Guzzle Version + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update + if: matrix.php >= 8 + - name: Install dependencies uses: nick-invision/retry@v1 with: @@ -94,6 +102,14 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Set Minimum Guzzle Version + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update + if: matrix.php >= 8 + - name: Install dependencies uses: nick-invision/retry@v1 with: diff --git a/composer.json b/composer.json index 7aa57c27ffa8..033f878c7b54 100644 --- a/composer.json +++ b/composer.json @@ -81,7 +81,7 @@ "aws/aws-sdk-php": "^3.155", "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", - "guzzlehttp/guzzle": "^7.2", + "guzzlehttp/guzzle": "^6.5.5|^7.0.1", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.4.2", "orchestra/testbench-core": "^7.0", @@ -132,7 +132,7 @@ "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", - "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^7.2).", + "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).", "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index b3fae079a42c..d954bf195656 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -34,7 +34,7 @@ }, "suggest": { "dragonmantank/cron-expression": "Required to use scheduler (^3.0.2).", - "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^7.2).", + "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^6.5.5|^7.0.1).", "illuminate/bus": "Required to use the scheduled job dispatcher (^9.0).", "illuminate/container": "Required to use the scheduler (^9.0).", "illuminate/filesystem": "Required to use the generator command (^9.0).", diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 24092e35692d..59dc22c6727d 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -31,7 +31,7 @@ }, "suggest": { "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", - "guzzlehttp/guzzle": "Required to use the HTTP Client (^7.2)." + "guzzlehttp/guzzle": "Required to use the HTTP Client (^6.5.5|^7.0.1)." }, "extra": { "branch-alias": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 5f782e13dc5c..379cc1f113b2 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -38,7 +38,7 @@ }, "suggest": { "aws/aws-sdk-php": "Required to use the SES mail driver (^3.155).", - "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^7.2).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.5.5|^7.0.1).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, "config": { From 04ef97558030a51dc5247b444ae17d3b608719de Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 21 Nov 2020 16:17:53 +0000 Subject: [PATCH 024/194] Drop Guzzle <7.2 (#35313) --- .github/workflows/tests.yml | 16 ---------------- composer.json | 4 ++-- src/Illuminate/Console/composer.json | 2 +- src/Illuminate/Http/composer.json | 2 +- src/Illuminate/Mail/composer.json | 2 +- 5 files changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 42fe7239751e..9062d28dbd93 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,14 +50,6 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Set Minimum Guzzle Version - uses: nick-invision/retry@v1 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update - if: matrix.php >= 8 - - name: Install dependencies uses: nick-invision/retry@v1 with: @@ -102,14 +94,6 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Set Minimum Guzzle Version - uses: nick-invision/retry@v1 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update - if: matrix.php >= 8 - - name: Install dependencies uses: nick-invision/retry@v1 with: diff --git a/composer.json b/composer.json index 033f878c7b54..7aa57c27ffa8 100644 --- a/composer.json +++ b/composer.json @@ -81,7 +81,7 @@ "aws/aws-sdk-php": "^3.155", "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", - "guzzlehttp/guzzle": "^6.5.5|^7.0.1", + "guzzlehttp/guzzle": "^7.2", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.4.2", "orchestra/testbench-core": "^7.0", @@ -132,7 +132,7 @@ "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", - "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^7.2).", "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).", "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index d954bf195656..b3fae079a42c 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -34,7 +34,7 @@ }, "suggest": { "dragonmantank/cron-expression": "Required to use scheduler (^3.0.2).", - "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^7.2).", "illuminate/bus": "Required to use the scheduled job dispatcher (^9.0).", "illuminate/container": "Required to use the scheduler (^9.0).", "illuminate/filesystem": "Required to use the generator command (^9.0).", diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 59dc22c6727d..24092e35692d 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -31,7 +31,7 @@ }, "suggest": { "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", - "guzzlehttp/guzzle": "Required to use the HTTP Client (^6.5.5|^7.0.1)." + "guzzlehttp/guzzle": "Required to use the HTTP Client (^7.2)." }, "extra": { "branch-alias": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 379cc1f113b2..5f782e13dc5c 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -38,7 +38,7 @@ }, "suggest": { "aws/aws-sdk-php": "Required to use the SES mail driver (^3.155).", - "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.5.5|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^7.2).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, "config": { From ecc22874e75cece7a4a5293219971d58c62e904e Mon Sep 17 00:00:00 2001 From: Jeremy Bloomstrom Date: Tue, 24 Nov 2020 05:25:19 -0900 Subject: [PATCH 025/194] Remove typehint on InteractsWithTime::travelTo for parity with Carbon::setTestNow (#35338) --- .../Foundation/Testing/Concerns/InteractsWithTime.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php index 184a2441ce86..de0cd40c99e5 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Testing\Concerns; -use DateTimeInterface; use Illuminate\Foundation\Testing\Wormhole; use Illuminate\Support\Carbon; @@ -22,11 +21,11 @@ public function travel($value) /** * Travel to another time. * - * @param \DateTimeInterface $date + * @param \DateTimeInterface|Closure|Carbon|string|false|null $date * @param callable|null $callback * @return mixed */ - public function travelTo(DateTimeInterface $date, $callback = null) + public function travelTo($date, $callback = null) { Carbon::setTestNow($date); From bb8ddebc379cee91c20d9e34bd5554f579090ff6 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 24 Nov 2020 15:51:51 +0100 Subject: [PATCH 026/194] [9.x] Fix type hints (#35344) * Update InteractsWithTime.php * Update InteractsWithTime.php --- .../Foundation/Testing/Concerns/InteractsWithTime.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php index de0cd40c99e5..bacbce882168 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php @@ -21,7 +21,7 @@ public function travel($value) /** * Travel to another time. * - * @param \DateTimeInterface|Closure|Carbon|string|false|null $date + * @param \DateTimeInterface|\Closure|\Illuminate\Support\Carbon|string|bool|null $date * @param callable|null $callback * @return mixed */ From ed09095d841f33e08f89935c0054f14e2bcc54d7 Mon Sep 17 00:00:00 2001 From: James Freeman Date: Thu, 26 Nov 2020 08:30:30 +0000 Subject: [PATCH 027/194] Added make scope command --- .../Foundation/Console/ScopeMakeCommand.php | 72 +++++++++++++++++++ .../Foundation/Console/StubPublishCommand.php | 1 + .../Foundation/Console/stubs/scope.stub | 23 ++++++ .../Providers/ArtisanServiceProvider.php | 14 ++++ 4 files changed, 110 insertions(+) create mode 100644 src/Illuminate/Foundation/Console/ScopeMakeCommand.php create mode 100644 src/Illuminate/Foundation/Console/stubs/scope.stub diff --git a/src/Illuminate/Foundation/Console/ScopeMakeCommand.php b/src/Illuminate/Foundation/Console/ScopeMakeCommand.php new file mode 100644 index 000000000000..a6de58063688 --- /dev/null +++ b/src/Illuminate/Foundation/Console/ScopeMakeCommand.php @@ -0,0 +1,72 @@ +resolveStubPath('/stubs/scope.stub'); + } + + /** + * Resolve the fully-qualified path to the stub. + * + * @param string $stub + * @return string + */ + protected function resolveStubPath($stub) + { + return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) + ? $customPath + : __DIR__.$stub; + } + + /** + * Get the default namespace for the class. + * + * @param string $rootNamespace + * @return string + */ + protected function getDefaultNamespace($rootNamespace) + { + return $rootNamespace.'\Scopes'; + } +} diff --git a/src/Illuminate/Foundation/Console/StubPublishCommand.php b/src/Illuminate/Foundation/Console/StubPublishCommand.php index 4db6ca9dd2e1..ed45c48577d6 100644 --- a/src/Illuminate/Foundation/Console/StubPublishCommand.php +++ b/src/Illuminate/Foundation/Console/StubPublishCommand.php @@ -63,6 +63,7 @@ public function handle() realpath(__DIR__.'/../../Foundation/Console/stubs/policy.plain.stub') => $stubsPath.'/policy.plain.stub', realpath(__DIR__.'/../../Foundation/Console/stubs/policy.stub') => $stubsPath.'/policy.stub', realpath(__DIR__.'/../../Foundation/Console/stubs/rule.stub') => $stubsPath.'/rule.stub', + realpath(__DIR__.'/../../Foundation/Console/stubs/scope.stub') => $stubsPath.'/scope.stub', realpath(__DIR__.'/../../Routing/Console/stubs/controller.api.stub') => $stubsPath.'/controller.api.stub', realpath(__DIR__.'/../../Routing/Console/stubs/controller.invokable.stub') => $stubsPath.'/controller.invokable.stub', realpath(__DIR__.'/../../Routing/Console/stubs/controller.model.api.stub') => $stubsPath.'/controller.model.api.stub', diff --git a/src/Illuminate/Foundation/Console/stubs/scope.stub b/src/Illuminate/Foundation/Console/stubs/scope.stub new file mode 100644 index 000000000000..1e12c1976755 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/scope.stub @@ -0,0 +1,23 @@ + RequestMakeCommand::class, 'ResourceMake' => ResourceMakeCommand::class, 'RuleMake' => RuleMakeCommand::class, + 'ScopeMake' => ScopeMakeCommand::class, 'SeederMake' => SeederMakeCommand::class, 'SessionTable' => SessionTableCommand::class, 'Serve' => ServeCommand::class, @@ -776,6 +778,18 @@ protected function registerRuleMakeCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerScopeMakeCommand() + { + $this->app->singleton(ScopeMakeCommand::class, function ($app) { + return new ScopeMakeCommand($app['files']); + }); + } + /** * Register the command. * From 1e317418dd4568f54286291c3e88b3396e98d42d Mon Sep 17 00:00:00 2001 From: James Freeman Date: Thu, 26 Nov 2020 14:37:32 +0000 Subject: [PATCH 028/194] Fixing publishing command --- src/Illuminate/Foundation/Console/stubs/scope.stub | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/scope.stub b/src/Illuminate/Foundation/Console/stubs/scope.stub index 1e12c1976755..b7dc351dacce 100644 --- a/src/Illuminate/Foundation/Console/stubs/scope.stub +++ b/src/Illuminate/Foundation/Console/stubs/scope.stub @@ -1,12 +1,12 @@ Date: Fri, 27 Nov 2020 09:43:34 -0600 Subject: [PATCH 029/194] formatting --- src/Illuminate/Foundation/Console/ScopeMakeCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/ScopeMakeCommand.php b/src/Illuminate/Foundation/Console/ScopeMakeCommand.php index a6de58063688..ec3a03d7468f 100644 --- a/src/Illuminate/Foundation/Console/ScopeMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ScopeMakeCommand.php @@ -67,6 +67,6 @@ protected function resolveStubPath($stub) */ protected function getDefaultNamespace($rootNamespace) { - return $rootNamespace.'\Scopes'; + return is_dir(app_path('Models')) ? $rootNamespace.'\\Models\\Scopes' : $rootNamespace.'\Scopes'; } } From 609516125647e980136e4407042460b1ecf527f3 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 30 Nov 2020 17:23:02 +0100 Subject: [PATCH 030/194] [9.x] Flysystem v2 (#33612) * Flysystem v2 * Dynamic separator for Windows * Update namespace FTP adapter * Bump minimum alpha * Remove ^2.0 constraint from ftp driver * Update composer.json * Update composer.json --- composer.json | 12 +- .../Filesystem/FileExistsException.php | 10 - .../Contracts/Filesystem/Filesystem.php | 9 +- src/Illuminate/Filesystem/AwsS3V3Adapter.php | 75 ++++ src/Illuminate/Filesystem/Cache.php | 71 ---- .../Filesystem/FilesystemAdapter.php | 328 +++++++++--------- .../Filesystem/FilesystemManager.php | 120 +++---- src/Illuminate/Filesystem/composer.json | 8 +- tests/Filesystem/FilesystemAdapterTest.php | 120 ++++--- tests/Filesystem/FilesystemTest.php | 23 -- 10 files changed, 373 insertions(+), 403 deletions(-) delete mode 100644 src/Illuminate/Contracts/Filesystem/FileExistsException.php create mode 100644 src/Illuminate/Filesystem/AwsS3V3Adapter.php delete mode 100644 src/Illuminate/Filesystem/Cache.php diff --git a/composer.json b/composer.json index 7aa57c27ffa8..2f5533c97fe0 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "dragonmantank/cron-expression": "^3.0.2", "egulias/email-validator": "^2.1.10", "league/commonmark": "^1.3", - "league/flysystem": "^1.1", + "league/flysystem": "^2.0", "monolog/monolog": "^2.0", "nesbot/carbon": "^2.31", "opis/closure": "^3.6", @@ -82,7 +82,9 @@ "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^7.2", - "league/flysystem-cached-adapter": "^1.0", + "league/flysystem-aws-s3-v3": "^2.0", + "league/flysystem-ftp": "^2.0", + "league/flysystem-sftp": "^2.0", "mockery/mockery": "^1.4.2", "orchestra/testbench-core": "^7.0", "pda/pheanstalk": "^4.0", @@ -134,9 +136,9 @@ "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^7.2).", "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).", - "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", - "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^2.0).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^2.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^2.0).", "mockery/mockery": "Required to use mocking (^1.4.2).", "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", diff --git a/src/Illuminate/Contracts/Filesystem/FileExistsException.php b/src/Illuminate/Contracts/Filesystem/FileExistsException.php deleted file mode 100644 index 9027892faa00..000000000000 --- a/src/Illuminate/Contracts/Filesystem/FileExistsException.php +++ /dev/null @@ -1,10 +0,0 @@ -client = $client; + } + + /** + * Get the URL for the file at the given path. + * + * @param string $path + * @return string + * + * @throws \RuntimeException + */ + public function url($path) + { + // If an explicit base URL has been set on the disk configuration then we will use + // it as the base URL instead of the default path. This allows the developer to + // have full control over the base path for this filesystem's generated URLs. + if (isset($this->config['url'])) { + return $this->concatPathToUrl($this->config['url'], $this->prefixer->prefixPath($path)); + } + + return $this->client->getObjectUrl( + $this->config['bucket'], $this->prefixer->prefixPath($path) + ); + } + + /** + * Get a temporary URL for the file at the given path. + * + * @param string $path + * @param \DateTimeInterface $expiration + * @param array $options + * @return string + */ + public function temporaryUrl($path, $expiration, array $options = []) + { + $command = $this->client->getCommand('GetObject', array_merge([ + 'Bucket' => $this->config['bucket'], + 'Key' => $this->prefixer->prefixPath($path), + ], $options)); + + return (string) $this->client->createPresignedRequest( + $command, $expiration + )->getUri(); + } +} diff --git a/src/Illuminate/Filesystem/Cache.php b/src/Illuminate/Filesystem/Cache.php deleted file mode 100644 index 8ae2486dabf8..000000000000 --- a/src/Illuminate/Filesystem/Cache.php +++ /dev/null @@ -1,71 +0,0 @@ -key = $key; - $this->expire = $expire; - $this->repository = $repository; - } - - /** - * Load the cache. - * - * @return void - */ - public function load() - { - $contents = $this->repository->get($this->key); - - if (! is_null($contents)) { - $this->setFromStorage($contents); - } - } - - /** - * Persist the cache. - * - * @return void - */ - public function save() - { - $contents = $this->getForStorage(); - - $this->repository->put($this->key, $contents, $this->expire); - } -} diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 1c33b9892676..29a7badbb7b4 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -3,49 +3,81 @@ namespace Illuminate\Filesystem; use Illuminate\Contracts\Filesystem\Cloud as CloudFilesystemContract; -use Illuminate\Contracts\Filesystem\FileExistsException as ContractFileExistsException; -use Illuminate\Contracts\Filesystem\FileNotFoundException as ContractFileNotFoundException; use Illuminate\Contracts\Filesystem\Filesystem as FilesystemContract; use Illuminate\Http\File; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; -use Illuminate\Support\Collection; use Illuminate\Support\Str; use InvalidArgumentException; -use League\Flysystem\Adapter\Ftp; -use League\Flysystem\Adapter\Local as LocalAdapter; -use League\Flysystem\AdapterInterface; -use League\Flysystem\AwsS3v3\AwsS3Adapter; -use League\Flysystem\Cached\CachedAdapter; -use League\Flysystem\FileExistsException; -use League\Flysystem\FileNotFoundException; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemAdapter as FlysystemAdapter; +use League\Flysystem\FilesystemOperator; +use League\Flysystem\Ftp\FtpAdapter; +use League\Flysystem\Local\LocalFilesystemAdapter as LocalAdapter; +use League\Flysystem\PathPrefixer; +use League\Flysystem\StorageAttributes; +use League\Flysystem\UnableToCopyFile; +use League\Flysystem\UnableToCreateDirectory; +use League\Flysystem\UnableToDeleteDirectory; +use League\Flysystem\UnableToDeleteFile; +use League\Flysystem\UnableToMoveFile; +use League\Flysystem\UnableToReadFile; +use League\Flysystem\UnableToSetVisibility; +use League\Flysystem\UnableToWriteFile; +use League\Flysystem\Visibility; use PHPUnit\Framework\Assert as PHPUnit; use Psr\Http\Message\StreamInterface; use RuntimeException; use Symfony\Component\HttpFoundation\StreamedResponse; /** - * @mixin \League\Flysystem\FilesystemInterface + * @mixin \League\Flysystem\FilesystemOperator */ class FilesystemAdapter implements CloudFilesystemContract { /** * The Flysystem filesystem implementation. * - * @var \League\Flysystem\FilesystemInterface + * @var \League\Flysystem\FilesystemOperator */ protected $driver; + /** + * The Flysystem adapter implementation. + * + * @var \League\Flysystem\FilesystemAdapter + */ + protected $adapter; + + /** + * The filesystem configuration. + * + * @var array + */ + protected $config; + + /** + * The Flysystem PathPrefixer instance. + * + * @var \League\Flysystem\PathPrefixer + */ + protected $prefixer; + /** * Create a new filesystem adapter instance. * - * @param \League\Flysystem\FilesystemInterface $driver + * @param \League\Flysystem\FilesystemOperator $driver + * @param \League\Flysystem\FilesystemAdapter $adapter + * @param array $config * @return void */ - public function __construct(FilesystemInterface $driver) + public function __construct(FilesystemOperator $driver, FlysystemAdapter $adapter, array $config = []) { $this->driver = $driver; + $this->adapter = $adapter; + $this->config = $config; + $this->prefixer = new PathPrefixer( + $config['root'] ?? '', $config['directory_separator'] ?? DIRECTORY_SEPARATOR + ); } /** @@ -105,7 +137,7 @@ public function assertMissing($path) */ public function exists($path) { - return $this->driver->has($path); + return $this->driver->fileExists($path); } /** @@ -127,29 +159,21 @@ public function missing($path) */ public function path($path) { - $adapter = $this->driver->getAdapter(); - - if ($adapter instanceof CachedAdapter) { - $adapter = $adapter->getAdapter(); - } - - return $adapter->getPathPrefix().$path; + return $this->prefixer->prefixPath($path); } /** * Get the contents of a file. * * @param string $path - * @return string - * - * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @return string|null */ public function get($path) { try { return $this->driver->read($path); - } catch (FileNotFoundException $e) { - throw new ContractFileNotFoundException($e->getMessage(), $e->getCode(), $e); + } catch (UnableToReadFile $e) { + // } } @@ -233,13 +257,21 @@ public function put($path, $contents, $options = []) return $this->putFile($path, $contents, $options); } - if ($contents instanceof StreamInterface) { - return $this->driver->putStream($path, $contents->detach(), $options); + try { + if ($contents instanceof StreamInterface) { + $this->driver->writeStream($path, $contents->detach(), $options); + + return true; + } + + is_resource($contents) + ? $this->driver->writeStream($path, $contents, $options) + : $this->driver->write($path, $contents, $options); + } catch (UnableToWriteFile $e) { + return false; } - return is_resource($contents) - ? $this->driver->putStream($path, $contents, $options) - : $this->driver->put($path, $contents, $options); + return true; } /** @@ -292,7 +324,7 @@ public function putFileAs($path, $file, $name, $options = []) */ public function getVisibility($path) { - if ($this->driver->getVisibility($path) == AdapterInterface::VISIBILITY_PUBLIC) { + if ($this->driver->visibility($path) == Visibility::PUBLIC) { return FilesystemContract::VISIBILITY_PUBLIC; } @@ -308,7 +340,13 @@ public function getVisibility($path) */ public function setVisibility($path, $visibility) { - return $this->driver->setVisibility($path, $this->parseVisibility($visibility)); + try { + $this->driver->setVisibility($path, $this->parseVisibility($visibility)); + } catch (UnableToSetVisibility $e) { + return false; + } + + return true; } /** @@ -359,10 +397,8 @@ public function delete($paths) foreach ($paths as $path) { try { - if (! $this->driver->delete($path)) { - $success = false; - } - } catch (FileNotFoundException $e) { + $this->driver->delete($path); + } catch (UnableToDeleteFile $e) { $success = false; } } @@ -379,7 +415,13 @@ public function delete($paths) */ public function copy($from, $to) { - return $this->driver->copy($from, $to); + try { + $this->driver->copy($from, $to); + } catch (UnableToCopyFile $e) { + return false; + } + + return true; } /** @@ -391,7 +433,13 @@ public function copy($from, $to) */ public function move($from, $to) { - return $this->driver->rename($from, $to); + try { + $this->driver->move($from, $to); + } catch (UnableToMoveFile $e) { + return false; + } + + return true; } /** @@ -402,7 +450,7 @@ public function move($from, $to) */ public function size($path) { - return $this->driver->getSize($path); + return $this->driver->fileSize($path); } /** @@ -413,7 +461,7 @@ public function size($path) */ public function mimeType($path) { - return $this->driver->getMimetype($path); + return $this->driver->mimeType($path); } /** @@ -424,38 +472,7 @@ public function mimeType($path) */ public function lastModified($path) { - return $this->driver->getTimestamp($path); - } - - /** - * Get the URL for the file at the given path. - * - * @param string $path - * @return string - * - * @throws \RuntimeException - */ - public function url($path) - { - $adapter = $this->driver->getAdapter(); - - if ($adapter instanceof CachedAdapter) { - $adapter = $adapter->getAdapter(); - } - - if (method_exists($adapter, 'getUrl')) { - return $adapter->getUrl($path); - } elseif (method_exists($this->driver, 'getUrl')) { - return $this->driver->getUrl($path); - } elseif ($adapter instanceof AwsS3Adapter) { - return $this->getAwsUrl($adapter, $path); - } elseif ($adapter instanceof Ftp) { - return $this->getFtpUrl($path); - } elseif ($adapter instanceof LocalAdapter) { - return $this->getLocalUrl($path); - } else { - throw new RuntimeException('This driver does not support retrieving URLs.'); - } + return $this->driver->lastModified($path); } /** @@ -464,9 +481,9 @@ public function url($path) public function readStream($path) { try { - return $this->driver->readStream($path) ?: null; - } catch (FileNotFoundException $e) { - throw new ContractFileNotFoundException($e->getMessage(), $e->getCode(), $e); + return $this->driver->readStream($path); + } catch (UnableToReadFile $e) { + // } } @@ -476,31 +493,37 @@ public function readStream($path) public function writeStream($path, $resource, array $options = []) { try { - return $this->driver->writeStream($path, $resource, $options); - } catch (FileExistsException $e) { - throw new ContractFileExistsException($e->getMessage(), $e->getCode(), $e); + $this->driver->writeStream($path, $resource, $options); + } catch (UnableToWriteFile $e) { + return false; } + + return true; } /** * Get the URL for the file at the given path. * - * @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter * @param string $path * @return string + * + * @throws \RuntimeException */ - protected function getAwsUrl($adapter, $path) + public function url($path) { - // If an explicit base URL has been set on the disk configuration then we will use - // it as the base URL instead of the default path. This allows the developer to - // have full control over the base path for this filesystem's generated URLs. - if (! is_null($url = $this->driver->getConfig()->get('url'))) { - return $this->concatPathToUrl($url, $adapter->getPathPrefix().$path); - } + $adapter = $this->adapter; - return $adapter->getClient()->getObjectUrl( - $adapter->getBucket(), $adapter->getPathPrefix().$path - ); + if (method_exists($adapter, 'getUrl')) { + return $adapter->getUrl($path); + } elseif (method_exists($this->driver, 'getUrl')) { + return $this->driver->getUrl($path); + } elseif ($adapter instanceof FtpAdapter) { + return $this->getFtpUrl($path); + } elseif ($adapter instanceof LocalAdapter) { + return $this->getLocalUrl($path); + } else { + throw new RuntimeException('This driver does not support retrieving URLs.'); + } } /** @@ -511,10 +534,8 @@ protected function getAwsUrl($adapter, $path) */ protected function getFtpUrl($path) { - $config = $this->driver->getConfig(); - - return $config->has('url') - ? $this->concatPathToUrl($config->get('url'), $path) + return isset($this->config['url']) + ? $this->concatPathToUrl($this->config['url'], $path) : $path; } @@ -526,13 +547,11 @@ protected function getFtpUrl($path) */ protected function getLocalUrl($path) { - $config = $this->driver->getConfig(); - // If an explicit base URL has been set on the disk configuration then we will use // it as the base URL instead of the default path. This allows the developer to // have full control over the base path for this filesystem's generated URLs. - if ($config->has('url')) { - return $this->concatPathToUrl($config->get('url'), $path); + if (isset($this->config['url'])) { + return $this->concatPathToUrl($this->config['url'], $path); } $path = '/storage/'.$path; @@ -559,42 +578,11 @@ protected function getLocalUrl($path) */ public function temporaryUrl($path, $expiration, array $options = []) { - $adapter = $this->driver->getAdapter(); - - if ($adapter instanceof CachedAdapter) { - $adapter = $adapter->getAdapter(); - } - - if (method_exists($adapter, 'getTemporaryUrl')) { - return $adapter->getTemporaryUrl($path, $expiration, $options); - } elseif ($adapter instanceof AwsS3Adapter) { - return $this->getAwsTemporaryUrl($adapter, $path, $expiration, $options); - } else { + if (! method_exists($this->adapter, 'getTemporaryUrl')) { throw new RuntimeException('This driver does not support creating temporary URLs.'); } - } - /** - * Get a temporary URL for the file at the given path. - * - * @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter - * @param string $path - * @param \DateTimeInterface $expiration - * @param array $options - * @return string - */ - public function getAwsTemporaryUrl($adapter, $path, $expiration, $options) - { - $client = $adapter->getClient(); - - $command = $client->getCommand('GetObject', array_merge([ - 'Bucket' => $adapter->getBucket(), - 'Key' => $adapter->getPathPrefix().$path, - ], $options)); - - return (string) $client->createPresignedRequest( - $command, $expiration - )->getUri(); + return $this->adapter->getTemporaryUrl($path, $expiration, $options); } /** @@ -618,9 +606,14 @@ protected function concatPathToUrl($url, $path) */ public function files($directory = null, $recursive = false) { - $contents = $this->driver->listContents($directory, $recursive); - - return $this->filterContentsByType($contents, 'file'); + return $this->driver->listContents($directory, $recursive) + ->filter(function (StorageAttributes $attributes) { + return $attributes->isFile(); + }) + ->map(function (StorageAttributes $attributes) { + return $attributes->path(); + }) + ->toArray(); } /** @@ -643,9 +636,14 @@ public function allFiles($directory = null) */ public function directories($directory = null, $recursive = false) { - $contents = $this->driver->listContents($directory, $recursive); - - return $this->filterContentsByType($contents, 'dir'); + return $this->driver->listContents($directory, $recursive) + ->filter(function (StorageAttributes $attributes) { + return $attributes->isDir(); + }) + ->map(function (StorageAttributes $attributes) { + return $attributes->path(); + }) + ->toArray(); } /** @@ -667,7 +665,13 @@ public function allDirectories($directory = null) */ public function makeDirectory($path) { - return $this->driver->createDir($path); + try { + $this->driver->createDirectory($path); + } catch (UnableToCreateDirectory $e) { + return false; + } + + return true; } /** @@ -678,47 +682,43 @@ public function makeDirectory($path) */ public function deleteDirectory($directory) { - return $this->driver->deleteDir($directory); + try { + $this->driver->deleteDirectory($directory); + } catch (UnableToDeleteDirectory $e) { + return false; + } + + return true; } /** - * Flush the Flysystem cache. + * Get the Flysystem driver. * - * @return void + * @return \League\Flysystem\FilesystemOperator */ - public function flushCache() + public function getDriver() { - $adapter = $this->driver->getAdapter(); - - if ($adapter instanceof CachedAdapter) { - $adapter->getCache()->flush(); - } + return $this->driver; } /** - * Get the Flysystem driver. + * Get the Flysystem adapter. * - * @return \League\Flysystem\FilesystemInterface + * @return \League\Flysystem\FilesystemAdapter */ - public function getDriver() + public function getAdapter() { - return $this->driver; + return $this->adapter; } /** - * Filter directory contents by type. + * Get the configuration values. * - * @param array $contents - * @param string $type * @return array */ - protected function filterContentsByType($contents, $type) + public function getConfig() { - return Collection::make($contents) - ->where('type', $type) - ->pluck('path') - ->values() - ->all(); + return $this->config; } /** @@ -737,9 +737,9 @@ protected function parseVisibility($visibility) switch ($visibility) { case FilesystemContract::VISIBILITY_PUBLIC: - return AdapterInterface::VISIBILITY_PUBLIC; + return Visibility::PUBLIC; case FilesystemContract::VISIBILITY_PRIVATE: - return AdapterInterface::VISIBILITY_PRIVATE; + return Visibility::PRIVATE; } throw new InvalidArgumentException("Unknown visibility: {$visibility}."); diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index 5575439418fc..14c953fb892d 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -7,15 +7,17 @@ use Illuminate\Contracts\Filesystem\Factory as FactoryContract; use Illuminate\Support\Arr; use InvalidArgumentException; -use League\Flysystem\Adapter\Ftp as FtpAdapter; -use League\Flysystem\Adapter\Local as LocalAdapter; -use League\Flysystem\AdapterInterface; -use League\Flysystem\AwsS3v3\AwsS3Adapter as S3Adapter; -use League\Flysystem\Cached\CachedAdapter; -use League\Flysystem\Cached\Storage\Memory as MemoryStore; +use League\Flysystem\AwsS3V3\AwsS3V3Adapter as S3Adapter; +use League\Flysystem\AwsS3V3\PortableVisibilityConverter as AwsS3PortableVisibilityConverter; use League\Flysystem\Filesystem as Flysystem; -use League\Flysystem\FilesystemInterface; -use League\Flysystem\Sftp\SftpAdapter; +use League\Flysystem\FilesystemAdapter as FlysystemAdapter; +use League\Flysystem\Ftp\FtpAdapter as FtpAdapter; +use League\Flysystem\Ftp\FtpConnectionOptions; +use League\Flysystem\Local\LocalFilesystemAdapter as LocalAdapter; +use League\Flysystem\PHPSecLibV2\SftpAdapter; +use League\Flysystem\PHPSecLibV2\SftpConnectionProvider; +use League\Flysystem\UnixVisibility\PortableVisibilityConverter; +use League\Flysystem\Visibility; /** * @mixin \Illuminate\Contracts\Filesystem\Filesystem @@ -140,13 +142,7 @@ protected function resolve($name) */ protected function callCustomCreator(array $config) { - $driver = $this->customCreators[$config['driver']]($this->app, $config); - - if ($driver instanceof FilesystemInterface) { - return $this->adapt($driver); - } - - return $driver; + return $this->customCreators[$config['driver']]($this->app, $config); } /** @@ -157,15 +153,19 @@ protected function callCustomCreator(array $config) */ public function createLocalDriver(array $config) { - $permissions = $config['permissions'] ?? []; + $visibility = PortableVisibilityConverter::fromArray( + $config['permissions'] ?? [] + ); $links = ($config['links'] ?? null) === 'skip' ? LocalAdapter::SKIP_LINKS : LocalAdapter::DISALLOW_LINKS; - return $this->adapt($this->createFlysystem(new LocalAdapter( - $config['root'], $config['lock'] ?? LOCK_EX, $links, $permissions - ), $config)); + $adapter = new LocalAdapter( + $config['root'], $visibility, $config['lock'] ?? LOCK_EX, $links + ); + + return new FilesystemAdapter($this->createFlysystem($adapter, $config), $adapter, $config); } /** @@ -176,9 +176,9 @@ public function createLocalDriver(array $config) */ public function createFtpDriver(array $config) { - return $this->adapt($this->createFlysystem( - new FtpAdapter($config), $config - )); + $adapter = new FtpAdapter(FtpConnectionOptions::fromArray($config)); + + return new FilesystemAdapter($this->createFlysystem($adapter, $config), $adapter, $config); } /** @@ -189,9 +189,17 @@ public function createFtpDriver(array $config) */ public function createSftpDriver(array $config) { - return $this->adapt($this->createFlysystem( - new SftpAdapter($config), $config - )); + $provider = SftpConnectionProvider::fromArray($config); + + $root = $config['root'] ?? '/'; + + $visibility = PortableVisibilityConverter::fromArray( + $config['permissions'] ?? [] + ); + + $adapter = new SftpAdapter($provider, $root, $visibility); + + return new FilesystemAdapter($this->createFlysystem($adapter, $config), $adapter, $config); } /** @@ -206,13 +214,19 @@ public function createS3Driver(array $config) $root = $s3Config['root'] ?? null; - $options = $config['options'] ?? []; + $visibility = new AwsS3PortableVisibilityConverter( + $config['visibility'] ?? Visibility::PUBLIC + ); + + $streamReads = $s3Config['stream_reads'] ?? false; + + $client = new S3Client($s3Config); - $streamReads = $config['stream_reads'] ?? false; + $adapter = new S3Adapter($client, $s3Config['bucket'], $root, $visibility, null, [], $streamReads); - return $this->adapt($this->createFlysystem( - new S3Adapter(new S3Client($s3Config), $s3Config['bucket'], $root, $options, $streamReads), $config - )); + return new AwsS3V3Adapter( + $this->createFlysystem($adapter, $config), $adapter, $s3Config, $client + ); } /** @@ -235,53 +249,15 @@ protected function formatS3Config(array $config) /** * Create a Flysystem instance with the given adapter. * - * @param \League\Flysystem\AdapterInterface $adapter + * @param \League\Flysystem\FilesystemAdapter $adapter * @param array $config - * @return \League\Flysystem\FilesystemInterface + * @return \League\Flysystem\FilesystemOperator */ - protected function createFlysystem(AdapterInterface $adapter, array $config) + protected function createFlysystem(FlysystemAdapter $adapter, array $config) { - $cache = Arr::pull($config, 'cache'); - $config = Arr::only($config, ['visibility', 'disable_asserts', 'url']); - if ($cache) { - $adapter = new CachedAdapter($adapter, $this->createCacheStore($cache)); - } - - return new Flysystem($adapter, count($config) > 0 ? $config : null); - } - - /** - * Create a cache store instance. - * - * @param mixed $config - * @return \League\Flysystem\Cached\CacheInterface - * - * @throws \InvalidArgumentException - */ - protected function createCacheStore($config) - { - if ($config === true) { - return new MemoryStore; - } - - return new Cache( - $this->app['cache']->store($config['store']), - $config['prefix'] ?? 'flysystem', - $config['expire'] ?? null - ); - } - - /** - * Adapt the filesystem implementation. - * - * @param \League\Flysystem\FilesystemInterface $filesystem - * @return \Illuminate\Contracts\Filesystem\Filesystem - */ - protected function adapt(FilesystemInterface $filesystem) - { - return new FilesystemAdapter($filesystem); + return new Flysystem($adapter, $config); } /** diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index b3655d43fe02..7d10b4aeb439 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -34,10 +34,10 @@ "suggest": { "ext-ftp": "Required to use the Flysystem FTP driver.", "illuminate/http": "Required for handling uploaded files (^7.0).", - "league/flysystem": "Required to use the Flysystem local and FTP drivers (^1.1).", - "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).", + "league/flysystem": "Required to use the Flysystem local driver (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^2.0).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^2.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^2.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "symfony/filesystem": "Required to enable support for relative symbolic links (^5.2).", "symfony/mime": "Required to enable support for guessing extensions (^5.2)." diff --git a/tests/Filesystem/FilesystemAdapterTest.php b/tests/Filesystem/FilesystemAdapterTest.php index 8e2cac163ce0..ed35ff6bdb52 100644 --- a/tests/Filesystem/FilesystemAdapterTest.php +++ b/tests/Filesystem/FilesystemAdapterTest.php @@ -3,14 +3,15 @@ namespace Illuminate\Tests\Filesystem; use GuzzleHttp\Psr7\Stream; -use Illuminate\Contracts\Filesystem\FileExistsException; -use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Filesystem\FilesystemAdapter; +use Illuminate\Filesystem\FilesystemManager; +use Illuminate\Foundation\Application; use Illuminate\Http\UploadedFile; use Illuminate\Testing\Assert; use InvalidArgumentException; -use League\Flysystem\Adapter\Local; use League\Flysystem\Filesystem; +use League\Flysystem\Ftp\FtpAdapter; +use League\Flysystem\Local\LocalFilesystemAdapter; use Mockery as m; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -19,24 +20,31 @@ class FilesystemAdapterTest extends TestCase { private $tempDir; private $filesystem; + private $adapter; protected function setUp(): void { $this->tempDir = __DIR__.'/tmp'; - $this->filesystem = new Filesystem(new Local($this->tempDir)); + $this->filesystem = new Filesystem( + $this->adapter = new LocalFilesystemAdapter($this->tempDir) + ); } protected function tearDown(): void { - $filesystem = new Filesystem(new Local(dirname($this->tempDir))); - $filesystem->deleteDir(basename($this->tempDir)); + $filesystem = new Filesystem( + $this->adapter = new LocalFilesystemAdapter(dirname($this->tempDir)) + ); + $filesystem->deleteDirectory(basename($this->tempDir)); m::close(); + + unset($this->tempDir, $this->filesystem, $this->adapter); } public function testResponse() { $this->filesystem->write('file.txt', 'Hello World'); - $files = new FilesystemAdapter($this->filesystem); + $files = new FilesystemAdapter($this->filesystem, $this->adapter); $response = $files->response('file.txt'); ob_start(); @@ -51,7 +59,7 @@ public function testResponse() public function testDownload() { $this->filesystem->write('file.txt', 'Hello World'); - $files = new FilesystemAdapter($this->filesystem); + $files = new FilesystemAdapter($this->filesystem, $this->adapter); $response = $files->download('file.txt', 'hello.txt'); $this->assertInstanceOf(StreamedResponse::class, $response); $this->assertSame('attachment; filename=hello.txt', $response->headers->get('content-disposition')); @@ -60,7 +68,7 @@ public function testDownload() public function testDownloadNonAsciiFilename() { $this->filesystem->write('file.txt', 'Hello World'); - $files = new FilesystemAdapter($this->filesystem); + $files = new FilesystemAdapter($this->filesystem, $this->adapter); $response = $files->download('file.txt', 'пиздюк.txt'); $this->assertInstanceOf(StreamedResponse::class, $response); $this->assertSame("attachment; filename=pizdyuk.txt; filename*=utf-8''%D0%BF%D0%B8%D0%B7%D0%B4%D1%8E%D0%BA.txt", $response->headers->get('content-disposition')); @@ -69,7 +77,7 @@ public function testDownloadNonAsciiFilename() public function testDownloadNonAsciiEmptyFilename() { $this->filesystem->write('пиздюк.txt', 'Hello World'); - $files = new FilesystemAdapter($this->filesystem); + $files = new FilesystemAdapter($this->filesystem, $this->adapter); $response = $files->download('пиздюк.txt'); $this->assertInstanceOf(StreamedResponse::class, $response); $this->assertSame('attachment; filename=pizdyuk.txt; filename*=utf-8\'\'%D0%BF%D0%B8%D0%B7%D0%B4%D1%8E%D0%BA.txt', $response->headers->get('content-disposition')); @@ -78,7 +86,7 @@ public function testDownloadNonAsciiEmptyFilename() public function testDownloadPercentInFilename() { $this->filesystem->write('Hello%World.txt', 'Hello World'); - $files = new FilesystemAdapter($this->filesystem); + $files = new FilesystemAdapter($this->filesystem, $this->adapter); $response = $files->download('Hello%World.txt', 'Hello%World.txt'); $this->assertInstanceOf(StreamedResponse::class, $response); $this->assertSame('attachment; filename=HelloWorld.txt; filename*=utf-8\'\'Hello%25World.txt', $response->headers->get('content-disposition')); @@ -87,40 +95,41 @@ public function testDownloadPercentInFilename() public function testExists() { $this->filesystem->write('file.txt', 'Hello World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $this->assertTrue($filesystemAdapter->exists('file.txt')); } public function testMissing() { - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $this->assertTrue($filesystemAdapter->missing('file.txt')); } public function testPath() { $this->filesystem->write('file.txt', 'Hello World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter, [ + 'root' => $this->tempDir.DIRECTORY_SEPARATOR, + ]); $this->assertEquals($this->tempDir.DIRECTORY_SEPARATOR.'file.txt', $filesystemAdapter->path('file.txt')); } public function testGet() { $this->filesystem->write('file.txt', 'Hello World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $this->assertSame('Hello World', $filesystemAdapter->get('file.txt')); } public function testGetFileNotFound() { - $filesystemAdapter = new FilesystemAdapter($this->filesystem); - $this->expectException(FileNotFoundException::class); - $filesystemAdapter->get('file.txt'); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); + $this->assertNull($filesystemAdapter->get('file.txt')); } public function testPut() { - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $filesystemAdapter->put('file.txt', 'Something inside'); $this->assertStringEqualsFile($this->tempDir.'/file.txt', 'Something inside'); } @@ -128,7 +137,7 @@ public function testPut() public function testPrepend() { file_put_contents($this->tempDir.'/file.txt', 'World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $filesystemAdapter->prepend('file.txt', 'Hello '); $this->assertStringEqualsFile($this->tempDir.'/file.txt', 'Hello '.PHP_EOL.'World'); } @@ -136,7 +145,7 @@ public function testPrepend() public function testAppend() { file_put_contents($this->tempDir.'/file.txt', 'Hello '); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $filesystemAdapter->append('file.txt', 'Moon'); $this->assertStringEqualsFile($this->tempDir.'/file.txt', 'Hello '.PHP_EOL.'Moon'); } @@ -144,15 +153,15 @@ public function testAppend() public function testDelete() { file_put_contents($this->tempDir.'/file.txt', 'Hello World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $this->assertTrue($filesystemAdapter->delete('file.txt')); Assert::assertFileDoesNotExist($this->tempDir.'/file.txt'); } - public function testDeleteReturnsFalseWhenFileNotFound() + public function testDeleteReturnsTrueWhenFileNotFound() { - $filesystemAdapter = new FilesystemAdapter($this->filesystem); - $this->assertFalse($filesystemAdapter->delete('file.txt')); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); + $this->assertTrue($filesystemAdapter->delete('file.txt')); } public function testCopy() @@ -161,7 +170,7 @@ public function testCopy() mkdir($this->tempDir.'/foo'); file_put_contents($this->tempDir.'/foo/foo.txt', $data); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $filesystemAdapter->copy('/foo/foo.txt', '/foo/foo2.txt'); $this->assertFileExists($this->tempDir.'/foo/foo.txt'); @@ -177,7 +186,7 @@ public function testMove() mkdir($this->tempDir.'/foo'); file_put_contents($this->tempDir.'/foo/foo.txt', $data); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $filesystemAdapter->move('/foo/foo.txt', '/foo/foo2.txt'); Assert::assertFileDoesNotExist($this->tempDir.'/foo/foo.txt'); @@ -189,7 +198,7 @@ public function testMove() public function testStream() { $this->filesystem->write('file.txt', $original_content = 'Hello World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $readStream = $filesystemAdapter->readStream('file.txt'); $filesystemAdapter->writeStream('copy.txt', $readStream); $this->assertEquals($original_content, $filesystemAdapter->get('copy.txt')); @@ -197,51 +206,48 @@ public function testStream() public function testStreamBetweenFilesystems() { - $secondFilesystem = new Filesystem(new Local($this->tempDir.'/second')); + $secondFilesystem = new Filesystem(new LocalFilesystemAdapter($this->tempDir.'/second')); $this->filesystem->write('file.txt', $original_content = 'Hello World'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); - $secondFilesystemAdapter = new FilesystemAdapter($secondFilesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); + $secondFilesystemAdapter = new FilesystemAdapter($secondFilesystem, $this->adapter); $readStream = $filesystemAdapter->readStream('file.txt'); $secondFilesystemAdapter->writeStream('copy.txt', $readStream); $this->assertEquals($original_content, $secondFilesystemAdapter->get('copy.txt')); } - public function testStreamToExistingFileThrows() + public function testStreamToExistingFileOverwrites() { - $this->expectException(FileExistsException::class); $this->filesystem->write('file.txt', 'Hello World'); $this->filesystem->write('existing.txt', 'Dear Kate'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $readStream = $filesystemAdapter->readStream('file.txt'); $filesystemAdapter->writeStream('existing.txt', $readStream); + $this->assertSame('Hello World', $filesystemAdapter->read('existing.txt')); } - public function testReadStreamNonExistentFileThrows() + public function testReadStreamNonExistentFileReturnsNull() { - $this->expectException(FileNotFoundException::class); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); - $filesystemAdapter->readStream('nonexistent.txt'); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); + $this->assertNull($filesystemAdapter->readStream('nonexistent.txt')); } public function testStreamInvalidResourceThrows() { $this->expectException(InvalidArgumentException::class); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $filesystemAdapter->writeStream('file.txt', 'foo bar'); } public function testPutWithStreamInterface() { file_put_contents($this->tempDir.'/foo.txt', 'some-data'); - $spy = m::spy($this->filesystem); - $filesystemAdapter = new FilesystemAdapter($spy); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $stream = fopen($this->tempDir.'/foo.txt', 'r'); $guzzleStream = new Stream($stream); $filesystemAdapter->put('bar.txt', $guzzleStream); fclose($stream); - $spy->shouldHaveReceived('putStream'); $this->assertSame('some-data', $filesystemAdapter->get('bar.txt')); } @@ -249,7 +255,7 @@ public function testPutFileAs() { file_put_contents($filePath = $this->tempDir.'/foo.txt', 'uploaded file content'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $uploadedFile = new UploadedFile($filePath, 'org.txt', null, null, true); @@ -273,7 +279,7 @@ public function testPutFileAsWithAbsoluteFilePath() { file_put_contents($filePath = $this->tempDir.'/foo.txt', 'normal file content'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $storagePath = $filesystemAdapter->putFileAs('/', $filePath, 'new.txt'); @@ -284,7 +290,7 @@ public function testPutFile() { file_put_contents($filePath = $this->tempDir.'/foo.txt', 'uploaded file content'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $uploadedFile = new UploadedFile($filePath, 'org.txt', null, null, true); @@ -306,7 +312,7 @@ public function testPutFileWithAbsoluteFilePath() { file_put_contents($filePath = $this->tempDir.'/foo.txt', 'uploaded file content'); - $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter = new FilesystemAdapter($this->filesystem, $this->adapter); $storagePath = $filesystemAdapter->putFile('/', $filePath); @@ -319,4 +325,26 @@ public function testPutFileWithAbsoluteFilePath() 'uploaded file content' ); } + + /** + * @requires extension ftp + */ + public function testCreateFtpDriver() + { + $filesystem = new FilesystemManager(new Application); + + $driver = $filesystem->createFtpDriver([ + 'host' => 'ftp.example.com', + 'username' => 'admin', + 'permPublic' => 0700, + 'unsupportedParam' => true, + ]); + + $this->assertInstanceOf(FtpAdapter::class, $driver->getAdapter()); + + $config = $driver->getConfig(); + $this->assertEquals(0700, $config['permPublic']); + $this->assertSame('ftp.example.com', $config['host']); + $this->assertSame('admin', $config['username']); + } } diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index d1ff89f680ce..eb2a156687eb 100755 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -4,8 +4,6 @@ use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Filesystem\Filesystem; -use Illuminate\Filesystem\FilesystemManager; -use Illuminate\Foundation\Application; use Illuminate\Support\LazyCollection; use Illuminate\Testing\Assert; use Mockery as m; @@ -568,27 +566,6 @@ public function testAllFilesReturnsFileInfoObjects() $this->assertContainsOnlyInstancesOf(SplFileInfo::class, $files->allFiles(self::$tempDir)); } - /** - * @requires extension ftp - */ - public function testCreateFtpDriver() - { - $filesystem = new FilesystemManager(new Application); - - $driver = $filesystem->createFtpDriver([ - 'host' => 'ftp.example.com', - 'username' => 'admin', - 'permPublic' => 0700, - 'unsupportedParam' => true, - ]); - - /** @var \League\Flysystem\Adapter\Ftp $adapter */ - $adapter = $driver->getAdapter(); - $this->assertEquals(0700, $adapter->getPermPublic()); - $this->assertSame('ftp.example.com', $adapter->getHost()); - $this->assertSame('admin', $adapter->getUsername()); - } - public function testHash() { file_put_contents(self::$tempDir.'/foo.txt', 'foo'); From bd1767911f04beea2dc734c0a17b3fd0ff12f87c Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Fri, 4 Dec 2020 09:19:51 -0500 Subject: [PATCH 031/194] [9.x] Address confusion between PostgreSQL concepts "schema" and "search_path" (#35463) * Fix terminology in respect to 'schema' vs 'search_path' * Added support for Comma separated search paths with added test * Added support for Postgres Variables in search paths with added test * Fix schema quoting issue and update tests to verify behavior More specifically, fix issue whereby individual schema paths in an array were quoted twice. Also, update arguments in tests to verify schema name parsing with vs. without quotes, for both string and array notations. * Update method to use new "search_path" config key name Co-authored-by: poppabear8883 --- .../Database/Connectors/PostgresConnector.php | 28 ++++++++------- .../Database/Schema/PostgresBuilder.php | 6 ++-- tests/Database/DatabaseConnectorTest.php | 36 +++++++++++++++++-- 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Database/Connectors/PostgresConnector.php b/src/Illuminate/Database/Connectors/PostgresConnector.php index a3ca25e96323..113039f763c7 100755 --- a/src/Illuminate/Database/Connectors/PostgresConnector.php +++ b/src/Illuminate/Database/Connectors/PostgresConnector.php @@ -40,7 +40,7 @@ public function connect(array $config) // database. Setting this DB timezone is an optional configuration item. $this->configureTimezone($connection, $config); - $this->configureSchema($connection, $config); + $this->configureSearchPath($connection, $config); // Postgres allows an application_name to be set by the user and this name is // used to when monitoring the application with pg_stat_activity. So we'll @@ -85,38 +85,40 @@ protected function configureTimezone($connection, array $config) } /** - * Set the schema on the connection. + * Set the search_path on the connection. * * @param \PDO $connection * @param array $config * @return void */ - protected function configureSchema($connection, $config) + protected function configureSearchPath($connection, $config) { - if (isset($config['schema'])) { - $schema = $this->formatSchema($config['schema']); + if (isset($config['search_path'])) { + $searchPath = $this->formatSearchPath($config['search_path']); - $connection->prepare("set search_path to {$schema}")->execute(); + $connection->prepare("set search_path to {$searchPath}")->execute(); } } /** - * Format the schema for the DSN. + * Format the search path for the DSN. * - * @param array|string $schema + * @param array|string $searchPath * @return string */ - protected function formatSchema($schema) + protected function formatSearchPath($searchPath) { - if (is_array($schema)) { - return '"'.implode('", "', $schema).'"'; + if (is_array($searchPath)) { + $searchPath = '"'.implode('", "', $searchPath).'"'; } - return '"'.$schema.'"'; + preg_match_all('/[a-zA-z0-9$]{1,}/i', $searchPath, $matches); + + return '"'.implode('", "', $matches[0]).'"'; } /** - * Set the schema on the connection. + * Set the application name on the connection. * * @param \PDO $connection * @param array $config diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 76673a719a41..9d10e9077ec9 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -164,12 +164,12 @@ protected function parseSchemaAndTable($table) { $table = explode('.', $table); - if (is_array($schema = $this->connection->getConfig('schema'))) { - if (in_array($table[0], $schema)) { + if (is_array($searchPath = $this->connection->getConfig('search_path'))) { + if (in_array($table[0], $searchPath)) { return [array_shift($table), implode('.', $table)]; } - $schema = head($schema); + $schema = head($searchPath); } return [$schema ?: 'public', implode('.', $table)]; diff --git a/tests/Database/DatabaseConnectorTest.php b/tests/Database/DatabaseConnectorTest.php index 5aacf2f1f64d..6ffebc28ba50 100755 --- a/tests/Database/DatabaseConnectorTest.php +++ b/tests/Database/DatabaseConnectorTest.php @@ -88,7 +88,7 @@ public function testPostgresConnectCallsCreateConnectionWithProperArguments() public function testPostgresSearchPathIsSet() { $dsn = 'pgsql:host=foo;dbname=bar'; - $config = ['host' => 'foo', 'database' => 'bar', 'schema' => 'public', 'charset' => 'utf8']; + $config = ['host' => 'foo', 'database' => 'bar', 'search_path' => 'public', 'charset' => 'utf8']; $connector = $this->getMockBuilder(PostgresConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock(); $connection = m::mock(stdClass::class); $connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']); @@ -104,7 +104,7 @@ public function testPostgresSearchPathIsSet() public function testPostgresSearchPathArraySupported() { $dsn = 'pgsql:host=foo;dbname=bar'; - $config = ['host' => 'foo', 'database' => 'bar', 'schema' => ['public', 'user'], 'charset' => 'utf8']; + $config = ['host' => 'foo', 'database' => 'bar', 'search_path' => ['public', '"user"'], 'charset' => 'utf8']; $connector = $this->getMockBuilder(PostgresConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock(); $connection = m::mock(stdClass::class); $connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']); @@ -117,6 +117,38 @@ public function testPostgresSearchPathArraySupported() $this->assertSame($result, $connection); } + public function testPostgresSearchPathCommaSeparatedValueSupported() + { + $dsn = 'pgsql:host=foo;dbname=bar'; + $config = ['host' => 'foo', 'database' => 'bar', 'search_path' => 'public, "user"', 'charset' => 'utf8']; + $connector = $this->getMockBuilder('Illuminate\Database\Connectors\PostgresConnector')->setMethods(['createConnection', 'getOptions'])->getMock(); + $connection = m::mock('stdClass'); + $connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->will($this->returnValue(['options'])); + $connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->will($this->returnValue($connection)); + $connection->shouldReceive('prepare')->once()->with('set names \'utf8\'')->andReturn($connection); + $connection->shouldReceive('prepare')->once()->with('set search_path to "public", "user"')->andReturn($connection); + $connection->shouldReceive('execute')->twice(); + $result = $connector->connect($config); + + $this->assertSame($result, $connection); + } + + public function testPostgresSearchPathVariablesSupported() + { + $dsn = 'pgsql:host=foo;dbname=bar'; + $config = ['host' => 'foo', 'database' => 'bar', 'search_path' => '"$user", public, user', 'charset' => 'utf8']; + $connector = $this->getMockBuilder('Illuminate\Database\Connectors\PostgresConnector')->setMethods(['createConnection', 'getOptions'])->getMock(); + $connection = m::mock('stdClass'); + $connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->will($this->returnValue(['options'])); + $connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->will($this->returnValue($connection)); + $connection->shouldReceive('prepare')->once()->with('set names \'utf8\'')->andReturn($connection); + $connection->shouldReceive('prepare')->once()->with('set search_path to "$user", "public", "user"')->andReturn($connection); + $connection->shouldReceive('execute')->twice(); + $result = $connector->connect($config); + + $this->assertSame($result, $connection); + } + public function testPostgresApplicationNameIsSet() { $dsn = 'pgsql:host=foo;dbname=bar'; From 1e02bc2b1508a9a73f76f33405053278983064f0 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 4 Dec 2020 12:50:42 -0500 Subject: [PATCH 032/194] Initial "summarization" feature --- .../Validation/ValidationException.php | 29 +++++++++- tests/Validation/ValidationExceptionTest.php | 54 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100755 tests/Validation/ValidationExceptionTest.php diff --git a/src/Illuminate/Validation/ValidationException.php b/src/Illuminate/Validation/ValidationException.php index 460f959f1fc4..43c0d2c4c9b4 100644 --- a/src/Illuminate/Validation/ValidationException.php +++ b/src/Illuminate/Validation/ValidationException.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator as ValidatorFacade; +use Illuminate\Support\Str; class ValidationException extends Exception { @@ -53,7 +54,7 @@ class ValidationException extends Exception */ public function __construct($validator, $response = null, $errorBag = 'default') { - parent::__construct('The given data was invalid.'); + parent::__construct(static::summarize($validator)); $this->response = $response; $this->errorBag = $errorBag; @@ -77,6 +78,32 @@ public static function withMessages(array $messages) })); } + + /** + * Create a summary error message from the validation errors. + * + * @param \Illuminate\Contracts\Validation\Validator $validator + * + * @return string + */ + protected static function summarize($validator) + { + $messages = $validator->errors()->all(); + + if (!count($messages)) { + return 'The given data was invalid.'; + } + + $message = array_shift($messages); + + if ($additional = count($messages)) { + $pluralized = 1 === $additional ? 'error' : 'errors'; + $message .= " (and $additional more $pluralized)"; + } + + return $message; + } + /** * Get all of the validation error messages. * diff --git a/tests/Validation/ValidationExceptionTest.php b/tests/Validation/ValidationExceptionTest.php new file mode 100755 index 000000000000..d54693c1dea2 --- /dev/null +++ b/tests/Validation/ValidationExceptionTest.php @@ -0,0 +1,54 @@ +getException([], []); + + $this->assertEquals('The given data was invalid.', $exception->getMessage()); + } + + + public function testExceptionSummarizesOneError() + { + $exception = $this->getException([], ['foo' => 'required']); + + $this->assertEquals('validation.required', $exception->getMessage()); + } + + + public function testExceptionSummarizesTwoErrors() + { + $exception = $this->getException([], [ 'foo' => 'required', 'bar' => 'required' ]); + + $this->assertEquals('validation.required (and 1 more error)', $exception->getMessage()); + } + + public function testExceptionSummarizesThreeOrMoreErrors() + { + $exception = $this->getException([], [ + 'foo' => 'required', + 'bar' => 'required', + 'baz' => 'required', + ]); + + $this->assertEquals('validation.required (and 2 more errors)', $exception->getMessage()); + } + + protected function getException($data = [], $rules = []) + { + $translator = new Translator(new ArrayLoader, 'en'); + $validator = new Validator($translator, $data, $rules); + + return new ValidationException($validator); + } +} From 75cdbedd505441de42427ab5bb2c7e03e5fb0777 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 4 Dec 2020 12:51:44 -0500 Subject: [PATCH 033/194] Remove unnecessary import --- src/Illuminate/Validation/ValidationException.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Validation/ValidationException.php b/src/Illuminate/Validation/ValidationException.php index 43c0d2c4c9b4..86e621c2de17 100644 --- a/src/Illuminate/Validation/ValidationException.php +++ b/src/Illuminate/Validation/ValidationException.php @@ -5,7 +5,6 @@ use Exception; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator as ValidatorFacade; -use Illuminate\Support\Str; class ValidationException extends Exception { From a96dd768dc34efb2d5e170bf8afe3d30d542924d Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 4 Dec 2020 13:04:21 -0500 Subject: [PATCH 034/194] StyleCI --- src/Illuminate/Validation/ValidationException.php | 3 +-- tests/Validation/ValidationExceptionTest.php | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/ValidationException.php b/src/Illuminate/Validation/ValidationException.php index 86e621c2de17..9dde569776a2 100644 --- a/src/Illuminate/Validation/ValidationException.php +++ b/src/Illuminate/Validation/ValidationException.php @@ -77,7 +77,6 @@ public static function withMessages(array $messages) })); } - /** * Create a summary error message from the validation errors. * @@ -89,7 +88,7 @@ protected static function summarize($validator) { $messages = $validator->errors()->all(); - if (!count($messages)) { + if (! count($messages)) { return 'The given data was invalid.'; } diff --git a/tests/Validation/ValidationExceptionTest.php b/tests/Validation/ValidationExceptionTest.php index d54693c1dea2..fb115eac9315 100755 --- a/tests/Validation/ValidationExceptionTest.php +++ b/tests/Validation/ValidationExceptionTest.php @@ -17,7 +17,6 @@ public function testExceptionSummarizesZeroErrors() $this->assertEquals('The given data was invalid.', $exception->getMessage()); } - public function testExceptionSummarizesOneError() { $exception = $this->getException([], ['foo' => 'required']); @@ -25,10 +24,9 @@ public function testExceptionSummarizesOneError() $this->assertEquals('validation.required', $exception->getMessage()); } - public function testExceptionSummarizesTwoErrors() { - $exception = $this->getException([], [ 'foo' => 'required', 'bar' => 'required' ]); + $exception = $this->getException([], ['foo' => 'required', 'bar' => 'required']); $this->assertEquals('validation.required (and 1 more error)', $exception->getMessage()); } From a974ad6191523addf2755aebdf94ce3c14eb958f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 7 Dec 2020 12:44:51 -0600 Subject: [PATCH 035/194] formatting --- src/Illuminate/Validation/ValidationException.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Validation/ValidationException.php b/src/Illuminate/Validation/ValidationException.php index 9dde569776a2..960171901b6f 100644 --- a/src/Illuminate/Validation/ValidationException.php +++ b/src/Illuminate/Validation/ValidationException.php @@ -78,10 +78,9 @@ public static function withMessages(array $messages) } /** - * Create a summary error message from the validation errors. - * - * @param \Illuminate\Contracts\Validation\Validator $validator + * Create a error message summary from the validation errors. * + * @param \Illuminate\Contracts\Validation\Validator $validator * @return string */ protected static function summarize($validator) @@ -96,7 +95,8 @@ protected static function summarize($validator) if ($additional = count($messages)) { $pluralized = 1 === $additional ? 'error' : 'errors'; - $message .= " (and $additional more $pluralized)"; + + $message .= " (and {$additional} more {$pluralized})"; } return $message; From 20fc31c8c9887df2298631de57b3cbfad5bb99c3 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 7 Dec 2020 21:05:35 -0500 Subject: [PATCH 036/194] "Normalize" the search_path parsing behavior Primarily, these changes "normalize" the search_path parsing behavior such that the new parseSearchPath() method returns the same result whether the search_path input is an array (with one or more schemas), a string with one schema, or a string of comma-separated schemas. This method's presence makes it much simpler to retrieve the search_path as configured on the connection and use it for more complex schema-related grammar construction. --- .../Database/Connectors/PostgresConnector.php | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Connectors/PostgresConnector.php b/src/Illuminate/Database/Connectors/PostgresConnector.php index 113039f763c7..f02f414ef5de 100755 --- a/src/Illuminate/Database/Connectors/PostgresConnector.php +++ b/src/Illuminate/Database/Connectors/PostgresConnector.php @@ -94,12 +94,35 @@ protected function configureTimezone($connection, array $config) protected function configureSearchPath($connection, $config) { if (isset($config['search_path'])) { - $searchPath = $this->formatSearchPath($config['search_path']); + $searchPath = $this->formatSearchPath( + $this->parseSearchPath($config['search_path']) + ); $connection->prepare("set search_path to {$searchPath}")->execute(); } } + /** + * Parse the search_path. + * + * @param string|array $searchPath + * @return array + */ + protected function parseSearchPath($searchPath) + { + if (is_string($searchPath)) { + preg_match_all('/[a-zA-z0-9$]{1,}/i', $searchPath, $matches); + + $searchPath = $matches[0]; + } + + array_walk($searchPath, function(&$schema) { + $schema = trim($schema, '\'"'); + }); + + return $searchPath; + } + /** * Format the search path for the DSN. * @@ -108,13 +131,7 @@ protected function configureSearchPath($connection, $config) */ protected function formatSearchPath($searchPath) { - if (is_array($searchPath)) { - $searchPath = '"'.implode('", "', $searchPath).'"'; - } - - preg_match_all('/[a-zA-z0-9$]{1,}/i', $searchPath, $matches); - - return '"'.implode('", "', $matches[0]).'"'; + return count($searchPath) === 1 ? '"' . $searchPath[0] . '"' : '"'.implode('", "', $searchPath).'"'; } /** From 76933a32c3fb36335cabf194e534b12d919ccf47 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 7 Dec 2020 21:17:10 -0500 Subject: [PATCH 037/194] Fix PostgreSQL object reference parsing The manner in which object references were parsed in certain scenarios caused methods such as hasTable() to return incorrect results. Among other issues, the underlying SQL grammar omitted the "table_catalog" (i.e., database) in the WHERE clause, which caused inaccurate results in certain cases, e.g., the method returned true incorrectly because a schema and table with the same name exist in a *different database*. --- .../Schema/Grammars/PostgresGrammar.php | 4 +- .../Database/Schema/PostgresBuilder.php | 70 +++++++++++++++---- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 204beecea3b2..f6450c1b41c9 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -42,7 +42,7 @@ class PostgresGrammar extends Grammar */ public function compileTableExists() { - return "select * from information_schema.tables where table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"; + return "select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"; } /** @@ -52,7 +52,7 @@ public function compileTableExists() */ public function compileColumnListing() { - return 'select column_name from information_schema.columns where table_schema = ? and table_name = ?'; + return 'select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?'; } /** diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 9d10e9077ec9..78fc744b1c43 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -12,12 +12,12 @@ class PostgresBuilder extends Builder */ public function hasTable($table) { - [$schema, $table] = $this->parseSchemaAndTable($table); + [$database, $schema, $table] = $this->parseSchemaAndTable($table); $table = $this->connection->getTablePrefix().$table; return count($this->connection->select( - $this->grammar->compileTableExists(), [$schema, $table] + $this->grammar->compileTableExists(), [$database, $schema, $table] )) > 0; } @@ -143,35 +143,77 @@ public function getAllTypes() */ public function getColumnListing($table) { - [$schema, $table] = $this->parseSchemaAndTable($table); + [$database, $schema, $table] = $this->parseSchemaAndTable($table); $table = $this->connection->getTablePrefix().$table; $results = $this->connection->select( - $this->grammar->compileColumnListing(), [$schema, $table] + $this->grammar->compileColumnListing(), [$database, $schema, $table] ); return $this->connection->getPostProcessor()->processColumnListing($results); } /** - * Parse the table name and extract the schema and table. + * Parse the search_path. * - * @param string $table + * @param string|array $searchPath * @return array */ - protected function parseSchemaAndTable($table) + protected function parseSearchPath($searchPath) { - $table = explode('.', $table); + if (is_string($searchPath)) { + preg_match_all('/[a-zA-z0-9$]{1,}/i', $searchPath, $matches); - if (is_array($searchPath = $this->connection->getConfig('search_path'))) { - if (in_array($table[0], $searchPath)) { - return [array_shift($table), implode('.', $table)]; - } + $searchPath = $matches[0]; + } + + array_walk($searchPath, function(&$schema) { + $schema = trim($schema, '\'"'); + }); + + return $searchPath; + } + + /** + * Parse the database object reference and extract the database, schema, and + * table. + * + * @param string $reference + * @return array + */ + protected function parseSchemaAndTable($reference) + { + $searchPath = $this->parseSearchPath( + $this->connection->getConfig('search_path') ?: 'public' + ); + + $parts = explode('.', $reference); + + // Use the connection's configured database by default. + + $database = $this->connection->getConfig('database'); + + // If the reference contains a database name, use that instead. + + if (count($parts) === 3) { + $database = $parts[0]; + + array_shift($parts); + } + + // Use the first schema in the search_path by default. + + $schema = $searchPath[0]; + + // If the reference contains a schema, use that instead. + + if (count($parts) === 2) { + $schema = $parts[0]; - $schema = head($searchPath); + array_shift($parts); } - return [$schema ?: 'public', implode('.', $table)]; + return [$database, $schema, $parts[0]]; } } From c630b8ec7c50725d45eaaddb1bd1d45370fa4a85 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 7 Dec 2020 22:31:15 -0500 Subject: [PATCH 038/194] Apply Style-CI fixes --- src/Illuminate/Database/Connectors/PostgresConnector.php | 4 ++-- src/Illuminate/Database/Schema/PostgresBuilder.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Connectors/PostgresConnector.php b/src/Illuminate/Database/Connectors/PostgresConnector.php index f02f414ef5de..d74a00dfc7b5 100755 --- a/src/Illuminate/Database/Connectors/PostgresConnector.php +++ b/src/Illuminate/Database/Connectors/PostgresConnector.php @@ -116,7 +116,7 @@ protected function parseSearchPath($searchPath) $searchPath = $matches[0]; } - array_walk($searchPath, function(&$schema) { + array_walk($searchPath, function (&$schema) { $schema = trim($schema, '\'"'); }); @@ -131,7 +131,7 @@ protected function parseSearchPath($searchPath) */ protected function formatSearchPath($searchPath) { - return count($searchPath) === 1 ? '"' . $searchPath[0] . '"' : '"'.implode('", "', $searchPath).'"'; + return count($searchPath) === 1 ? '"'.$searchPath[0].'"' : '"'.implode('", "', $searchPath).'"'; } /** diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 78fc744b1c43..c95423166928 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -168,7 +168,7 @@ protected function parseSearchPath($searchPath) $searchPath = $matches[0]; } - array_walk($searchPath, function(&$schema) { + array_walk($searchPath, function (&$schema) { $schema = trim($schema, '\'"'); }); From 7620a54b65ae296f1810931eb9f67d86fca1b21b Mon Sep 17 00:00:00 2001 From: Alin Ionut Date: Tue, 8 Dec 2020 16:14:14 +0200 Subject: [PATCH 039/194] [9.x] Add passwordTimeout to RequirePassword middleware as a parameter (#35531) * add passwordTimeout to RequirePassword middleware as a parameter * Update RequirePassword.php Co-authored-by: Alin Musat Co-authored-by: Taylor Otwell --- src/Illuminate/Auth/Middleware/RequirePassword.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/RequirePassword.php b/src/Illuminate/Auth/Middleware/RequirePassword.php index 315bdb8121ca..4ed43954da22 100644 --- a/src/Illuminate/Auth/Middleware/RequirePassword.php +++ b/src/Illuminate/Auth/Middleware/RequirePassword.php @@ -50,11 +50,12 @@ public function __construct(ResponseFactory $responseFactory, UrlGenerator $urlG * @param \Illuminate\Http\Request $request * @param \Closure $next * @param string|null $redirectToRoute + * @param int|null $passwordTimeoutSeconds * @return mixed */ - public function handle($request, Closure $next, $redirectToRoute = null) + public function handle($request, Closure $next, $redirectToRoute = null, $passwordTimeoutSeconds = null) { - if ($this->shouldConfirmPassword($request)) { + if ($this->shouldConfirmPassword($request, $passwordTimeoutSeconds)) { if ($request->expectsJson()) { return $this->responseFactory->json([ 'message' => 'Password confirmation required.', @@ -73,12 +74,13 @@ public function handle($request, Closure $next, $redirectToRoute = null) * Determine if the confirmation timeout has expired. * * @param \Illuminate\Http\Request $request + * @param int|null $passwordTimeoutSeconds * @return bool */ - protected function shouldConfirmPassword($request) + protected function shouldConfirmPassword($request, $passwordTimeoutSeconds = null) { $confirmedAt = time() - $request->session()->get('auth.password_confirmed_at', 0); - return $confirmedAt > $this->passwordTimeout; + return $confirmedAt > ($passwordTimeoutSeconds ?? $this->passwordTimeout); } } From a5582b772a0f1e1791988fab070cc94cc99fbbc2 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Tue, 8 Dec 2020 14:09:30 -0500 Subject: [PATCH 040/194] [9.x] Default address methods (#35534) * Default ipAddress column name * Default macAddress column name --- src/Illuminate/Database/Schema/Blueprint.php | 4 ++-- .../DatabaseMySqlSchemaGrammarTest.php | 20 +++++++++++++++++++ .../DatabasePostgresSchemaGrammarTest.php | 20 +++++++++++++++++++ .../DatabaseSQLiteSchemaGrammarTest.php | 20 +++++++++++++++++++ .../DatabaseSqlServerSchemaGrammarTest.php | 20 +++++++++++++++++++ 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 36dfbb7597b6..f8c273fbcbc6 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1201,7 +1201,7 @@ public function foreignUuid($column) * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function ipAddress($column) + public function ipAddress($column = 'ip_address') { return $this->addColumn('ipAddress', $column); } @@ -1212,7 +1212,7 @@ public function ipAddress($column) * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function macAddress($column) + public function macAddress($column = 'mac_address') { return $this->addColumn('macAddress', $column); } diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index c89af64847ad..3e81cdca0950 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1009,6 +1009,16 @@ public function testAddingIpAddress() $this->assertSame('alter table `users` add `foo` varchar(45) not null', $statements[0]); } + public function testAddingIpAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->ipAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table `users` add `ip_address` varchar(45) not null', $statements[0]); + } + public function testAddingMacAddress() { $blueprint = new Blueprint('users'); @@ -1019,6 +1029,16 @@ public function testAddingMacAddress() $this->assertSame('alter table `users` add `foo` varchar(17) not null', $statements[0]); } + public function testAddingMacAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->macAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table `users` add `mac_address` varchar(17) not null', $statements[0]); + } + public function testAddingGeometry() { $blueprint = new Blueprint('geo'); diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 052197fd08c4..ce8514e4901f 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -856,6 +856,16 @@ public function testAddingIpAddress() $this->assertSame('alter table "users" add column "foo" inet not null', $statements[0]); } + public function testAddingIpAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->ipAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "ip_address" inet not null', $statements[0]); + } + public function testAddingMacAddress() { $blueprint = new Blueprint('users'); @@ -866,6 +876,16 @@ public function testAddingMacAddress() $this->assertSame('alter table "users" add column "foo" macaddr not null', $statements[0]); } + public function testAddingMacAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->macAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "mac_address" macaddr not null', $statements[0]); + } + public function testCompileForeign() { $blueprint = new Blueprint('users'); diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index 41e53cc725e7..442d0f137d58 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -741,6 +741,16 @@ public function testAddingIpAddress() $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); } + public function testAddingIpAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->ipAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "ip_address" varchar not null', $statements[0]); + } + public function testAddingMacAddress() { $blueprint = new Blueprint('users'); @@ -751,6 +761,16 @@ public function testAddingMacAddress() $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); } + public function testAddingMacAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->macAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "mac_address" varchar not null', $statements[0]); + } + public function testAddingGeometry() { $blueprint = new Blueprint('geo'); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 5ca3790522ab..acb2ed68367e 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -771,6 +771,16 @@ public function testAddingIpAddress() $this->assertSame('alter table "users" add "foo" nvarchar(45) not null', $statements[0]); } + public function testAddingIpAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->ipAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add "ip_address" nvarchar(45) not null', $statements[0]); + } + public function testAddingMacAddress() { $blueprint = new Blueprint('users'); @@ -781,6 +791,16 @@ public function testAddingMacAddress() $this->assertSame('alter table "users" add "foo" nvarchar(17) not null', $statements[0]); } + public function testAddingMacAddressDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->macAddress(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add "mac_address" nvarchar(17) not null', $statements[0]); + } + public function testAddingGeometry() { $blueprint = new Blueprint('geo'); From 6b055465a534bb1c7999e46945ebe1e0de2be88c Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 9 Dec 2020 06:48:08 -0700 Subject: [PATCH 041/194] Removed action from SymfonyRoute options (#35542) --- src/Illuminate/Routing/Route.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 37ba1aaa4236..ad2dd8d7f5bb 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -1103,7 +1103,7 @@ public function toSymfonyRoute() { return new SymfonyRoute( preg_replace('/\{(\w+?)\?\}/', '{$1}', $this->uri()), $this->getOptionalParameterNames(), - $this->wheres, ['utf8' => true, 'action' => $this->action], + $this->wheres, ['utf8' => true], $this->getDomain() ?: '', [], $this->methods ); } From 7128e69832141b86271c65c27bc4f1c0e99af443 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Tue, 8 Dec 2020 17:07:49 -0500 Subject: [PATCH 042/194] Add tests to cover any added or modified code --- .../Database/DatabasePostgresBuilderTest.php | 209 ++++++++++++++++++ .../DatabasePostgresSchemaGrammarTest.php | 14 ++ 2 files changed, 223 insertions(+) create mode 100644 tests/Database/DatabasePostgresBuilderTest.php diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php new file mode 100644 index 000000000000..e20e24d1213f --- /dev/null +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -0,0 +1,209 @@ +getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn(null); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileTableExists')->andReturn("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"); + $connection->shouldReceive('select')->with("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'", ['laravel', 'public', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $builder = $this->getBuilder($connection); + + $builder->hasTable('foo'); + } + + /** + * Ensure that when the reference is unqualified (i.e., does not contain a + * database name or a schema), and the first schema in the search_path is + * NOT the default ('public'), the database specified on the connection is + * used, and the first schema in the search_path is used. + */ + public function testWhenSearchPathNotEmptyHasTableWithUnqualifiedSchemaReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('myapp,public'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileTableExists')->andReturn("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"); + $connection->shouldReceive('select')->with("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'", ['laravel', 'myapp', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $builder = $this->getBuilder($connection); + + $builder->hasTable('foo'); + } + + /** + * Ensure that when the reference is qualified only with a schema, that + * the database specified on the connection is used, and the specified + * schema is used, even if it is not within the search_path. + */ + public function testWhenSchemaNotInSearchPathHasTableWithQualifiedSchemaReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileTableExists')->andReturn("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"); + $connection->shouldReceive('select')->with("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'", ['laravel', 'myapp', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $builder = $this->getBuilder($connection); + + $builder->hasTable('myapp.foo'); + } + + /** + * Ensure that when the reference is qualified with a database AND a schema, + * and the database is NOT the database configured for the connection, the + * specified database is used instead. + */ + public function testWhenDatabaseNotDefaultHasTableWithFullyQualifiedReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileTableExists')->andReturn("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"); + $connection->shouldReceive('select')->with("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'", ['mydatabase', 'myapp', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $builder = $this->getBuilder($connection); + + $builder->hasTable('mydatabase.myapp.foo'); + } + + /** + * Ensure that when the reference is unqualified (i.e., does not contain a + * database name or a schema), and the search_path is empty, the database + * specified on the connection is used, and the default schema ('public') + * is used. + */ + public function testWhenSearchPathEmptyGetColumnListingWithUnqualifiedReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn(null); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileColumnListing')->andReturn('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?'); + $connection->shouldReceive('select')->with('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?', ['laravel', 'public', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $processor = m::mock(PostgresProcessor::class); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processColumnListing')->andReturn(['some_column']); + $builder = $this->getBuilder($connection); + + $builder->getColumnListing('foo'); + } + + /** + * Ensure that when the reference is unqualified (i.e., does not contain a + * database name or a schema), and the first schema in the search_path is + * NOT the default ('public'), the database specified on the connection is + * used, and the first schema in the search_path is used. + */ + public function testWhenSearchPathNotEmptyGetColumnListingWithUnqualifiedSchemaReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('myapp,public'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileColumnListing')->andReturn('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?'); + $connection->shouldReceive('select')->with('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?', ['laravel', 'myapp', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $processor = m::mock(PostgresProcessor::class); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processColumnListing')->andReturn(['some_column']); + $builder = $this->getBuilder($connection); + + $builder->getColumnListing('foo'); + } + + /** + * Ensure that when the reference is qualified only with a schema, that + * the database specified on the connection is used, and the specified + * schema is used, even if it is not within the search_path. + */ + public function testWhenSchemaNotInSearchPathGetColumnListingWithQualifiedSchemaReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileColumnListing')->andReturn('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?'); + $connection->shouldReceive('select')->with('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?', ['laravel', 'myapp', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $processor = m::mock(PostgresProcessor::class); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processColumnListing')->andReturn(['some_column']); + $builder = $this->getBuilder($connection); + + $builder->getColumnListing('myapp.foo'); + } + + /** + * Ensure that when the reference is qualified with a database AND a schema, + * and the database is NOT the database configured for the connection, the + * specified database is used instead. + */ + public function testWhenDatabaseNotDefaultGetColumnListingWithFullyQualifiedReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileColumnListing')->andReturn('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?'); + $connection->shouldReceive('select')->with('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?', ['mydatabase', 'myapp', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $processor = m::mock(PostgresProcessor::class); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processColumnListing')->andReturn(['some_column']); + $builder = $this->getBuilder($connection); + + $builder->getColumnListing('mydatabase.myapp.foo'); + } + + protected function getConnection() + { + return m::mock(Connection::class); + } + + protected function getBuilder($connection) + { + return new PostgresBuilder($connection); + } + + protected function getGrammar() + { + return new PostgresGrammar; + } +} diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 052197fd08c4..f99728474107 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -998,6 +998,20 @@ public function testDropAllTypesEscapesTableNames() $this->assertSame('drop type "alpha","beta","gamma" cascade', $statement); } + public function testCompileTableExists() + { + $statement = $this->getGrammar()->compileTableExists(); + + $this->assertSame('select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = \'BASE TABLE\'', $statement); + } + + public function testCompileColumnListing() + { + $statement = $this->getGrammar()->compileColumnListing(); + + $this->assertSame('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?', $statement); + } + protected function getConnection() { return m::mock(Connection::class); From b457b4a4ae70e18b8298a067d3023d0e3c2e4342 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 9 Dec 2020 14:43:58 -0600 Subject: [PATCH 043/194] formatting --- .../Database/Connectors/PostgresConnector.php | 12 ++-- .../Database/Schema/PostgresBuilder.php | 61 +++++++++---------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/Illuminate/Database/Connectors/PostgresConnector.php b/src/Illuminate/Database/Connectors/PostgresConnector.php index d74a00dfc7b5..c2c621d2c5d5 100755 --- a/src/Illuminate/Database/Connectors/PostgresConnector.php +++ b/src/Illuminate/Database/Connectors/PostgresConnector.php @@ -85,7 +85,7 @@ protected function configureTimezone($connection, array $config) } /** - * Set the search_path on the connection. + * Set the "search_path" on the database connection. * * @param \PDO $connection * @param array $config @@ -94,18 +94,16 @@ protected function configureTimezone($connection, array $config) protected function configureSearchPath($connection, $config) { if (isset($config['search_path'])) { - $searchPath = $this->formatSearchPath( - $this->parseSearchPath($config['search_path']) - ); + $searchPath = $this->quoteSearchPath($this->parseSearchPath($config['search_path'])); $connection->prepare("set search_path to {$searchPath}")->execute(); } } /** - * Parse the search_path. + * Parse the "search_path" configuration value into an array. * - * @param string|array $searchPath + * @param string|array $searchPath * @return array */ protected function parseSearchPath($searchPath) @@ -129,7 +127,7 @@ protected function parseSearchPath($searchPath) * @param array|string $searchPath * @return string */ - protected function formatSearchPath($searchPath) + protected function quoteSearchPath($searchPath) { return count($searchPath) === 1 ? '"'.$searchPath[0].'"' : '"'.implode('", "', $searchPath).'"'; } diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index c95423166928..37d01fce4590 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -155,29 +155,7 @@ public function getColumnListing($table) } /** - * Parse the search_path. - * - * @param string|array $searchPath - * @return array - */ - protected function parseSearchPath($searchPath) - { - if (is_string($searchPath)) { - preg_match_all('/[a-zA-z0-9$]{1,}/i', $searchPath, $matches); - - $searchPath = $matches[0]; - } - - array_walk($searchPath, function (&$schema) { - $schema = trim($schema, '\'"'); - }); - - return $searchPath; - } - - /** - * Parse the database object reference and extract the database, schema, and - * table. + * Parse the database object reference and extract the database, schema, and table. * * @param string $reference * @return array @@ -190,30 +168,47 @@ protected function parseSchemaAndTable($reference) $parts = explode('.', $reference); - // Use the connection's configured database by default. - $database = $this->connection->getConfig('database'); - // If the reference contains a database name, use that instead. - + // If the reference contains a database name, we will use that instead of the + // default database name for the connection. This allows the database name + // to be specified in the query instead of at the full connection level. if (count($parts) === 3) { $database = $parts[0]; - array_shift($parts); } - // Use the first schema in the search_path by default. - + // We will use the default schema unless the schema has been specified in the + // query. If the schema has been specified in the query then we can use it + // instead of a default schema configured in the connection search path. $schema = $searchPath[0]; - // If the reference contains a schema, use that instead. - if (count($parts) === 2) { $schema = $parts[0]; - array_shift($parts); } return [$database, $schema, $parts[0]]; } + + /** + * Parse the "search_path" value into an array. + * + * @param string|array $searchPath + * @return array + */ + protected function parseSearchPath($searchPath) + { + if (is_string($searchPath)) { + preg_match_all('/[a-zA-z0-9$]{1,}/i', $searchPath, $matches); + + $searchPath = $matches[0]; + } + + array_walk($searchPath, function (&$schema) { + $schema = trim($schema, '\'"'); + }); + + return $searchPath; + } } From 26fec586451d3c730f7a39b4d1906c7736f57ddc Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 9 Dec 2020 21:37:08 +0000 Subject: [PATCH 044/194] Fixed bad merge --- src/Illuminate/Filesystem/composer.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index bdee21077345..7d10b4aeb439 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -39,13 +39,8 @@ "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^2.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^2.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", -<<<<<<< HEAD "symfony/filesystem": "Required to enable support for relative symbolic links (^5.2).", "symfony/mime": "Required to enable support for guessing extensions (^5.2)." -======= - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.1.4).", - "symfony/mime": "Required to enable support for guessing extensions (^5.1.4)." ->>>>>>> 8.x }, "config": { "sort-packages": true From e615d237173915f6ec555b4f8d7f5d43385e8449 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Fri, 11 Dec 2020 09:16:03 -0500 Subject: [PATCH 045/194] Account for special '$user' variable appearing as first schema in search_path (#35567) Given that the default search_path value in a PostgreSQL installation is '"$user", public', or perhaps just '"$user"', as may be the case if hardened against CVE-2018-1058, it is preferable to account for the possibility that an end-user may wish to configure a PostgreSQL database connection in Laravel to mimic said default. Now, if '$user' is the first schema in the search_path, the PostgresBuilder will resolve that schema name to the username defined on the database connection whenever appropriate, e.g., in the hasTable() and getColumnListing() methods. --- .../Database/Schema/PostgresBuilder.php | 4 +- .../Database/DatabasePostgresBuilderTest.php | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 37d01fce4590..0cba5f4d9a16 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -181,7 +181,9 @@ protected function parseSchemaAndTable($reference) // We will use the default schema unless the schema has been specified in the // query. If the schema has been specified in the query then we can use it // instead of a default schema configured in the connection search path. - $schema = $searchPath[0]; + $schema = $searchPath[0] === '$user' + ? $this->connection->getConfig('username') + : $searchPath[0]; if (count($parts) === 2) { $schema = $parts[0]; diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index e20e24d1213f..f41e271a4428 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -58,6 +58,29 @@ public function testWhenSearchPathNotEmptyHasTableWithUnqualifiedSchemaReference $builder->hasTable('foo'); } + /** + * Ensure that when the reference is unqualified (i.e., does not contain a + * database name or a schema), and the first schema in the search_path is + * the special variable '$user', the database specified on the connection is + * used, the first schema in the search_path is used, and the variable + * resolves to the username specified on the connection. + */ + public function testWhenFirstSchemaInSearchPathIsVariableHasTableWithUnqualifiedSchemaReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('username')->andReturn('foouser'); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('$user'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileTableExists')->andReturn("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"); + $connection->shouldReceive('select')->with("select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'", ['laravel', 'foouser', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $builder = $this->getBuilder($connection); + + $builder->hasTable('foo'); + } + /** * Ensure that when the reference is qualified only with a schema, that * the database specified on the connection is used, and the specified @@ -146,6 +169,32 @@ public function testWhenSearchPathNotEmptyGetColumnListingWithUnqualifiedSchemaR $builder->getColumnListing('foo'); } + /** + * Ensure that when the reference is unqualified (i.e., does not contain a + * database name or a schema), and the first schema in the search_path is + * the special variable '$user', the database specified on the connection is + * used, the first schema in the search_path is used, and the variable + * resolves to the username specified on the connection. + */ + public function testWhenFirstSchemaInSearchPathIsVariableGetColumnListingWithUnqualifiedSchemaReferenceIsCorrect() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('username')->andReturn('foouser'); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('$user'); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileColumnListing')->andReturn('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?'); + $connection->shouldReceive('select')->with('select column_name from information_schema.columns where table_catalog = ? and table_schema = ? and table_name = ?', ['laravel', 'foouser', 'foo'])->andReturn(['countable_result']); + $connection->shouldReceive('getTablePrefix'); + $connection->shouldReceive('getConfig')->with('database')->andReturn('laravel'); + $processor = m::mock(PostgresProcessor::class); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processColumnListing')->andReturn(['some_column']); + $builder = $this->getBuilder($connection); + + $builder->getColumnListing('foo'); + } + /** * Ensure that when the reference is qualified only with a schema, that * the database specified on the connection is used, and the specified From 97d41b065f28b2777f99c06f5f94f8fe65500863 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 11 Dec 2020 14:01:02 -0600 Subject: [PATCH 046/194] add default names --- .../Console/Scheduling/ScheduleListCommand.php | 9 +++++++++ .../Console/Scheduling/ScheduleTestCommand.php | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php index a46f9c7f1502..bc8cecfe0618 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php @@ -15,6 +15,15 @@ class ScheduleListCommand extends Command */ protected $signature = 'schedule:list {--timezone= : The timezone that times should be displayed in}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'schedule:list'; + /** * The console command description. * diff --git a/src/Illuminate/Console/Scheduling/ScheduleTestCommand.php b/src/Illuminate/Console/Scheduling/ScheduleTestCommand.php index 2d15888bbbf8..0854ab8e9efb 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleTestCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleTestCommand.php @@ -13,6 +13,15 @@ class ScheduleTestCommand extends Command */ protected $name = 'schedule:test'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'schedule:test'; + /** * The console command description. * From 4066ca3cf7089d5107b13a7303312a9649018ac1 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Sat, 12 Dec 2020 22:19:37 -0500 Subject: [PATCH 047/194] [9.x] Fix several lingering issues with PostgreSQL search_path handling (#35588) * Fix issue with special $user search path variable not being resolved For any scenario in which PostgreSQL's internal "information_schema" is queried using a schema/schemas derived from the search_path configured on the connection, it is necessary to resolve PostgreSQL's special "$user" variable to the actual username set on the connection. While this resolution is performed correctly in the related parseSchemaAndTable() method, it was not being performed here, prior to this change. * Update variable name to reflect what it actually represents * Add new tests to cover search_path behavior when dropping all tables --- .../Schema/Grammars/PostgresGrammar.php | 10 ++--- .../Database/Schema/PostgresBuilder.php | 12 ++++- .../Database/DatabasePostgresBuilderTest.php | 45 +++++++++++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index f6450c1b41c9..8486e499d313 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -246,12 +246,12 @@ public function compileDropAllTypes($types) /** * Compile the SQL needed to retrieve all table names. * - * @param string|array $schema + * @param string|array $searchPath * @return string */ - public function compileGetAllTables($schema) + public function compileGetAllTables($searchPath) { - return "select tablename from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $schema)."')"; + return "select tablename from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $searchPath)."')"; } /** @@ -260,9 +260,9 @@ public function compileGetAllTables($schema) * @param string|array $schema * @return string */ - public function compileGetAllViews($schema) + public function compileGetAllViews($searchPath) { - return "select viewname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $schema)."')"; + return "select viewname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $searchPath)."')"; } /** diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 0cba5f4d9a16..c249ccf02ebe 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -107,7 +107,9 @@ public function dropAllTypes() public function getAllTables() { return $this->connection->select( - $this->grammar->compileGetAllTables((array) $this->connection->getConfig('schema')) + $this->grammar->compileGetAllTables( + $this->parseSearchPath($this->connection->getConfig('search_path')) + ) ); } @@ -119,7 +121,9 @@ public function getAllTables() public function getAllViews() { return $this->connection->select( - $this->grammar->compileGetAllViews((array) $this->connection->getConfig('schema')) + $this->grammar->compileGetAllViews( + $this->parseSearchPath($this->connection->getConfig('search_path')) + ) ); } @@ -209,6 +213,10 @@ protected function parseSearchPath($searchPath) array_walk($searchPath, function (&$schema) { $schema = trim($schema, '\'"'); + + $schema = $schema === '$user' + ? $this->connection->getConfig('username') + : $schema; }); return $searchPath; diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index f41e271a4428..54e64e2e54e5 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -241,6 +241,51 @@ public function testWhenDatabaseNotDefaultGetColumnListingWithFullyQualifiedRefe $builder->getColumnListing('mydatabase.myapp.foo'); } + /** + * Ensure that when the search_path contains just one schema, only that + * schema is passed into the query that is executed to acquire the list + * of tables to be dropped. + */ + public function testDropAllTablesWithOneSchemaInSearchPath() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); + $connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileGetAllTables')->with(['public'])->andReturn("select tablename from pg_catalog.pg_tables where schemaname in ('public')"); + $connection->shouldReceive('select')->with("select tablename from pg_catalog.pg_tables where schemaname in ('public')")->andReturn(['users']); + $grammar->shouldReceive('compileDropAllTables')->with(['users'])->andReturn('drop table "'.implode('","', ['users']).'" cascade'); + $connection->shouldReceive('statement')->with('drop table "'.implode('","', ['users']).'" cascade'); + $builder = $this->getBuilder($connection); + + $builder->dropAllTables(); + } + + /** + * Ensure that when the search_path contains more than one schema, both + * schemas are passed into the query that is executed to acquire the list + * of tables to be dropped. Furthermore, ensure that the special '$user' + * variable is resolved to the username specified on the database connection + * in the process. + */ + public function testDropAllTablesWithMoreThanOneSchemaInSearchPath() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->with('username')->andReturn('foouser'); + $connection->shouldReceive('getConfig')->with('search_path')->andReturn('"$user", public'); + $connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'public'])->andReturn("select tablename from pg_catalog.pg_tables where schemaname in ('foouser','public')"); + $connection->shouldReceive('select')->with("select tablename from pg_catalog.pg_tables where schemaname in ('foouser','public')")->andReturn(['users', 'users']); + $grammar->shouldReceive('compileDropAllTables')->with(['users', 'users'])->andReturn('drop table "'.implode('","', ['users', 'users']).'" cascade'); + $connection->shouldReceive('statement')->with('drop table "'.implode('","', ['users', 'users']).'" cascade'); + $builder = $this->getBuilder($connection); + + $builder->dropAllTables(); + } + protected function getConnection() { return m::mock(Connection::class); From 8968f68c6be534317d9c8e6c5c1df794617c6531 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:30:57 -0500 Subject: [PATCH 048/194] WIP --- src/Illuminate/Testing/TestResponse.php | 24 ++++-- tests/Testing/TestResponseTest.php | 99 +++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index f5e9b39d5295..7a48b278fa4e 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -15,6 +15,7 @@ use Illuminate\Testing\Assert as PHPUnit; use Illuminate\Testing\Constraints\SeeInOrder; use LogicException; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\StreamedResponse; /** @@ -289,7 +290,7 @@ public function assertPlainCookie($cookieName, $value = null) public function assertCookie($cookieName, $value = null, $encrypted = true, $unserialize = false) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName), + $cookie = $this->getCookie($cookieName, $encrypted, $unserialize), "Cookie [{$cookieName}] not present on response." ); @@ -299,13 +300,9 @@ public function assertCookie($cookieName, $value = null, $encrypted = true, $uns $cookieValue = $cookie->getValue(); - $actual = $encrypted - ? CookieValuePrefix::remove(app('encrypter')->decrypt($cookieValue, $unserialize)) - : $cookieValue; - PHPUnit::assertEquals( - $value, $actual, - "Cookie [{$cookieName}] was found, but value [{$actual}] does not match [{$value}]." + $value, $cookieValue, + "Cookie [{$cookieName}] was found, but value [{$cookieValue}] does not match [{$value}]." ); return $this; @@ -377,12 +374,23 @@ public function assertCookieMissing($cookieName) * Get the given cookie from the response. * * @param string $cookieName + * @param bool $decrypt + * @param bool $unserialize * @return \Symfony\Component\HttpFoundation\Cookie|null */ - protected function getCookie($cookieName) + public function getCookie($cookieName, $decrypt = false, $unserialize = false) { foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { + if ($decrypt) { + $decryptedValue = CookieValuePrefix::remove(app('encrypter')->decrypt($cookie->getValue(), $unserialize)); + $cookie = new Cookie( + $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), + $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), + $cookie->isRaw(), $cookie->getSameSite() + ); + } + return $cookie; } } diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 8aae14243652..ee02ce0bfab7 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -2,8 +2,12 @@ namespace Illuminate\Tests\Foundation; +use Illuminate\Container\Container; +use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; +use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; +use Illuminate\Encryption\Encrypter; use Illuminate\Filesystem\Filesystem; use Illuminate\Http\Response; use Illuminate\Testing\TestResponse; @@ -13,6 +17,7 @@ use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\Cookie; class TestResponseTest extends TestCase { @@ -1154,6 +1159,100 @@ public function testItCanBeTapped() })->assertStatus(418); } + public function testAssertPlainCookie() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) + ); + + $response->assertPlainCookie('cookie-name', 'cookie-value'); + } + + public function testAssertCookie() + { + $container = Container::getInstance(); + $encrypter = new Encrypter(str_repeat('a', 16)); + $container->singleton('encrypter', function() use ($encrypter) { + return $encrypter; + }); + + $cookieName = 'cookie-name'; + $cookieValue = 'cookie-value'; + $encryptedValue = $encrypter->encrypt(CookieValuePrefix::create($cookieName, $encrypter->getKey()).$cookieValue, false); + + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) + ); + + $response->assertCookie($cookieName, $cookieValue); + } + + public function testAssertCookieExpired() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', time() - 5000)) + ); + + $response->assertCookieExpired('cookie-name'); + } + + + public function testAssertCookieNotExpired() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', time() + 5000)) + ); + + $response->assertCookieNotExpired('cookie-name'); + } + + + public function testAssertCookieMissing() + { + $response = TestResponse::fromBaseResponse(new Response()); + + $response->assertCookieMissing('cookie-name'); + } + + public function testGetDecryptedCookie() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) + ); + + $cookie = $response->getCookie('cookie-name'); + + $this->assertInstanceOf(Cookie::class, $cookie); + $this->assertEquals('cookie-name', $cookie->getName()); + $this->assertEquals('cookie-value', $cookie->getValue()); + } + + + public function testGetEncryptedCookie() + { + $container = Container::getInstance(); + $encrypter = new Encrypter(str_repeat('a', 16)); + $container->singleton('encrypter', function() use ($encrypter) { + return $encrypter; + }); + + $cookieName = 'cookie-name'; + $cookieValue = 'cookie-value'; + $encryptedValue = $encrypter->encrypt( + CookieValuePrefix::create($cookieName, $encrypter->getKey()).$cookieValue, false + ); + + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) + ); + + $cookie = $response->getCookie($cookieName, true); + + $this->assertInstanceOf(Cookie::class, $cookie); + $this->assertEquals($cookieName, $cookie->getName()); + $this->assertEquals($cookieValue, $cookie->getValue()); + } + private function makeMockResponse($content) { $baseResponse = tap(new Response, function ($response) use ($content) { From 669b3371d27424fb507d48f5a7e75de479901c86 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:33:53 -0500 Subject: [PATCH 049/194] Default to decrypt --- src/Illuminate/Testing/TestResponse.php | 11 ++++++----- tests/Testing/TestResponseTest.php | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 7a48b278fa4e..ea504b3a7feb 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -4,6 +4,7 @@ use ArrayAccess; use Closure; +use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; @@ -317,7 +318,7 @@ public function assertCookie($cookieName, $value = null, $encrypted = true, $uns public function assertCookieExpired($cookieName) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName), + $cookie = $this->getCookie($cookieName, false), "Cookie [{$cookieName}] not present on response." ); @@ -340,7 +341,7 @@ public function assertCookieExpired($cookieName) public function assertCookieNotExpired($cookieName) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName), + $cookie = $this->getCookie($cookieName, false), "Cookie [{$cookieName}] not present on response." ); @@ -363,7 +364,7 @@ public function assertCookieNotExpired($cookieName) public function assertCookieMissing($cookieName) { PHPUnit::assertNull( - $this->getCookie($cookieName), + $this->getCookie($cookieName, false), "Cookie [{$cookieName}] is present on response." ); @@ -378,12 +379,12 @@ public function assertCookieMissing($cookieName) * @param bool $unserialize * @return \Symfony\Component\HttpFoundation\Cookie|null */ - public function getCookie($cookieName, $decrypt = false, $unserialize = false) + public function getCookie($cookieName, $decrypt = true, $unserialize = false) { foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { if ($decrypt) { - $decryptedValue = CookieValuePrefix::remove(app('encrypter')->decrypt($cookie->getValue(), $unserialize)); + $decryptedValue = CookieValuePrefix::remove(app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize)); $cookie = new Cookie( $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index ee02ce0bfab7..21511062aca3 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1172,7 +1172,7 @@ public function testAssertCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton(EncrypterContract::class, function() use ($encrypter) { return $encrypter; }); @@ -1220,7 +1220,7 @@ public function testGetDecryptedCookie() (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) ); - $cookie = $response->getCookie('cookie-name'); + $cookie = $response->getCookie('cookie-name', false); $this->assertInstanceOf(Cookie::class, $cookie); $this->assertEquals('cookie-name', $cookie->getName()); @@ -1232,7 +1232,7 @@ public function testGetEncryptedCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton(EncrypterContract::class, function() use ($encrypter) { return $encrypter; }); @@ -1246,7 +1246,7 @@ public function testGetEncryptedCookie() (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) ); - $cookie = $response->getCookie($cookieName, true); + $cookie = $response->getCookie($cookieName); $this->assertInstanceOf(Cookie::class, $cookie); $this->assertEquals($cookieName, $cookie->getName()); From 0f1edb824e923977cd23b5b98da033f649fd2f13 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:35:20 -0500 Subject: [PATCH 050/194] Code style --- src/Illuminate/Testing/TestResponse.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index ea504b3a7feb..5303c92673f1 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -384,7 +384,9 @@ public function getCookie($cookieName, $decrypt = true, $unserialize = false) foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { if ($decrypt) { - $decryptedValue = CookieValuePrefix::remove(app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize)); + $decryptedValue = CookieValuePrefix::remove( + app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize) + ); $cookie = new Cookie( $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), From e401fa7480ab31b4a150ce88754a01e1cdf21615 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:59:30 -0500 Subject: [PATCH 051/194] Revert to "encrypter" rather than contract --- src/Illuminate/Testing/TestResponse.php | 3 +-- tests/Testing/TestResponseTest.php | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 5303c92673f1..d4e983b400c6 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -4,7 +4,6 @@ use ArrayAccess; use Closure; -use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; @@ -385,7 +384,7 @@ public function getCookie($cookieName, $decrypt = true, $unserialize = false) if ($cookie->getName() === $cookieName) { if ($decrypt) { $decryptedValue = CookieValuePrefix::remove( - app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize) + app('encrypter')->decrypt($cookie->getValue(), $unserialize) ); $cookie = new Cookie( $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 21511062aca3..df4a0b37118f 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Foundation; use Illuminate\Container\Container; -use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; @@ -1172,7 +1171,7 @@ public function testAssertCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton(EncrypterContract::class, function() use ($encrypter) { + $container->singleton('encrypter', function() use ($encrypter) { return $encrypter; }); @@ -1232,7 +1231,7 @@ public function testGetEncryptedCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton(EncrypterContract::class, function() use ($encrypter) { + $container->singleton('encrypter', function() use ($encrypter) { return $encrypter; }); From 70192dc0e576476d516939a063dbbd6dd922ef4a Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:01:41 -0500 Subject: [PATCH 052/194] StyleCI --- tests/Testing/TestResponseTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index df4a0b37118f..e0f276e22c01 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1171,7 +1171,7 @@ public function testAssertCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton('encrypter', function () use ($encrypter) { return $encrypter; }); @@ -1195,7 +1195,6 @@ public function testAssertCookieExpired() $response->assertCookieExpired('cookie-name'); } - public function testAssertCookieNotExpired() { $response = TestResponse::fromBaseResponse( @@ -1205,7 +1204,6 @@ public function testAssertCookieNotExpired() $response->assertCookieNotExpired('cookie-name'); } - public function testAssertCookieMissing() { $response = TestResponse::fromBaseResponse(new Response()); @@ -1226,12 +1224,11 @@ public function testGetDecryptedCookie() $this->assertEquals('cookie-value', $cookie->getValue()); } - public function testGetEncryptedCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton('encrypter', function () use ($encrypter) { return $encrypter; }); From dd5812050226f45ca6d831a52f56263559d55c38 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:09:05 -0500 Subject: [PATCH 053/194] Fix assertCookieNotExpired with session-only cookies --- src/Illuminate/Testing/TestResponse.php | 2 +- tests/Testing/TestResponseTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index d4e983b400c6..c43d9a8d55e9 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -347,7 +347,7 @@ public function assertCookieNotExpired($cookieName) $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime()); PHPUnit::assertTrue( - $expiresAt->greaterThan(Carbon::now()), + 0 === $cookie->getExpiresTime() || $expiresAt->greaterThan(Carbon::now()), "Cookie [{$cookieName}] is expired, it expired at [{$expiresAt}]." ); diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index e0f276e22c01..b4de4349ba0a 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1204,6 +1204,15 @@ public function testAssertCookieNotExpired() $response->assertCookieNotExpired('cookie-name'); } + public function testAssertSessionCookieNotExpired() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) + ); + + $response->assertCookieNotExpired('cookie-name'); + } + public function testAssertCookieMissing() { $response = TestResponse::fromBaseResponse(new Response()); From 529a378ce9db4a37b73f79d4f20755488214bd1b Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:14:41 -0500 Subject: [PATCH 054/194] Handle missing encryption key in tests --- src/Illuminate/Testing/TestResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index c43d9a8d55e9..40c742ee4981 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -290,7 +290,7 @@ public function assertPlainCookie($cookieName, $value = null) public function assertCookie($cookieName, $value = null, $encrypted = true, $unserialize = false) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName, $encrypted, $unserialize), + $cookie = $this->getCookie($cookieName, $encrypted && ! is_null($value), $unserialize), "Cookie [{$cookieName}] not present on response." ); From 0d16ce9c1b3ee194ee7f8b2baef41905925e191f Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:42:13 -0500 Subject: [PATCH 055/194] Handle assertCookieExpired on session cookie --- src/Illuminate/Testing/TestResponse.php | 2 +- tests/Testing/TestResponseTest.php | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 40c742ee4981..df3a66273270 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -324,7 +324,7 @@ public function assertCookieExpired($cookieName) $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime()); PHPUnit::assertTrue( - $expiresAt->lessThan(Carbon::now()), + 0 !== $cookie->getExpiresTime() && $expiresAt->lessThan(Carbon::now()), "Cookie [{$cookieName}] is not expired, it expires at [{$expiresAt}]." ); diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index b4de4349ba0a..ffafd225805c 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1195,6 +1195,17 @@ public function testAssertCookieExpired() $response->assertCookieExpired('cookie-name'); } + public function testAssertSessionCookieExpiredDoesNotTriggerOnSessionCookies() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) + ); + + $this->expectException(ExpectationFailedException::class); + + $response->assertCookieExpired('cookie-name'); + } + public function testAssertCookieNotExpired() { $response = TestResponse::fromBaseResponse( From 92957206252cd4e40430f6f9eb2560566fa34ba3 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 18:37:41 -0500 Subject: [PATCH 056/194] [9.x] Make Redirector::setIntendedUrl fluent (#35609) --- src/Illuminate/Routing/Redirector.php | 4 +++- tests/Routing/RoutingRedirectorTest.php | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/Redirector.php b/src/Illuminate/Routing/Redirector.php index 99e7c226985d..3a5b50392165 100755 --- a/src/Illuminate/Routing/Redirector.php +++ b/src/Illuminate/Routing/Redirector.php @@ -115,11 +115,13 @@ public function intended($default = '/', $status = 302, $headers = [], $secure = * Set the intended url. * * @param string $url - * @return void + * @return $this */ public function setIntendedUrl($url) { $this->session->put('url.intended', $url); + + return $this; } /** diff --git a/tests/Routing/RoutingRedirectorTest.php b/tests/Routing/RoutingRedirectorTest.php index ec86d0ab5e94..d8177dca303b 100644 --- a/tests/Routing/RoutingRedirectorTest.php +++ b/tests/Routing/RoutingRedirectorTest.php @@ -182,6 +182,7 @@ public function testItSetsValidIntendedUrl() { $this->session->shouldReceive('put')->once()->with('url.intended', 'http://foo.com/bar'); - $this->redirect->setIntendedUrl('http://foo.com/bar'); + $result = $this->redirect->setIntendedUrl('http://foo.com/bar'); + $this->assertInstanceOf(Redirector::class, $result); } } From ca2d99233a1e1a8456a01c42eff8d274bc0a26eb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 15 Dec 2020 07:51:12 -0600 Subject: [PATCH 057/194] formatting --- src/Illuminate/Testing/TestResponse.php | 27 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index df3a66273270..3583fa7344e2 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -382,18 +382,25 @@ public function getCookie($cookieName, $decrypt = true, $unserialize = false) { foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { - if ($decrypt) { - $decryptedValue = CookieValuePrefix::remove( - app('encrypter')->decrypt($cookie->getValue(), $unserialize) - ); - $cookie = new Cookie( - $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), - $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), - $cookie->isRaw(), $cookie->getSameSite() - ); + if (! $decrypt) { + return $cookie; } - return $cookie; + $decryptedValue = CookieValuePrefix::remove( + app('encrypter')->decrypt($cookie->getValue(), $unserialize) + ); + + return new Cookie( + $cookie->getName(), + $decryptedValue, + $cookie->getExpiresTime(), + $cookie->getPath(), + $cookie->getDomain(), + $cookie->isSecure(), + $cookie->isHttpOnly(), + $cookie->isRaw(), + $cookie->getSameSite() + ); } } } From c34f65496c53b6456ddf782e1dbc9cef861e73d1 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:30:57 -0500 Subject: [PATCH 058/194] WIP --- src/Illuminate/Testing/TestResponse.php | 24 ++++-- tests/Testing/TestResponseTest.php | 99 +++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index f5e9b39d5295..7a48b278fa4e 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -15,6 +15,7 @@ use Illuminate\Testing\Assert as PHPUnit; use Illuminate\Testing\Constraints\SeeInOrder; use LogicException; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\StreamedResponse; /** @@ -289,7 +290,7 @@ public function assertPlainCookie($cookieName, $value = null) public function assertCookie($cookieName, $value = null, $encrypted = true, $unserialize = false) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName), + $cookie = $this->getCookie($cookieName, $encrypted, $unserialize), "Cookie [{$cookieName}] not present on response." ); @@ -299,13 +300,9 @@ public function assertCookie($cookieName, $value = null, $encrypted = true, $uns $cookieValue = $cookie->getValue(); - $actual = $encrypted - ? CookieValuePrefix::remove(app('encrypter')->decrypt($cookieValue, $unserialize)) - : $cookieValue; - PHPUnit::assertEquals( - $value, $actual, - "Cookie [{$cookieName}] was found, but value [{$actual}] does not match [{$value}]." + $value, $cookieValue, + "Cookie [{$cookieName}] was found, but value [{$cookieValue}] does not match [{$value}]." ); return $this; @@ -377,12 +374,23 @@ public function assertCookieMissing($cookieName) * Get the given cookie from the response. * * @param string $cookieName + * @param bool $decrypt + * @param bool $unserialize * @return \Symfony\Component\HttpFoundation\Cookie|null */ - protected function getCookie($cookieName) + public function getCookie($cookieName, $decrypt = false, $unserialize = false) { foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { + if ($decrypt) { + $decryptedValue = CookieValuePrefix::remove(app('encrypter')->decrypt($cookie->getValue(), $unserialize)); + $cookie = new Cookie( + $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), + $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), + $cookie->isRaw(), $cookie->getSameSite() + ); + } + return $cookie; } } diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 8aae14243652..ee02ce0bfab7 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -2,8 +2,12 @@ namespace Illuminate\Tests\Foundation; +use Illuminate\Container\Container; +use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; +use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; +use Illuminate\Encryption\Encrypter; use Illuminate\Filesystem\Filesystem; use Illuminate\Http\Response; use Illuminate\Testing\TestResponse; @@ -13,6 +17,7 @@ use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\Cookie; class TestResponseTest extends TestCase { @@ -1154,6 +1159,100 @@ public function testItCanBeTapped() })->assertStatus(418); } + public function testAssertPlainCookie() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) + ); + + $response->assertPlainCookie('cookie-name', 'cookie-value'); + } + + public function testAssertCookie() + { + $container = Container::getInstance(); + $encrypter = new Encrypter(str_repeat('a', 16)); + $container->singleton('encrypter', function() use ($encrypter) { + return $encrypter; + }); + + $cookieName = 'cookie-name'; + $cookieValue = 'cookie-value'; + $encryptedValue = $encrypter->encrypt(CookieValuePrefix::create($cookieName, $encrypter->getKey()).$cookieValue, false); + + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) + ); + + $response->assertCookie($cookieName, $cookieValue); + } + + public function testAssertCookieExpired() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', time() - 5000)) + ); + + $response->assertCookieExpired('cookie-name'); + } + + + public function testAssertCookieNotExpired() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', time() + 5000)) + ); + + $response->assertCookieNotExpired('cookie-name'); + } + + + public function testAssertCookieMissing() + { + $response = TestResponse::fromBaseResponse(new Response()); + + $response->assertCookieMissing('cookie-name'); + } + + public function testGetDecryptedCookie() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) + ); + + $cookie = $response->getCookie('cookie-name'); + + $this->assertInstanceOf(Cookie::class, $cookie); + $this->assertEquals('cookie-name', $cookie->getName()); + $this->assertEquals('cookie-value', $cookie->getValue()); + } + + + public function testGetEncryptedCookie() + { + $container = Container::getInstance(); + $encrypter = new Encrypter(str_repeat('a', 16)); + $container->singleton('encrypter', function() use ($encrypter) { + return $encrypter; + }); + + $cookieName = 'cookie-name'; + $cookieValue = 'cookie-value'; + $encryptedValue = $encrypter->encrypt( + CookieValuePrefix::create($cookieName, $encrypter->getKey()).$cookieValue, false + ); + + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) + ); + + $cookie = $response->getCookie($cookieName, true); + + $this->assertInstanceOf(Cookie::class, $cookie); + $this->assertEquals($cookieName, $cookie->getName()); + $this->assertEquals($cookieValue, $cookie->getValue()); + } + private function makeMockResponse($content) { $baseResponse = tap(new Response, function ($response) use ($content) { From 55e5d161f70b7d1250eb73377ad4d235e66e0b37 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:33:53 -0500 Subject: [PATCH 059/194] Default to decrypt --- src/Illuminate/Testing/TestResponse.php | 11 ++++++----- tests/Testing/TestResponseTest.php | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 7a48b278fa4e..ea504b3a7feb 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -4,6 +4,7 @@ use ArrayAccess; use Closure; +use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; @@ -317,7 +318,7 @@ public function assertCookie($cookieName, $value = null, $encrypted = true, $uns public function assertCookieExpired($cookieName) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName), + $cookie = $this->getCookie($cookieName, false), "Cookie [{$cookieName}] not present on response." ); @@ -340,7 +341,7 @@ public function assertCookieExpired($cookieName) public function assertCookieNotExpired($cookieName) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName), + $cookie = $this->getCookie($cookieName, false), "Cookie [{$cookieName}] not present on response." ); @@ -363,7 +364,7 @@ public function assertCookieNotExpired($cookieName) public function assertCookieMissing($cookieName) { PHPUnit::assertNull( - $this->getCookie($cookieName), + $this->getCookie($cookieName, false), "Cookie [{$cookieName}] is present on response." ); @@ -378,12 +379,12 @@ public function assertCookieMissing($cookieName) * @param bool $unserialize * @return \Symfony\Component\HttpFoundation\Cookie|null */ - public function getCookie($cookieName, $decrypt = false, $unserialize = false) + public function getCookie($cookieName, $decrypt = true, $unserialize = false) { foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { if ($decrypt) { - $decryptedValue = CookieValuePrefix::remove(app('encrypter')->decrypt($cookie->getValue(), $unserialize)); + $decryptedValue = CookieValuePrefix::remove(app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize)); $cookie = new Cookie( $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index ee02ce0bfab7..21511062aca3 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1172,7 +1172,7 @@ public function testAssertCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton(EncrypterContract::class, function() use ($encrypter) { return $encrypter; }); @@ -1220,7 +1220,7 @@ public function testGetDecryptedCookie() (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) ); - $cookie = $response->getCookie('cookie-name'); + $cookie = $response->getCookie('cookie-name', false); $this->assertInstanceOf(Cookie::class, $cookie); $this->assertEquals('cookie-name', $cookie->getName()); @@ -1232,7 +1232,7 @@ public function testGetEncryptedCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton(EncrypterContract::class, function() use ($encrypter) { return $encrypter; }); @@ -1246,7 +1246,7 @@ public function testGetEncryptedCookie() (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) ); - $cookie = $response->getCookie($cookieName, true); + $cookie = $response->getCookie($cookieName); $this->assertInstanceOf(Cookie::class, $cookie); $this->assertEquals($cookieName, $cookie->getName()); From 941fa46930490861e1d6904b102f85537cf373ac Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:35:20 -0500 Subject: [PATCH 060/194] Code style --- src/Illuminate/Testing/TestResponse.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index ea504b3a7feb..5303c92673f1 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -384,7 +384,9 @@ public function getCookie($cookieName, $decrypt = true, $unserialize = false) foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { if ($decrypt) { - $decryptedValue = CookieValuePrefix::remove(app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize)); + $decryptedValue = CookieValuePrefix::remove( + app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize) + ); $cookie = new Cookie( $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), From 3963bed4a539521ab29ee870c283957e43082d59 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 15:59:30 -0500 Subject: [PATCH 061/194] Revert to "encrypter" rather than contract --- src/Illuminate/Testing/TestResponse.php | 3 +-- tests/Testing/TestResponseTest.php | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 5303c92673f1..d4e983b400c6 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -4,7 +4,6 @@ use ArrayAccess; use Closure; -use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; @@ -385,7 +384,7 @@ public function getCookie($cookieName, $decrypt = true, $unserialize = false) if ($cookie->getName() === $cookieName) { if ($decrypt) { $decryptedValue = CookieValuePrefix::remove( - app(EncrypterContract::class)->decrypt($cookie->getValue(), $unserialize) + app('encrypter')->decrypt($cookie->getValue(), $unserialize) ); $cookie = new Cookie( $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 21511062aca3..df4a0b37118f 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Foundation; use Illuminate\Container\Container; -use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\View\View; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Database\Eloquent\Model; @@ -1172,7 +1171,7 @@ public function testAssertCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton(EncrypterContract::class, function() use ($encrypter) { + $container->singleton('encrypter', function() use ($encrypter) { return $encrypter; }); @@ -1232,7 +1231,7 @@ public function testGetEncryptedCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton(EncrypterContract::class, function() use ($encrypter) { + $container->singleton('encrypter', function() use ($encrypter) { return $encrypter; }); From 4770f302974443a9fe85f183ababc073c18725e7 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:01:41 -0500 Subject: [PATCH 062/194] StyleCI --- tests/Testing/TestResponseTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index df4a0b37118f..e0f276e22c01 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1171,7 +1171,7 @@ public function testAssertCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton('encrypter', function () use ($encrypter) { return $encrypter; }); @@ -1195,7 +1195,6 @@ public function testAssertCookieExpired() $response->assertCookieExpired('cookie-name'); } - public function testAssertCookieNotExpired() { $response = TestResponse::fromBaseResponse( @@ -1205,7 +1204,6 @@ public function testAssertCookieNotExpired() $response->assertCookieNotExpired('cookie-name'); } - public function testAssertCookieMissing() { $response = TestResponse::fromBaseResponse(new Response()); @@ -1226,12 +1224,11 @@ public function testGetDecryptedCookie() $this->assertEquals('cookie-value', $cookie->getValue()); } - public function testGetEncryptedCookie() { $container = Container::getInstance(); $encrypter = new Encrypter(str_repeat('a', 16)); - $container->singleton('encrypter', function() use ($encrypter) { + $container->singleton('encrypter', function () use ($encrypter) { return $encrypter; }); From be273a8a3ac0cc1a8525d6ed9b1ef8a835a48d48 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:09:05 -0500 Subject: [PATCH 063/194] Fix assertCookieNotExpired with session-only cookies --- src/Illuminate/Testing/TestResponse.php | 2 +- tests/Testing/TestResponseTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index d4e983b400c6..c43d9a8d55e9 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -347,7 +347,7 @@ public function assertCookieNotExpired($cookieName) $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime()); PHPUnit::assertTrue( - $expiresAt->greaterThan(Carbon::now()), + 0 === $cookie->getExpiresTime() || $expiresAt->greaterThan(Carbon::now()), "Cookie [{$cookieName}] is expired, it expired at [{$expiresAt}]." ); diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index e0f276e22c01..b4de4349ba0a 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1204,6 +1204,15 @@ public function testAssertCookieNotExpired() $response->assertCookieNotExpired('cookie-name'); } + public function testAssertSessionCookieNotExpired() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) + ); + + $response->assertCookieNotExpired('cookie-name'); + } + public function testAssertCookieMissing() { $response = TestResponse::fromBaseResponse(new Response()); From bd53408e0722c58c01b943a187b1fd2d77335d62 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:14:41 -0500 Subject: [PATCH 064/194] Handle missing encryption key in tests --- src/Illuminate/Testing/TestResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index c43d9a8d55e9..40c742ee4981 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -290,7 +290,7 @@ public function assertPlainCookie($cookieName, $value = null) public function assertCookie($cookieName, $value = null, $encrypted = true, $unserialize = false) { PHPUnit::assertNotNull( - $cookie = $this->getCookie($cookieName, $encrypted, $unserialize), + $cookie = $this->getCookie($cookieName, $encrypted && ! is_null($value), $unserialize), "Cookie [{$cookieName}] not present on response." ); From 1a599a8eaf363244a61f460fb2a8735e8cd0adb2 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 14 Dec 2020 16:42:13 -0500 Subject: [PATCH 065/194] Handle assertCookieExpired on session cookie --- src/Illuminate/Testing/TestResponse.php | 2 +- tests/Testing/TestResponseTest.php | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 40c742ee4981..df3a66273270 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -324,7 +324,7 @@ public function assertCookieExpired($cookieName) $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime()); PHPUnit::assertTrue( - $expiresAt->lessThan(Carbon::now()), + 0 !== $cookie->getExpiresTime() && $expiresAt->lessThan(Carbon::now()), "Cookie [{$cookieName}] is not expired, it expires at [{$expiresAt}]." ); diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index b4de4349ba0a..ffafd225805c 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1195,6 +1195,17 @@ public function testAssertCookieExpired() $response->assertCookieExpired('cookie-name'); } + public function testAssertSessionCookieExpiredDoesNotTriggerOnSessionCookies() + { + $response = TestResponse::fromBaseResponse( + (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) + ); + + $this->expectException(ExpectationFailedException::class); + + $response->assertCookieExpired('cookie-name'); + } + public function testAssertCookieNotExpired() { $response = TestResponse::fromBaseResponse( From 4e39fde389922f2972b50c000980253d044fcbd4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 15 Dec 2020 07:51:12 -0600 Subject: [PATCH 066/194] formatting --- src/Illuminate/Testing/TestResponse.php | 27 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index df3a66273270..3583fa7344e2 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -382,18 +382,25 @@ public function getCookie($cookieName, $decrypt = true, $unserialize = false) { foreach ($this->headers->getCookies() as $cookie) { if ($cookie->getName() === $cookieName) { - if ($decrypt) { - $decryptedValue = CookieValuePrefix::remove( - app('encrypter')->decrypt($cookie->getValue(), $unserialize) - ); - $cookie = new Cookie( - $cookie->getName(), $decryptedValue, $cookie->getExpiresTime(), $cookie->getPath(), - $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly(), - $cookie->isRaw(), $cookie->getSameSite() - ); + if (! $decrypt) { + return $cookie; } - return $cookie; + $decryptedValue = CookieValuePrefix::remove( + app('encrypter')->decrypt($cookie->getValue(), $unserialize) + ); + + return new Cookie( + $cookie->getName(), + $decryptedValue, + $cookie->getExpiresTime(), + $cookie->getPath(), + $cookie->getDomain(), + $cookie->isSecure(), + $cookie->isHttpOnly(), + $cookie->isRaw(), + $cookie->getSameSite() + ); } } } From d6059bb1504908ba71e320254e7b15a76db93792 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Fri, 18 Dec 2020 17:51:50 +0000 Subject: [PATCH 067/194] [9.x] Add before resolving callbacks to contract (#35661) * Add beforeResolving signature to container contract * Make docblock consistent --- src/Illuminate/Contracts/Container/Container.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index 1b8bb6407934..710e7b15bb5d 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -163,6 +163,15 @@ public function call($callback, array $parameters = [], $defaultMethod = null); */ public function resolved($abstract); + /** + * Register a new before resolving callback. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + */ + public function beforeResolving($abstract, Closure $callback = null); + /** * Register a new resolving callback. * From 840166a046f6e285a7aa50daa1afd2a0bea51b46 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 21 Dec 2020 06:12:58 +0800 Subject: [PATCH 068/194] [9.x] Cast Stringable to string when used with json_encode() (#35680) * [9.x] Cast Stringable to string when used with json_encode(). Signed-off-by: Mior Muhammad Zaki * Update src/Illuminate/Support/Stringable.php Co-authored-by: Anton Komarev <1849174+antonkomarev@users.noreply.github.com> * Update Stringable.php Co-authored-by: Taylor Otwell Co-authored-by: Anton Komarev <1849174+antonkomarev@users.noreply.github.com> --- src/Illuminate/Support/Stringable.php | 13 ++++++++++++- tests/Support/SupportStringableTest.php | 7 +++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index c24d19e6a923..017917baa097 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -4,9 +4,10 @@ use Closure; use Illuminate\Support\Traits\Macroable; +use JsonSerializable; use Symfony\Component\VarDumper\VarDumper; -class Stringable +class Stringable implements JsonSerializable { use Macroable; @@ -722,6 +723,16 @@ public function dd() exit(1); } + /** + * Convert the object into something JSON serializable. + * + * @return string + */ + public function jsonSerialize() + { + return $this->__toString(); + } + /** * Proxy dynamic properties onto methods. * diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 1986d050de9c..930d99ac4aef 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -545,4 +545,11 @@ public function testChunk() $this->assertInstanceOf(Collection::class, $chunks); $this->assertSame(['foo', 'bar', 'baz'], $chunks->all()); } + + public function testJsonSerializable() + { + $this->assertSame('"laravel-php-framework"', json_encode($this->stringable('LaravelPhpFramework')->kebab())); + $this->assertSame('["laravel-php-framework"]', json_encode([$this->stringable('LaravelPhpFramework')->kebab()])); + $this->assertSame('{"title":"laravel-php-framework"}', json_encode(['title' => $this->stringable('LaravelPhpFramework')->kebab()])); + } } From 2dc6ce5a67680c9e544a1730dcd755efd29049ec Mon Sep 17 00:00:00 2001 From: Igor Finagin Date: Mon, 21 Dec 2020 01:28:28 +0300 Subject: [PATCH 069/194] Returns self after merge casts (#35677) --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 2a3ec0ee477b..0bde3e119227 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -514,11 +514,13 @@ protected function mutateAttributeForArray($key, $value) * Merge new casts with existing casts on the model. * * @param array $casts - * @return void + * @return $this */ public function mergeCasts($casts) { $this->casts = array_merge($this->casts, $casts); + + return $this; } /** From f4110cce9381c072aa9e7ea6f2b933bc8ccc326e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Mon, 28 Dec 2020 21:31:24 +0100 Subject: [PATCH 070/194] Support for overriding component props using attributes spread --- .../View/Compilers/Concerns/CompilesComponents.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php index 41f034c05048..61a7fa8c06a6 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php @@ -150,15 +150,17 @@ protected function compileEndComponentFirst() */ protected function compileProps($expression) { - return "exceptProps{$expression}; ?> + return "only(array_keys{$expression}); ?> +exceptProps{$expression}; ?> \$__value) { - \$\$__key = \$\$__key ?? \$__value; + \$\$__key = \$__props[\$__key] ?? \$\$__key ?? \$__value; } ?> \$__value) { if (array_key_exists(\$__key, \$__defined_vars)) unset(\$\$__key); } ?> -"; + +"; } /** From 32dcdb64a0ae2835a3aae1b051a429013d802c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Tue, 29 Dec 2020 01:23:51 +0100 Subject: [PATCH 071/194] Added tests --- tests/View/Blade/BladePropsTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/View/Blade/BladePropsTest.php diff --git a/tests/View/Blade/BladePropsTest.php b/tests/View/Blade/BladePropsTest.php new file mode 100644 index 000000000000..4daf76f20205 --- /dev/null +++ b/tests/View/Blade/BladePropsTest.php @@ -0,0 +1,21 @@ +assertSame('only(array_keys([\'one\' => true, \'two\' => \'string\'])); ?> +exceptProps([\'one\' => true, \'two\' => \'string\']); ?> + true, \'two\' => \'string\']), \'is_string\', ARRAY_FILTER_USE_KEY) as $__key => $__value) { + $$__key = $__props[$__key] ?? $$__key ?? $__value; +} ?> + + $__value) { + if (array_key_exists($__key, $__defined_vars)) unset($$__key); +} ?> + +', $this->compiler->compileString('@props([\'one\' => true, \'two\' => \'string\'])')); + } +} From 7da69e80f22e2ddefcb57cb234b3ce38d46c72c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Tue, 29 Dec 2020 17:07:30 +0100 Subject: [PATCH 072/194] Added Class Based components support --- src/Illuminate/View/Compilers/Concerns/CompilesComponents.php | 2 +- tests/View/Blade/BladeComponentsTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php index 61a7fa8c06a6..8f3d6da9ad03 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php @@ -63,7 +63,7 @@ public static function compileClassComponentOpening(string $component, string $a { return implode("\n", [ '', - 'getContainer()->make('.Str::finish($component, '::class').', '.($data ?: '[]').'); ?>', + 'getContainer()->make('.Str::finish($component, '::class').', '.($data ?: '[]').' + (isset($attributes) ? (array) $attributes->getIterator() : [])); ?>', 'withName('.$alias.'); ?>', 'shouldRender()): ?>', 'startComponent($component->resolveView(), $component->data()); ?>', diff --git a/tests/View/Blade/BladeComponentsTest.php b/tests/View/Blade/BladeComponentsTest.php index 8aefd61a341f..a174f5412d0e 100644 --- a/tests/View/Blade/BladeComponentsTest.php +++ b/tests/View/Blade/BladeComponentsTest.php @@ -13,7 +13,7 @@ public function testComponentsAreCompiled() public function testClassComponentsAreCompiled() { $this->assertSame(' -getContainer()->make(Test::class, ["foo" => "bar"]); ?> +getContainer()->make(Test::class, ["foo" => "bar"] + (isset($attributes) ? (array) $attributes->getIterator() : [])); ?> withName(\'test\'); ?> shouldRender()): ?> startComponent($component->resolveView(), $component->data()); ?>', $this->compiler->compileString('@component(\'Test::class\', \'test\', ["foo" => "bar"])')); From 55125a86b153618879dd6b7abcb45859256e7305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Tue, 29 Dec 2020 19:58:50 +0100 Subject: [PATCH 073/194] Exclude assigned props from attributes array --- .../View/Compilers/ComponentTagCompiler.php | 3 + .../Compilers/Concerns/CompilesComponents.php | 9 +-- src/Illuminate/View/ComponentAttributeBag.php | 24 +++++++- .../Blade/BladeComponentTagCompilerTest.php | 57 +++++++++++++++++++ tests/View/Blade/BladePropsTest.php | 9 +-- tests/View/ViewComponentAttributeBagTest.php | 26 +++++++++ 6 files changed, 119 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index b7b5300535b6..132a9f754302 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -231,6 +231,9 @@ protected function componentString(string $component, array $attributes) } return " @component('{$class}', '{$component}', [".$this->attributesToString($parameters, $escapeBound = false).']) +getConstructor()): ?> +except(collect($constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['.$this->attributesToString($attributes->all(), $escapeAttributes = $class !== DynamicComponent::class).']); ?>'; } diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php index 8f3d6da9ad03..4f48aa2379ba 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php @@ -150,17 +150,18 @@ protected function compileEndComponentFirst() */ protected function compileProps($expression) { - return "only(array_keys{$expression}); ?> + return "onlyProps{$expression} as \$__key => \$__value) { + \$\$__key = \$\$__key ?? \$__value; +} ?> exceptProps{$expression}; ?> \$__value) { - \$\$__key = \$__props[\$__key] ?? \$\$__key ?? \$__value; + \$\$__key = \$\$__key ?? \$__value; } ?> \$__value) { if (array_key_exists(\$__key, \$__defined_vars)) unset(\$\$__key); } ?> - -"; +"; } /** diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index 7a2b9f959ea6..0591ec1029b2 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -153,6 +153,17 @@ public function thatStartWith($string) return $this->whereStartsWith($string); } + /** + * Only include the given attribute from the attribute array. + * + * @param mixed|array $keys + * @return static + */ + public function onlyProps($keys) + { + return $this->only($this->extractPropsNames($keys)); + } + /** * Exclude the given attribute from the attribute array. * @@ -160,6 +171,17 @@ public function thatStartWith($string) * @return static */ public function exceptProps($keys) + { + return $this->except($this->extractPropsNames($keys)); + } + + /** + * Extract prop names from given keys. + * + * @param mixed|array $keys + * @return array + */ + protected function extractPropsNames($keys) { $props = []; @@ -170,7 +192,7 @@ public function exceptProps($keys) $props[] = Str::kebab($key); } - return $this->except($props); + return $props; } /** diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index 6872d38ae4a1..85029d8e5540 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -41,8 +41,14 @@ public function testBasicComponentParsing() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
'); $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['type' => 'foo','limit' => '5','@click' => 'foo','wire:click' => 'changePlan(\''.e(\$plan).'\')','required' => true]); ?>\n". "@endcomponentClass @component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?>\n". '@endcomponentClass
', trim($result)); } @@ -52,6 +58,9 @@ public function testBasicComponentWithEmptyAttributesParsing() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
'); $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['type' => '','limit' => '','@click' => '','required' => true]); ?>\n". '@endcomponentClass
', trim($result)); } @@ -61,6 +70,9 @@ public function testDataCamelCasing() $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => '1']) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?> @endcomponentClass", trim($result)); } @@ -69,6 +81,9 @@ public function testColonData() $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => 1]) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?> @endcomponentClass", trim($result)); } @@ -77,6 +92,9 @@ public function testColonAttributesIsEscapedIfStrings() $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['src' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('foo')]); ?> @endcomponentClass", trim($result)); } @@ -85,6 +103,9 @@ public function testColonNestedComponentParsing() $result = $this->compiler(['foo:alert' => TestAlertComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'foo:alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?> @endcomponentClass", trim($result)); } @@ -93,6 +114,9 @@ public function testColonStartingNestedComponentParsing() $result = $this->compiler(['foo:alert' => TestAlertComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'foo:alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?> @endcomponentClass", trim($result)); } @@ -101,6 +125,9 @@ public function testSelfClosingComponentsCanBeCompiled() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
'); $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?>\n". '@endcomponentClass
', trim($result)); } @@ -140,6 +167,9 @@ public function testComponentsCanBeCompiledWithHyphenAttributes() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['class' => 'bar','wire:model' => 'foo','x-on:click' => 'bar','@click' => 'baz']); ?>\n". '@endcomponentClass', trim($result)); } @@ -149,6 +179,9 @@ public function testSelfClosingComponentsCanBeCompiledWithDataAndAttributes() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => 'foo']) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['class' => 'bar','wire:model' => 'foo']); ?>\n". '@endcomponentClass', trim($result)); } @@ -159,6 +192,9 @@ public function testComponentCanReceiveAttributeBag() $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['class' => 'bar','attributes' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\$attributes),'wire:model' => 'foo']); ?> @endcomponentClass", trim($result)); } @@ -169,6 +205,9 @@ public function testSelfClosingComponentCanReceiveAttributeBag() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
merge([\'class\' => \'test\']) }} wire:model="foo" />
'); $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => 'foo']) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['class' => 'bar','attributes' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\$attributes->merge(['class' => 'test'])),'wire:model' => 'foo']); ?>\n". '@endcomponentClass
', trim($result)); } @@ -178,6 +217,9 @@ public function testComponentsCanHaveAttachedWord() $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags('Words'); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?> @endcomponentClass Words", trim($result)); } @@ -186,6 +228,9 @@ public function testSelfClosingComponentsCanHaveAttachedWord() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('Words'); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?>\n". '@endcomponentClass Words', trim($result)); } @@ -195,6 +240,9 @@ public function testSelfClosingComponentsCanBeCompiledWithBoundData() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(''); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => \$title]) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['class' => 'bar']); ?>\n". '@endcomponentClass', trim($result)); } @@ -205,6 +253,9 @@ public function testPairedComponentTags() '); $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([]); ?> @endcomponentClass", trim($result)); } @@ -221,6 +272,9 @@ public function testClasslessComponents() $result = $this->compiler()->compileTags(''); $this->assertSame("@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']]) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['name' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('Taylor'),'age' => 31,'wire:model' => 'foo']); ?>\n". '@endcomponentClass', trim($result)); } @@ -237,6 +291,9 @@ public function testPackagesClasslessComponents() $result = $this->compiler()->compileTags(''); $this->assertSame("@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']]) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes(['name' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('Taylor'),'age' => 31,'wire:model' => 'foo']); ?>\n". '@endcomponentClass', trim($result)); } diff --git a/tests/View/Blade/BladePropsTest.php b/tests/View/Blade/BladePropsTest.php index 4daf76f20205..4df35acb9625 100644 --- a/tests/View/Blade/BladePropsTest.php +++ b/tests/View/Blade/BladePropsTest.php @@ -6,16 +6,17 @@ class BladePropsTest extends AbstractBladeTestCase { public function testPropsAreCompiled() { - $this->assertSame('only(array_keys([\'one\' => true, \'two\' => \'string\'])); ?> + $this->assertSame('onlyProps([\'one\' => true, \'two\' => \'string\']) as $__key => $__value) { + $$__key = $$__key ?? $__value; +} ?> exceptProps([\'one\' => true, \'two\' => \'string\']); ?> true, \'two\' => \'string\']), \'is_string\', ARRAY_FILTER_USE_KEY) as $__key => $__value) { - $$__key = $__props[$__key] ?? $$__key ?? $__value; + $$__key = $$__key ?? $__value; } ?> $__value) { if (array_key_exists($__key, $__defined_vars)) unset($$__key); } ?> - -', $this->compiler->compileString('@props([\'one\' => true, \'two\' => \'string\'])')); +', $this->compiler->compileString('@props([\'one\' => true, \'two\' => \'string\'])')); } } diff --git a/tests/View/ViewComponentAttributeBagTest.php b/tests/View/ViewComponentAttributeBagTest.php index c91e74589e24..0e49631d2712 100644 --- a/tests/View/ViewComponentAttributeBagTest.php +++ b/tests/View/ViewComponentAttributeBagTest.php @@ -64,5 +64,31 @@ public function testAttributeRetrieval() ]); $this->assertSame('test-string="ok" test-true="test-true" test-0="0" test-0-string="0" test-empty-string=""', (string) $bag); + + $bag = (new ComponentAttributeBag) + ->merge([ + 'test-extract-1' => 'extracted-1', + 'test-extract-2' => 'extracted-2', + 'test-discard-1' => 'discarded-1', + 'test-discard-2' => 'discarded-2' + ]); + + $this->assertSame('test-extract-1="extracted-1" test-extract-2="extracted-2"', (string) $bag->exceptProps([ + 'test-discard-1', + 'test-discard-2' => 'defaultValue' + ])); + + $bag = (new ComponentAttributeBag) + ->merge([ + 'test-extract-1' => 'extracted-1', + 'test-extract-2' => 'extracted-2', + 'test-discard-1' => 'discarded-1', + 'test-discard-2' => 'discarded-2' + ]); + + $this->assertSame('test-extract-1="extracted-1" test-extract-2="extracted-2"', (string) $bag->onlyProps([ + 'test-extract-1', + 'test-extract-2' => 'defaultValue' + ])); } } From 6364c5b8643e68317e4803062258f28d1583b21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Tue, 29 Dec 2020 20:00:33 +0100 Subject: [PATCH 074/194] Fix Style CI --- tests/View/ViewComponentAttributeBagTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/View/ViewComponentAttributeBagTest.php b/tests/View/ViewComponentAttributeBagTest.php index 0e49631d2712..fb8f5e38160e 100644 --- a/tests/View/ViewComponentAttributeBagTest.php +++ b/tests/View/ViewComponentAttributeBagTest.php @@ -70,12 +70,12 @@ public function testAttributeRetrieval() 'test-extract-1' => 'extracted-1', 'test-extract-2' => 'extracted-2', 'test-discard-1' => 'discarded-1', - 'test-discard-2' => 'discarded-2' + 'test-discard-2' => 'discarded-2', ]); $this->assertSame('test-extract-1="extracted-1" test-extract-2="extracted-2"', (string) $bag->exceptProps([ 'test-discard-1', - 'test-discard-2' => 'defaultValue' + 'test-discard-2' => 'defaultValue', ])); $bag = (new ComponentAttributeBag) @@ -83,12 +83,12 @@ public function testAttributeRetrieval() 'test-extract-1' => 'extracted-1', 'test-extract-2' => 'extracted-2', 'test-discard-1' => 'discarded-1', - 'test-discard-2' => 'discarded-2' + 'test-discard-2' => 'discarded-2', ]); $this->assertSame('test-extract-1="extracted-1" test-extract-2="extracted-2"', (string) $bag->onlyProps([ 'test-extract-1', - 'test-extract-2' => 'defaultValue' + 'test-extract-2' => 'defaultValue', ])); } } From 6ab8438062bc8ca6a29cbe4f3372cab68dd93482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Wed, 30 Dec 2020 14:32:25 +0100 Subject: [PATCH 075/194] Added some integration test around Component attributes inheritance --- .../Blade/BladeComponentTagCompilerTest.php | 35 +++++++++++++++++++ tests/View/Blade/BladeComponentsTest.php | 21 +++++++++++ tests/View/Blade/BladePropsTest.php | 24 +++++++++++++ 3 files changed, 80 insertions(+) diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index 85029d8e5540..d8383cd4e45f 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -8,6 +8,7 @@ use Illuminate\View\Compilers\BladeCompiler; use Illuminate\View\Compilers\ComponentTagCompiler; use Illuminate\View\Component; +use Illuminate\View\ComponentAttributeBag; use InvalidArgumentException; use Mockery; @@ -341,6 +342,40 @@ public function testItThrowsAnExceptionForNonExistingClass() $this->compiler()->compileTags(''); } + public function testAttributesTreatedAsPropsAreRemovedFromFinalAttributes() + { + $container = new Container; + $container->instance(Application::class, $app = Mockery::mock(Application::class)); + $container->instance(Factory::class, $factory = Mockery::mock(Factory::class)); + $app->shouldReceive('getNamespace')->andReturn('App\\'); + $factory->shouldReceive('exists')->andReturn(false); + Container::setInstance($container); + + $attributes = new ComponentAttributeBag(['userId' => 'bar', 'other' => 'ok']); + + $component = Mockery::mock(\Illuminate\View\Component::class); + $component->shouldReceive('withName', 'test'); + $component->shouldReceive('shouldRender')->andReturn(true); + $component->shouldReceive('resolveView')->andReturn(''); + $component->shouldReceive('data')->andReturn([]); + $component->shouldReceive('withAttributes'); + + $__env = Mockery::mock(\Illuminate\View\Factory::class); + $__env->shouldReceive('getContainer->make')->with(TestProfileComponent::class, ['userId' => 'bar', 'other' => 'ok'])->andReturn($component); + $__env->shouldReceive('startComponent'); + $__env->shouldReceive('renderComponent'); + + $template = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); + $template = $this->compiler->compileString($template); + + ob_start(); + eval(" ?> $template assertSame($attributes->get('userId'), null); + $this->assertSame($attributes->get('other'), 'ok'); + } + protected function mockViewFactory($existsSucceeds = true) { $container = new Container; diff --git a/tests/View/Blade/BladeComponentsTest.php b/tests/View/Blade/BladeComponentsTest.php index a174f5412d0e..6488601ba203 100644 --- a/tests/View/Blade/BladeComponentsTest.php +++ b/tests/View/Blade/BladeComponentsTest.php @@ -2,6 +2,9 @@ namespace Illuminate\Tests\View\Blade; +use Illuminate\View\ComponentAttributeBag; +use Mockery as m; + class BladeComponentsTest extends AbstractBladeTestCase { public function testComponentsAreCompiled() @@ -52,4 +55,22 @@ public function testEndSlotsAreCompiled() { $this->assertSame('endSlot(); ?>', $this->compiler->compileString('@endslot')); } + + public function testPropsAreExtractedFromParentAttributesCorrectlyForClassComponents() + { + $attributes = new ComponentAttributeBag(['foo' => 'baz', 'other' => 'ok']); + + $component = m::mock(\Illuminate\View\Component::class); + $component->shouldReceive('withName', 'test'); + $component->shouldReceive('shouldRender')->andReturn(false); + + $__env = m::mock(\Illuminate\View\Factory::class); + $__env->shouldReceive('getContainer->make')->with('Test', ['foo' => 'bar', 'other' => 'ok'])->andReturn($component); + + $template = $this->compiler->compileString('@component(\'Test::class\', \'test\', ["foo" => "bar"])'); + + ob_start(); + eval(" ?> $template ', $this->compiler->compileString('@props([\'one\' => true, \'two\' => \'string\'])')); } + + public function testPropsAreExtractedFromParentAttributesCorrectly() + { + $test1 = $test2 = $test4 = null; + + $attributes = new ComponentAttributeBag(['test1' => 'value1', 'test2' => 'value2', 'test3' => 'value3']); + + $template = $this->compiler->compileString('@props([\'test1\' => \'default\', \'test2\', \'test4\' => \'default\'])'); + + ob_start(); + eval(" ?> $template assertSame($test1, 'value1'); + $this->assertSame($test2, 'value2'); + $this->assertSame(isset($test3), false); + $this->assertSame($test4, 'default'); + + $this->assertSame($attributes->get('test1'), null); + $this->assertSame($attributes->get('test2'), null); + $this->assertSame($attributes->get('test3'), 'value3'); + } } From 3b8edf040a0b392804c0f40cefdacc288c370813 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 1 Jan 2021 10:57:09 -0600 Subject: [PATCH 076/194] formatting --- src/Illuminate/View/ComponentAttributeBag.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index 0591ec1029b2..b867569a5b0b 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -161,7 +161,7 @@ public function thatStartWith($string) */ public function onlyProps($keys) { - return $this->only($this->extractPropsNames($keys)); + return $this->only($this->extractPropNames($keys)); } /** @@ -172,7 +172,7 @@ public function onlyProps($keys) */ public function exceptProps($keys) { - return $this->except($this->extractPropsNames($keys)); + return $this->except($this->extractPropNames($keys)); } /** @@ -181,7 +181,7 @@ public function exceptProps($keys) * @param mixed|array $keys * @return array */ - protected function extractPropsNames($keys) + protected function extractPropNames($keys) { $props = []; From 6978dde5a85c8900586e63b4870be7e6060cf6fc Mon Sep 17 00:00:00 2001 From: Bobby Bouwmann Date: Sun, 3 Jan 2021 20:25:57 +0100 Subject: [PATCH 077/194] Remove exception illustrated layout as it's not used anymore (#35768) --- .../views/illustrated-layout.blade.php | 486 ------------------ 1 file changed, 486 deletions(-) delete mode 100644 src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php diff --git a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php deleted file mode 100644 index 2e5b8240b59b..000000000000 --- a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php +++ /dev/null @@ -1,486 +0,0 @@ - - - - - - - @yield('title') - - - - - - - - - -
-
-
-
- @yield('code', __('Oh no')) -
- -
- -

- @yield('message') -

- - - - -
-
- -
- @yield('image') -
-
- - From ef82f51051005868504d5ef99158da92fbb8fed5 Mon Sep 17 00:00:00 2001 From: Greg Date: Mon, 14 Dec 2020 13:30:02 +0000 Subject: [PATCH 078/194] support nested arrays of encrypted cookies such as`a[b][c]` --- src/Illuminate/Cookie/CookieValuePrefix.php | 15 ++++ .../Cookie/Middleware/EncryptCookies.php | 39 ++++++++- .../Cookie/Middleware/EncryptCookiesTest.php | 79 ++++++++++++++++--- 3 files changed, 120 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Cookie/CookieValuePrefix.php b/src/Illuminate/Cookie/CookieValuePrefix.php index e39cb69fa6aa..4eb10f57746f 100644 --- a/src/Illuminate/Cookie/CookieValuePrefix.php +++ b/src/Illuminate/Cookie/CookieValuePrefix.php @@ -26,4 +26,19 @@ public static function remove($cookieValue) { return substr($cookieValue, 41); } + + /** + * Validate a cookie value contains a valid prefix and return it without or null. + * + * @param string $cookieName + * @param string $cookieValue + * @param string $key + * @return string|null + */ + public static function validate($cookieName, $cookieValue, $key) + { + $hasValidPrefix = strpos($cookieValue, static::create($cookieName, $key)) === 0; + + return $hasValidPrefix ? static::remove($cookieValue) : null; + } } diff --git a/src/Illuminate/Cookie/Middleware/EncryptCookies.php b/src/Illuminate/Cookie/Middleware/EncryptCookies.php index 4a116cfb3301..388703416cba 100644 --- a/src/Illuminate/Cookie/Middleware/EncryptCookies.php +++ b/src/Illuminate/Cookie/Middleware/EncryptCookies.php @@ -76,17 +76,15 @@ public function handle($request, Closure $next) protected function decrypt(Request $request) { foreach ($request->cookies as $key => $cookie) { - if ($this->isDisabled($key) || is_array($cookie)) { + if ($this->isDisabled($key)) { continue; } try { $value = $this->decryptCookie($key, $cookie); - $hasValidPrefix = strpos($value, CookieValuePrefix::create($key, $this->encrypter->getKey())) === 0; - $request->cookies->set( - $key, $hasValidPrefix ? CookieValuePrefix::remove($value) : null + $key, $this->validateValue($key, $value) ); } catch (DecryptException $e) { $request->cookies->set($key, null); @@ -96,6 +94,36 @@ protected function decrypt(Request $request) return $request; } + /** + * Validate and remove the cookie value prefix from the value. + * + * @param string $key + * @param string $value + * @return string|array|null + */ + protected function validateValue(string $key, $value) + { + return is_array($value) ? $this->validateArray($key, $value) : + CookieValuePrefix::validate($key, $value, $this->encrypter->getKey()); + } + + /** + * Validate and remove the cookie value prefix from all values of an array. + * + * @param string $key + * @param array $value + * @return array + */ + protected function validateArray(string $key, array $value) + { + $stripped = []; + foreach ($value as $subKey => $subValue) { + $stripped[$subKey] = $this->validateValue("${key}[${subKey}]", $subValue); + } + + return $stripped; + } + /** * Decrypt the given cookie and return the value. * @@ -124,6 +152,9 @@ protected function decryptArray(array $cookie) if (is_string($value)) { $decrypted[$key] = $this->encrypter->decrypt($value, static::serialized($key)); } + if (is_array($value)) { + $decrypted[$key] = $this->decryptArray($value); + } } return $decrypted; diff --git a/tests/Cookie/Middleware/EncryptCookiesTest.php b/tests/Cookie/Middleware/EncryptCookiesTest.php index 321c2edc3827..06f3c6c3b05d 100644 --- a/tests/Cookie/Middleware/EncryptCookiesTest.php +++ b/tests/Cookie/Middleware/EncryptCookiesTest.php @@ -5,6 +5,7 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Cookie\CookieJar; +use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Encryption\Encrypter; @@ -18,6 +19,11 @@ class EncryptCookiesTest extends TestCase { + /** + * @var \Illuminate\Container\Container + */ + protected $container; + /** * @var \Illuminate\Routing\Router */ @@ -30,12 +36,12 @@ protected function setUp(): void { parent::setUp(); - $container = new Container; - $container->singleton(EncrypterContract::class, function () { + $this->container = new Container; + $this->container->singleton(EncrypterContract::class, function () { return new Encrypter(str_repeat('a', 16)); }); - $this->router = new Router(new Dispatcher, $container); + $this->router = new Router(new Dispatcher, $this->container); } public function testSetCookieEncryption() @@ -48,11 +54,14 @@ public function testSetCookieEncryption() $response = $this->router->dispatch(Request::create($this->setCookiePath, 'GET')); $cookies = $response->headers->getCookies(); - $this->assertCount(2, $cookies); + $this->assertCount(4, $cookies); $this->assertSame('encrypted_cookie', $cookies[0]->getName()); $this->assertNotSame('value', $cookies[0]->getValue()); - $this->assertSame('unencrypted_cookie', $cookies[1]->getName()); - $this->assertSame('value', $cookies[1]->getValue()); + $this->assertSame('encrypted[array_cookie]', $cookies[1]->getName()); + $this->assertNotSame('value', $cookies[1]->getValue()); + $this->assertSame('encrypted[nested][array_cookie]', $cookies[2]->getName()); + $this->assertSame('unencrypted_cookie', $cookies[3]->getName()); + $this->assertSame('value', $cookies[3]->getValue()); } public function testQueuedCookieEncryption() @@ -65,11 +74,59 @@ public function testQueuedCookieEncryption() $response = $this->router->dispatch(Request::create($this->queueCookiePath, 'GET')); $cookies = $response->headers->getCookies(); - $this->assertCount(2, $cookies); + $this->assertCount(4, $cookies); $this->assertSame('encrypted_cookie', $cookies[0]->getName()); $this->assertNotSame('value', $cookies[0]->getValue()); - $this->assertSame('unencrypted_cookie', $cookies[1]->getName()); - $this->assertSame('value', $cookies[1]->getValue()); + $this->assertSame('encrypted[array_cookie]', $cookies[1]->getName()); + $this->assertNotSame('value', $cookies[1]->getValue()); + $this->assertSame('encrypted[nested][array_cookie]', $cookies[2]->getName()); + $this->assertNotSame('value', $cookies[2]->getValue()); + $this->assertSame('unencrypted_cookie', $cookies[3]->getName()); + $this->assertSame('value', $cookies[3]->getValue()); + } + + protected function getEncryptedCookieValue($key, $value) + { + $encrypter = $this->container->make(EncrypterContract::class); + + return $encrypter->encrypt( + CookieValuePrefix::create($key, $encrypter->getKey()).$value, + false + ); + } + + public function testCookieDecryption() + { + $cookies = [ + 'encrypted_cookie' => $this->getEncryptedCookieValue('encrypted_cookie', 'value'), + 'encrypted' => [ + 'array_cookie' => $this->getEncryptedCookieValue('encrypted[array_cookie]', 'value'), + 'nested' => [ + 'array_cookie' => $this->getEncryptedCookieValue('encrypted[nested][array_cookie]', 'value'), + ], + ], + 'unencrypted_cookie' => 'value', + ]; + + $this->container->make(EncryptCookiesTestMiddleware::class)->handle( + Request::create('/cookie/read', 'GET', [], $cookies), + function ($request) { + $cookies = $request->cookies->all(); + $this->assertCount(3, $cookies); + $this->assertArrayHasKey('encrypted_cookie', $cookies); + $this->assertSame('value', $cookies['encrypted_cookie']); + $this->assertArrayHasKey('encrypted', $cookies); + $this->assertArrayHasKey('array_cookie', $cookies['encrypted']); + $this->assertSame('value', $cookies['encrypted']['array_cookie']); + $this->assertArrayHasKey('nested', $cookies['encrypted']); + $this->assertArrayHasKey('array_cookie', $cookies['encrypted']['nested']); + $this->assertSame('value', $cookies['encrypted']['nested']['array_cookie']); + $this->assertArrayHasKey('unencrypted_cookie', $cookies); + $this->assertSame('value', $cookies['unencrypted_cookie']); + + return new Response; + } + ); } } @@ -79,6 +136,8 @@ public function setCookies() { $response = new Response; $response->headers->setCookie(new Cookie('encrypted_cookie', 'value')); + $response->headers->setCookie(new Cookie('encrypted[array_cookie]', 'value')); + $response->headers->setCookie(new Cookie('encrypted[nested][array_cookie]', 'value')); $response->headers->setCookie(new Cookie('unencrypted_cookie', 'value')); return $response; @@ -103,6 +162,8 @@ public function __construct() { $cookie = new CookieJar; $cookie->queue(new Cookie('encrypted_cookie', 'value')); + $cookie->queue(new Cookie('encrypted[array_cookie]', 'value')); + $cookie->queue(new Cookie('encrypted[nested][array_cookie]', 'value')); $cookie->queue(new Cookie('unencrypted_cookie', 'value')); $this->cookies = $cookie; From 4aa5b3bbd10880bd74b2a70f25fcec032e089ed2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 5 Jan 2021 09:23:14 -0600 Subject: [PATCH 079/194] formatting --- src/Illuminate/Cookie/CookieValuePrefix.php | 2 +- .../Cookie/Middleware/EncryptCookies.php | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Cookie/CookieValuePrefix.php b/src/Illuminate/Cookie/CookieValuePrefix.php index 4eb10f57746f..0c8f86a3f7eb 100644 --- a/src/Illuminate/Cookie/CookieValuePrefix.php +++ b/src/Illuminate/Cookie/CookieValuePrefix.php @@ -28,7 +28,7 @@ public static function remove($cookieValue) } /** - * Validate a cookie value contains a valid prefix and return it without or null. + * Validate a cookie value contains a valid prefix. If it does, return the cookie value with the prefix removed. Otherwise, return null. * * @param string $cookieName * @param string $cookieValue diff --git a/src/Illuminate/Cookie/Middleware/EncryptCookies.php b/src/Illuminate/Cookie/Middleware/EncryptCookies.php index 388703416cba..d67c7b6308bc 100644 --- a/src/Illuminate/Cookie/Middleware/EncryptCookies.php +++ b/src/Illuminate/Cookie/Middleware/EncryptCookies.php @@ -83,9 +83,7 @@ protected function decrypt(Request $request) try { $value = $this->decryptCookie($key, $cookie); - $request->cookies->set( - $key, $this->validateValue($key, $value) - ); + $request->cookies->set($key, $this->validateValue($key, $value)); } catch (DecryptException $e) { $request->cookies->set($key, null); } @@ -103,8 +101,9 @@ protected function decrypt(Request $request) */ protected function validateValue(string $key, $value) { - return is_array($value) ? $this->validateArray($key, $value) : - CookieValuePrefix::validate($key, $value, $this->encrypter->getKey()); + return is_array($value) + ? $this->validateArray($key, $value) + : CookieValuePrefix::validate($key, $value, $this->encrypter->getKey()); } /** @@ -116,12 +115,13 @@ protected function validateValue(string $key, $value) */ protected function validateArray(string $key, array $value) { - $stripped = []; - foreach ($value as $subKey => $subValue) { - $stripped[$subKey] = $this->validateValue("${key}[${subKey}]", $subValue); + $validated = []; + + foreach ($value as $index => $subValue) { + $validated[$index] = $this->validateValue("${key}[${index}]", $subValue); } - return $stripped; + return $validated; } /** @@ -152,6 +152,7 @@ protected function decryptArray(array $cookie) if (is_string($value)) { $decrypted[$key] = $this->encrypter->decrypt($value, static::serialized($key)); } + if (is_array($value)) { $decrypted[$key] = $this->decryptArray($value); } From 4c0d55f5ffa59b6ff0221e87b135cf1965657c63 Mon Sep 17 00:00:00 2001 From: Marco Boers Date: Fri, 8 Jan 2021 17:21:24 +0100 Subject: [PATCH 080/194] [9.x] Fix BelongsToMany#updateOrCreate behaviour merge arguments for new models (#35827) * Update updateOrCreate on BelongsToMany to follow default behaviour of merging arguments for newly created models * Fix failing tests Co-authored-by: Marco --- .../Eloquent/Relations/BelongsToMany.php | 2 +- .../Database/EloquentBelongsToManyTest.php | 33 +++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index ab13ef538fcd..cecb13e915dc 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -628,7 +628,7 @@ public function firstOrCreate(array $attributes, array $joining = [], $touch = t public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true) { if (is_null($instance = $this->related->where($attributes)->first())) { - return $this->create($values, $joining, $touch); + return $this->create(array_merge($attributes, $values), $joining, $touch); } $instance->fill($values); diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index b66cd3d3f34c..2599fdd85858 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -39,6 +39,7 @@ protected function setUp(): void Schema::create('tags', function (Blueprint $table) { $table->increments('id'); $table->string('name'); + $table->string('type')->nullable(); $table->timestamps(); }); @@ -453,6 +454,18 @@ public function testUpdateOrCreateMethod() $this->assertNotNull($post->tags()->whereName('dives')->first()); } + public function testUpdateOrCreateMethodCreate() + { + $post = Post::create(['title' => Str::random()]); + + $post->tags()->updateOrCreate(['name' => 'wavez'], ['type' => 'featured']); + + $tag = $post->tags()->whereType('featured')->first(); + + $this->assertNotNull($tag); + $this->assertSame('wavez', $tag->name); + } + public function testSyncMethod() { $post = Post::create(['title' => Str::random()]); @@ -647,7 +660,7 @@ public function testCanTouchRelatedModels() public function testWherePivotOnString() { - $tag = Tag::create(['name' => Str::random()]); + $tag = Tag::create(['name' => Str::random()])->fresh(); $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ @@ -663,7 +676,7 @@ public function testWherePivotOnString() public function testFirstWhere() { - $tag = Tag::create(['name' => 'foo']); + $tag = Tag::create(['name' => 'foo'])->fresh(); $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ @@ -679,7 +692,7 @@ public function testFirstWhere() public function testWherePivotOnBoolean() { - $tag = Tag::create(['name' => Str::random()]); + $tag = Tag::create(['name' => Str::random()])->fresh(); $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ @@ -695,7 +708,7 @@ public function testWherePivotOnBoolean() public function testWherePivotInMethod() { - $tag = Tag::create(['name' => Str::random()]); + $tag = Tag::create(['name' => Str::random()])->fresh(); $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ @@ -730,7 +743,7 @@ public function testOrWherePivotInMethod() public function testWherePivotNotInMethod() { $tag1 = Tag::create(['name' => Str::random()]); - $tag2 = Tag::create(['name' => Str::random()]); + $tag2 = Tag::create(['name' => Str::random()])->fresh(); $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ @@ -768,7 +781,7 @@ public function testOrWherePivotNotInMethod() public function testWherePivotNullMethod() { $tag1 = Tag::create(['name' => Str::random()]); - $tag2 = Tag::create(['name' => Str::random()]); + $tag2 = Tag::create(['name' => Str::random()])->fresh(); $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ @@ -784,7 +797,7 @@ public function testWherePivotNullMethod() public function testWherePivotNotNullMethod() { - $tag1 = Tag::create(['name' => Str::random()]); + $tag1 = Tag::create(['name' => Str::random()])->fresh(); $tag2 = Tag::create(['name' => Str::random()]); $post = Post::create(['title' => Str::random()]); @@ -909,8 +922,8 @@ public function testPivotDoesntHavePrimaryKey() public function testOrderByPivotMethod() { $tag1 = Tag::create(['name' => Str::random()]); - $tag2 = Tag::create(['name' => Str::random()]); - $tag3 = Tag::create(['name' => Str::random()]); + $tag2 = Tag::create(['name' => Str::random()])->fresh(); + $tag3 = Tag::create(['name' => Str::random()])->fresh(); $tag4 = Tag::create(['name' => Str::random()]); $post = Post::create(['title' => Str::random()]); @@ -1030,7 +1043,7 @@ class Tag extends Model { public $table = 'tags'; public $timestamps = true; - protected $fillable = ['name']; + protected $fillable = ['name', 'type']; public function posts() { From 2996da8d616aa648ac7646001d318928ae4a41f6 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Sat, 9 Jan 2021 23:29:38 -0400 Subject: [PATCH 081/194] add passthru methods to eloquent builder --- src/Illuminate/Database/Eloquent/Builder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index d3f1f96a8c13..e10fe62d558b 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -77,6 +77,7 @@ class Builder protected $passthru = [ 'insert', 'insertOrIgnore', 'insertGetId', 'insertUsing', 'getBindings', 'toSql', 'dump', 'dd', 'exists', 'doesntExist', 'count', 'min', 'max', 'avg', 'average', 'sum', 'getConnection', 'raw', 'getGrammar', + 'newQuery', 'getProcessor', 'implode', 'aggregate', 'numericAggregate', ]; /** From b026c12d7cdb4a74bcbff24526f99e5f97253367 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 11 Jan 2021 08:53:09 -0600 Subject: [PATCH 082/194] formatting --- src/Illuminate/Database/Eloquent/Builder.php | 27 +++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index e10fe62d558b..cf8ffa9c7d21 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -75,9 +75,30 @@ class Builder * @var string[] */ protected $passthru = [ - 'insert', 'insertOrIgnore', 'insertGetId', 'insertUsing', 'getBindings', 'toSql', 'dump', 'dd', - 'exists', 'doesntExist', 'count', 'min', 'max', 'avg', 'average', 'sum', 'getConnection', 'raw', 'getGrammar', - 'newQuery', 'getProcessor', 'implode', 'aggregate', 'numericAggregate', + 'aggregate', + 'average', + 'avg', + 'count', + 'dd', + 'doesntExist', + 'dump', + 'exists', + 'getBindings', + 'getConnection', + 'getGrammar', + 'getProcessor', + 'implode', + 'insert', + 'insertGetId', + 'insertOrIgnore', + 'insertUsing', + 'max', + 'min', + 'newQuery', + 'numericAggregate', + 'raw', + 'sum', + 'toSql', ]; /** From 4a45e56d93f24738fd1b97e30e9d2cff43fbef67 Mon Sep 17 00:00:00 2001 From: Loots-it Date: Tue, 12 Jan 2021 15:53:30 +0100 Subject: [PATCH 083/194] =?UTF-8?q?[9.x]=20Added=20argument=20transformNul?= =?UTF-8?q?lToEmptyString=20to=20the=20functions=20old()=20and=20=E2=80=A6?= =?UTF-8?q?=20(#35853)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added argument transformNullToEmptyString to the functions old() and getOldInput() and added tests * Removed argument transformNullToEmptyString from the functions old() and getOldInput() --- tests/Session/SessionStoreTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Session/SessionStoreTest.php b/tests/Session/SessionStoreTest.php index 5871cc657a85..a48dcb088212 100644 --- a/tests/Session/SessionStoreTest.php +++ b/tests/Session/SessionStoreTest.php @@ -226,7 +226,7 @@ public function testOldInputFlashing() { $session = $this->getSession(); $session->put('boom', 'baz'); - $session->flashInput(['foo' => 'bar', 'bar' => 0]); + $session->flashInput(['foo' => 'bar', 'bar' => 0, 'name' => null]); $this->assertTrue($session->hasOldInput('foo')); $this->assertSame('bar', $session->getOldInput('foo')); @@ -239,6 +239,9 @@ public function testOldInputFlashing() $this->assertSame('bar', $session->getOldInput('foo')); $this->assertEquals(0, $session->getOldInput('bar')); $this->assertFalse($session->hasOldInput('boom')); + + $this->assertSame('default', $session->getOldInput('input', 'default')); + $this->assertSame(null, $session->getOldInput('name', 'default')); } public function testDataFlashing() From 8b5845b1955905f8c316f2e0fec9406ca1ace631 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Wed, 13 Jan 2021 15:20:19 +0100 Subject: [PATCH 084/194] [9.x] Adds support for Parallel Testing (#35778) * Adds parallel testing * Fixes "Class MysqlBuilder" not found * Updates wording when drivers do not support create/drop databases * Avoids "getenv" and "putenv" in favour of $_SERVER * Moves "createDatabaseIfNotExists" to "createDatabase" * Adds support to "Postgres" * Fixes CS * Uses a database per process regardless of the used database testing trait * Apply fixes from StyleCI * Removes unused catch * Refactors into service providers * Apply fixes from StyleCI * Removes token resolver from the public API * Renames Parallel Testing register callbacks * Adds "setUp" process and "tearDown" test case * Updates Parallel Testing facade * Suffixes _test_ on storage too * Fixes missing envs for process callbacks * Apply fixes from StyleCI * Ensures "drops" only happen when needed * Apply fixes from StyleCI * Adds support for SQLite file databases * Adds tests for SQLite file databases * Lower case create/drop statements * Adds support for SQL Server * Apply fixes from StyleCI * Adds tests against Parallel Testing callbacks * Adds tests for parallel console output * Apply fixes from StyleCI * Removes unused lines in tests * Calls Parallel Testing setUp callbacks after refresh app only * Cleans folders for parallel testing * Makes test databases persist * Apply fixes from StyleCI * Resolve parallel testing callbacks from container * Apply fixes from StyleCI * Update TestDatabases.php * Update ParallelTesting.php * Renames "refresh-databases" to "recreate-databases" Co-authored-by: Nuno Maduro Co-authored-by: Taylor Otwell --- composer.json | 1 + src/Illuminate/Database/Schema/Builder.php | 22 ++ .../Database/Schema/Grammars/Grammar.php | 24 ++ .../Database/Schema/Grammars/MySqlGrammar.php | 31 +++ .../Schema/Grammars/PostgresGrammar.php | 30 +++ .../Schema/Grammars/SqlServerGrammar.php | 29 ++ .../Database/Schema/MySqlBuilder.php | 26 ++ .../Database/Schema/PostgresBuilder.php | 26 ++ .../Database/Schema/SQLiteBuilder.php | 26 ++ .../Database/Schema/SqlServerBuilder.php | 26 ++ .../Providers/FoundationServiceProvider.php | 2 + .../Foundation/Testing/TestCase.php | 5 + .../Support/Facades/ParallelTesting.php | 25 ++ src/Illuminate/Support/Facades/Schema.php | 2 + src/Illuminate/Support/Facades/Storage.php | 10 +- .../Testing/Concerns/TestDatabases.php | 162 +++++++++++ .../Testing/ParallelConsoleOutput.php | 60 +++++ src/Illuminate/Testing/ParallelRunner.php | 140 ++++++++++ src/Illuminate/Testing/ParallelTesting.php | 255 ++++++++++++++++++ .../ParallelTestingServiceProvider.php | 38 +++ .../DatabaseAbstractSchemaGrammarTest.php | 37 +++ .../DatabaseMySqlSchemaGrammarTest.php | 42 +++ tests/Database/DatabaseMysqlBuilderTest.php | 48 ++++ .../Database/DatabasePostgresBuilderTest.php | 30 +++ .../DatabasePostgresSchemaGrammarTest.php | 38 +++ tests/Database/DatabaseSQLiteBuilderTest.php | 91 +++++++ tests/Database/DatabaseSchemaBuilderTest.php | 27 ++ .../DatabaseSqlServerSchemaGrammarTest.php | 36 +++ tests/Database/SqlServerBuilderTest.php | 46 ++++ tests/Testing/ParallelConsoleOutputTest.php | 25 ++ tests/Testing/ParallelTestingTest.php | 99 +++++++ 31 files changed, 1456 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Support/Facades/ParallelTesting.php create mode 100644 src/Illuminate/Testing/Concerns/TestDatabases.php create mode 100644 src/Illuminate/Testing/ParallelConsoleOutput.php create mode 100644 src/Illuminate/Testing/ParallelRunner.php create mode 100644 src/Illuminate/Testing/ParallelTesting.php create mode 100644 src/Illuminate/Testing/ParallelTestingServiceProvider.php create mode 100755 tests/Database/DatabaseAbstractSchemaGrammarTest.php create mode 100644 tests/Database/DatabaseMysqlBuilderTest.php create mode 100644 tests/Database/DatabaseSQLiteBuilderTest.php create mode 100644 tests/Database/SqlServerBuilderTest.php create mode 100644 tests/Testing/ParallelConsoleOutputTest.php create mode 100644 tests/Testing/ParallelTestingTest.php diff --git a/composer.json b/composer.json index 2f5533c97fe0..79bea59f041d 100644 --- a/composer.json +++ b/composer.json @@ -131,6 +131,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).", "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", + "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 80611bfc92ed..04f96e43308a 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -94,6 +94,28 @@ public static function morphUsingUuids() return static::defaultMorphKeyType('uuid'); } + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + throw new LogicException('This database driver does not support creating databases.'); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + throw new LogicException('This database driver does not support dropping databases.'); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index b60dfe817b62..18071b2fbb12 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -9,6 +9,7 @@ use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; +use LogicException; use RuntimeException; abstract class Grammar extends BaseGrammar @@ -27,6 +28,29 @@ abstract class Grammar extends BaseGrammar */ protected $fluentCommands = []; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + throw new LogicException('This database driver does not support creating databases.'); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + throw new LogicException('This database driver does not support dropping databases.'); + } + /** * Compile a rename column command. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index c2952e47926c..ecaf96e2a3a1 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -26,6 +26,37 @@ class MySqlGrammar extends Grammar */ protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger']; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + return sprintf( + 'create database %s default character set %s default collate %s', + $this->wrapValue($name), + $this->wrapValue($connection->getConfig('charset')), + $this->wrapValue($connection->getConfig('collation')), + ); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + return sprintf( + 'drop database if exists %s', + $this->wrapValue($name) + ); + } + /** * Compile the query to determine the list of tables. * diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 8486e499d313..58328f2e09e2 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -35,6 +35,36 @@ class PostgresGrammar extends Grammar */ protected $fluentCommands = ['Comment']; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + return sprintf( + 'create database %s encoding %s', + $this->wrapValue($name), + $this->wrapValue($connection->getConfig('charset')), + ); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + return sprintf( + 'drop database if exists %s', + $this->wrapValue($name) + ); + } + /** * Compile the query to determine if a table exists. * diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 79f3f0f5e3ad..c3fc442e2368 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -28,6 +28,35 @@ class SqlServerGrammar extends Grammar */ protected $serials = ['tinyInteger', 'smallInteger', 'mediumInteger', 'integer', 'bigInteger']; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + return sprintf( + 'create database %s', + $this->wrapValue($name), + ); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + return sprintf( + 'drop database if exists %s', + $this->wrapValue($name) + ); + } + /** * Compile the query to determine if a table exists. * diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index f07946c85e23..b7cff5568d1b 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -4,6 +4,32 @@ class MySqlBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name, $this->connection) + ); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index c249ccf02ebe..4e5e4aecda2e 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -4,6 +4,32 @@ class PostgresBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name, $this->connection) + ); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 78b6b9c78d2e..6a1dbae23ec6 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -2,8 +2,34 @@ namespace Illuminate\Database\Schema; +use Illuminate\Support\Facades\File; + class SQLiteBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return File::put($name, '') !== false; + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return File::exists($name) + ? File::delete($name) + : true; + } + /** * Drop all tables from the database. * diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index 0b3e47bec9a6..223abd44ed1c 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -4,6 +4,32 @@ class SqlServerBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name, $this->connection) + ); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); + } + /** * Drop all tables from the database. * diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index 2f39afd43d36..f5ffb33658f5 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Illuminate\Support\AggregateServiceProvider; use Illuminate\Support\Facades\URL; +use Illuminate\Testing\ParallelTestingServiceProvider; use Illuminate\Validation\ValidationException; class FoundationServiceProvider extends AggregateServiceProvider @@ -16,6 +17,7 @@ class FoundationServiceProvider extends AggregateServiceProvider */ protected $providers = [ FormRequestServiceProvider::class, + ParallelTestingServiceProvider::class, ]; /** diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index b32202517ceb..6bbc653102da 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -7,6 +7,7 @@ use Illuminate\Console\Application as Artisan; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Facade; +use Illuminate\Support\Facades\ParallelTesting; use Illuminate\Support\Str; use Mockery; use Mockery\Exception\InvalidCountException; @@ -81,6 +82,8 @@ protected function setUp(): void if (! $this->app) { $this->refreshApplication(); + + ParallelTesting::callSetUpTestCaseCallbacks($this); } $this->setUpTraits(); @@ -152,6 +155,8 @@ protected function tearDown(): void if ($this->app) { $this->callBeforeApplicationDestroyedCallbacks(); + ParallelTesting::callTearDownTestCaseCallbacks($this); + $this->app->flush(); $this->app = null; diff --git a/src/Illuminate/Support/Facades/ParallelTesting.php b/src/Illuminate/Support/Facades/ParallelTesting.php new file mode 100644 index 000000000000..deed8a1b6aba --- /dev/null +++ b/src/Illuminate/Support/Facades/ParallelTesting.php @@ -0,0 +1,25 @@ +get('filesystems.default'); - (new Filesystem)->cleanDirectory( - $root = storage_path('framework/testing/disks/'.$disk) - ); + $root = storage_path('framework/testing/disks/'.$disk); + + if ($token = ParallelTesting::token()) { + $root = "{$root}_test_{$token}"; + } + + (new Filesystem)->cleanDirectory($root); static::set($disk, $fake = static::createLocalDriver(array_merge($config, [ 'root' => $root, diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php new file mode 100644 index 000000000000..5da0b81bd73e --- /dev/null +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -0,0 +1,162 @@ +whenNotUsingInMemoryDatabase(function ($database) { + if (ParallelTesting::option('recreate_databases')) { + Schema::dropDatabaseIfExists( + $this->testDatabase($database) + ); + } + }); + }); + + ParallelTesting::setUpTestCase(function ($testCase) { + $uses = array_flip(class_uses_recursive(get_class($testCase))); + + $databaseTraits = [ + Testing\DatabaseMigrations::class, + Testing\DatabaseTransactions::class, + Testing\RefreshDatabase::class, + ]; + + if (Arr::hasAny($uses, $databaseTraits)) { + $this->whenNotUsingInMemoryDatabase(function ($database) use ($uses) { + $testDatabase = $this->ensureTestDatabaseExists($database); + + $this->switchToDatabase($testDatabase); + + if (isset($uses[Testing\DatabaseTransactions::class])) { + $this->ensureSchemaIsUpToDate(); + } + }); + } + }); + } + + /** + * Ensure a test database exists and returns its name. + * + * @param string $database + * + * @return string + */ + protected function ensureTestDatabaseExists($database) + { + return tap($this->testDatabase($database), function ($testDatabase) use ($database) { + try { + $this->usingDatabase($testDatabase, function () { + Schema::hasTable('dummy'); + }); + } catch (QueryException $e) { + $this->usingDatabase($database, function () use ($testDatabase) { + Schema::dropDatabaseIfExists($testDatabase); + Schema::createDatabase($testDatabase); + }); + } + }); + } + + /** + * Ensure the current database test schema is up to date. + * + * @return void + */ + protected function ensureSchemaIsUpToDate() + { + if (! static::$schemaIsUpToDate) { + Artisan::call('migrate'); + + static::$schemaIsUpToDate = true; + } + } + + /** + * Runs the given callable using the given database. + * + * @param string $database + * @param callable $database + * @return void + */ + protected function usingDatabase($database, $callable) + { + $original = DB::getConfig('database'); + + try { + $this->switchToDatabase($database); + $callable(); + } finally { + $this->switchToDatabase($original); + } + } + + /** + * Apply the given callback when tests are not using in memory database. + * + * @param callable $callback + * @return void + */ + protected function whenNotUsingInMemoryDatabase($callback) + { + $database = DB::getConfig('database'); + + if ($database != ':memory:') { + $callback($database); + } + } + + /** + * Switch to the given database. + * + * @param string $database + * @return void + */ + protected function switchToDatabase($database) + { + DB::purge(); + + $default = config('database.default'); + + config()->set( + "database.connections.{$default}.database", + $database, + ); + } + + /** + * Returns the test database name. + * + * @return string + */ + protected function testDatabase($database) + { + $token = ParallelTesting::token(); + + return "{$database}_test_{$token}"; + } +} diff --git a/src/Illuminate/Testing/ParallelConsoleOutput.php b/src/Illuminate/Testing/ParallelConsoleOutput.php new file mode 100644 index 000000000000..7444be3b92d7 --- /dev/null +++ b/src/Illuminate/Testing/ParallelConsoleOutput.php @@ -0,0 +1,60 @@ +getVerbosity(), + $output->isDecorated(), + $output->getFormatter(), + ); + + $this->output = $output; + } + + /** + * Writes a message to the output. + * + * @param string|iterable $messages + * @param bool $newline + * @param int $options + * @return void + */ + public function write($messages, bool $newline = false, int $options = 0) + { + $messages = collect($messages)->filter(function ($message) { + return ! Str::contains($message, $this->ignore); + }); + + $this->output->write($messages->toArray(), $newline, $options); + } +} diff --git a/src/Illuminate/Testing/ParallelRunner.php b/src/Illuminate/Testing/ParallelRunner.php new file mode 100644 index 000000000000..e26528703bbe --- /dev/null +++ b/src/Illuminate/Testing/ParallelRunner.php @@ -0,0 +1,140 @@ +options = $options; + + if ($output instanceof ConsoleOutput) { + $output = new ParallelConsoleOutput($output); + } + + $this->runner = new WrapperRunner($options, $output); + } + + /** + * Set the application resolver callback. + * + * @param \Closure|null $resolver + * @return void + */ + public static function resolveApplicationUsing($resolver) + { + static::$applicationResolver = $resolver; + } + + /** + * Runs the test suite. + * + * @return void + */ + public function run(): void + { + (new PhpHandler)->handle($this->options->configuration()->php()); + + $this->forEachProcess(function () { + ParallelTesting::callSetUpProcessCallbacks(); + }); + + try { + $this->runner->run(); + } finally { + $this->forEachProcess(function () { + ParallelTesting::callTearDownProcessCallbacks(); + }); + } + } + + /** + * Returns the highest exit code encountered throughout the course of test execution. + * + * @return int + */ + public function getExitCode(): int + { + return $this->runner->getExitCode(); + } + + /** + * Apply the given callback for each process. + * + * @param callable $callback + * @return void + */ + protected function forEachProcess($callback) + { + collect(range(1, $this->options->processes()))->each(function ($token) use ($callback) { + tap($this->createApplication(), function ($app) use ($callback, $token) { + ParallelTesting::resolveTokenUsing(function () use ($token) { + return $token; + }); + + $callback($app); + })->flush(); + }); + } + + /** + * Creates the application. + * + * @return \Illuminate\Contracts\Foundation\Application + */ + protected function createApplication() + { + $applicationResolver = static::$applicationResolver ?: function () { + $applicationCreator = new class { + use \Tests\CreatesApplication; + }; + + return $applicationCreator->createApplication(); + }; + + return call_user_func($applicationResolver); + } +} diff --git a/src/Illuminate/Testing/ParallelTesting.php b/src/Illuminate/Testing/ParallelTesting.php new file mode 100644 index 000000000000..ba67e16c5c74 --- /dev/null +++ b/src/Illuminate/Testing/ParallelTesting.php @@ -0,0 +1,255 @@ +container = $container; + } + + /** + * Set a callback that should be used when resolving options. + * + * @param \Closure|null $callback + * @return void + */ + public function resolveOptionsUsing($resolver) + { + $this->optionsResolver = $resolver; + } + + /** + * Set a callback that should be used when resolving the unique process token. + * + * @param \Closure|null $callback + * @return void + */ + public function resolveTokenUsing($resolver) + { + $this->tokenResolver = $resolver; + } + + /** + * Register a "setUp" process callback. + * + * @param callable $callback + * @return void + */ + public function setUpProcess($callback) + { + $this->setUpProcessCallbacks[] = $callback; + } + + /** + * Register a "setUp" test case callback. + * + * @param callable $callback + * @return void + */ + public function setUpTestCase($callback) + { + $this->setUpTestCaseCallbacks[] = $callback; + } + + /** + * Register a "tearDown" process callback. + * + * @param callable $callback + * @return void + */ + public function tearDownProcess($callback) + { + $this->tearDownProcessCallbacks[] = $callback; + } + + /** + * Register a "tearDown" test case callback. + * + * @param callable $callback + * @return void + */ + public function tearDownTestCase($callback) + { + $this->tearDownTestCaseCallbacks[] = $callback; + } + + /** + * Call all of the "setUp" process callbacks. + * + * @return void + */ + public function callSetUpProcessCallbacks() + { + $this->whenRunningInParallel(function () { + foreach ($this->setUpProcessCallbacks as $callback) { + $this->container->call($callback, [ + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Call all of the "setUp" test case callbacks. + * + * @param \Illuminate\Foundation\Testing\TestCase $testCase + * @return void + */ + public function callSetUpTestCaseCallbacks($testCase) + { + $this->whenRunningInParallel(function () use ($testCase) { + foreach ($this->setUpTestCaseCallbacks as $callback) { + $this->container->call($callback, [ + 'testCase' => $testCase, + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Call all of the "tearDown" process callbacks. + * + * @return void + */ + public function callTearDownProcessCallbacks() + { + $this->whenRunningInParallel(function () { + foreach ($this->tearDownProcessCallbacks as $callback) { + $this->container->call($callback, [ + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Call all of the "tearDown" test case callbacks. + * + * @param \Illuminate\Foundation\Testing\TestCase $testCase + * @return void + */ + public function callTearDownTestCaseCallbacks($testCase) + { + $this->whenRunningInParallel(function () use ($testCase) { + foreach ($this->tearDownTestCaseCallbacks as $callback) { + $this->container->call($callback, [ + 'testCase' => $testCase, + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Get an parallel testing option. + * + * @param string $option + * @return mixed + */ + public function option($option) + { + $optionsResolver = $this->optionsResolver ?: function ($option) { + $option = 'LARAVEL_PARALLEL_TESTING_'.Str::upper($option); + + return $_SERVER[$option] ?? false; + }; + + return call_user_func($optionsResolver, $option); + } + + /** + * Gets an unique test token. + * + * @return int|false + */ + public function token() + { + return $token = $this->tokenResolver + ? call_user_func($this->tokenResolver) + : ($_SERVER['TEST_TOKEN'] ?? false); + } + + /** + * Apply the callback if tests are running in parallel. + * + * @param callable $callback + * @return void + */ + protected function whenRunningInParallel($callback) + { + if ($this->inParallel()) { + $callback(); + } + } + + /** + * Indicates if the current tests are been run in parallel. + * + * @return bool + */ + protected function inParallel() + { + return ! empty($_SERVER['LARAVEL_PARALLEL_TESTING']) && $this->token(); + } +} diff --git a/src/Illuminate/Testing/ParallelTestingServiceProvider.php b/src/Illuminate/Testing/ParallelTestingServiceProvider.php new file mode 100644 index 000000000000..20b900d2e58e --- /dev/null +++ b/src/Illuminate/Testing/ParallelTestingServiceProvider.php @@ -0,0 +1,38 @@ +app->runningInConsole()) { + $this->bootTestDatabase(); + } + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + if ($this->app->runningInConsole()) { + $this->app->singleton(ParallelTesting::class, function () { + return new ParallelTesting($this->app); + }); + } + } +} diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php new file mode 100755 index 000000000000..04e23eb264be --- /dev/null +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -0,0 +1,37 @@ +expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support creating databases.'); + + $grammar->compileCreateDatabase('foo', m::mock(Connection::class)); + } + + public function testDropDatabaseIfExists() + { + $grammar = new class extends Grammar {}; + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support dropping databases.'); + + $grammar->compileDropDatabaseIfExists('foo'); + } +} diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 3e81cdca0950..ebb190ccb46b 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1149,6 +1149,48 @@ public function testAddingComment() $this->assertSame("alter table `users` add `foo` varchar(255) not null comment 'Escape \\' when using words like it\\'s'", $statements[0]); } + public function testCreateDatabase() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8mb4_foo'); + $connection->shouldReceive('getConfig')->once()->once()->with('collation')->andReturn('utf8mb4_unicode_ci_foo'); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + + $this->assertSame( + 'create database `my_database_a` default character set `utf8mb4_foo` default collate `utf8mb4_unicode_ci_foo`', + $statement + ); + + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8mb4_bar'); + $connection->shouldReceive('getConfig')->once()->once()->with('collation')->andReturn('utf8mb4_unicode_ci_bar'); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + + $this->assertSame( + 'create database `my_database_b` default character set `utf8mb4_bar` default collate `utf8mb4_unicode_ci_bar`', + $statement + ); + } + + public function testDropDatabaseIfExists() + { + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); + + $this->assertSame( + 'drop database if exists `my_database_a`', + $statement + ); + + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); + + $this->assertSame( + 'drop database if exists `my_database_b`', + $statement + ); + } + public function testDropAllTables() { $statement = $this->getGrammar()->compileDropAllTables(['alpha', 'beta', 'gamma']); diff --git a/tests/Database/DatabaseMysqlBuilderTest.php b/tests/Database/DatabaseMysqlBuilderTest.php new file mode 100644 index 000000000000..dd36209eb40e --- /dev/null +++ b/tests/Database/DatabaseMysqlBuilderTest.php @@ -0,0 +1,48 @@ +shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); + $connection->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8mb4_unicode_ci'); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database `my_temporary_database` default character set `utf8mb4` default collate `utf8mb4_unicode_ci`' + )->andReturn(true); + + $builder = new MySqlBuilder($connection); + $builder->createDatabase('my_temporary_database'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new MySqlGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists `my_database_a`' + )->andReturn(true); + + $builder = new MySqlBuilder($connection); + + $builder->dropDatabaseIfExists('my_database_a'); + } +} diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index 54e64e2e54e5..bb5b7a023b64 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -16,6 +16,36 @@ protected function tearDown(): void m::close(); } + public function testCreateDatabase() + { + $grammar = new PostgresGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database "my_temporary_database" encoding "utf8"' + )->andReturn(true); + + $builder = $this->getBuilder($connection); + $builder->createDatabase('my_temporary_database'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new PostgresGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists "my_database_a"' + )->andReturn(true); + + $builder = $this->getBuilder($connection); + + $builder->dropDatabaseIfExists('my_database_a'); + } + /** * Ensure that when the reference is unqualified (i.e., does not contain a * database name or a schema), and the search_path is empty, the database diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index f044eb9b6667..7e10fae23d55 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -997,6 +997,44 @@ public function testAddingMultiPolygon() $this->assertSame('alter table "geo" add column "coordinates" geography(multipolygon, 4326) not null', $statements[0]); } + public function testCreateDatabase() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8_foo'); + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + + $this->assertSame( + 'create database "my_database_a" encoding "utf8_foo"', + $statement + ); + + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8_bar'); + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + + $this->assertSame( + 'create database "my_database_b" encoding "utf8_bar"', + $statement + ); + } + + public function testDropDatabaseIfExists() + { + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); + + $this->assertSame( + 'drop database if exists "my_database_a"', + $statement + ); + + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); + + $this->assertSame( + 'drop database if exists "my_database_b"', + $statement + ); + } + public function testDropAllTablesEscapesTableNames() { $statement = $this->getGrammar()->compileDropAllTables(['alpha', 'beta', 'gamma']); diff --git a/tests/Database/DatabaseSQLiteBuilderTest.php b/tests/Database/DatabaseSQLiteBuilderTest.php new file mode 100644 index 000000000000..b2587ea67d82 --- /dev/null +++ b/tests/Database/DatabaseSQLiteBuilderTest.php @@ -0,0 +1,91 @@ +singleton('files', Filesystem::class); + + Facade::setFacadeApplication($app); + } + + protected function tearDown(): void + { + m::close(); + + Container::setInstance(null); + Facade::setFacadeApplication(null); + } + + public function testCreateDatabase() + { + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once(); + + $builder = new SQLiteBuilder($connection); + + File::shouldReceive('put') + ->once() + ->with('my_temporary_database_a', '') + ->andReturn(20); // bytes + + $this->assertTrue($builder->createDatabase('my_temporary_database_a')); + + File::shouldReceive('put') + ->once() + ->with('my_temporary_database_b', '') + ->andReturn(false); + + $this->assertFalse($builder->createDatabase('my_temporary_database_b')); + } + + public function testDropDatabaseIfExists() + { + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once(); + + $builder = new SQLiteBuilder($connection); + + File::shouldReceive('exists') + ->once() + ->andReturn(true); + + File::shouldReceive('delete') + ->once() + ->with('my_temporary_database_b') + ->andReturn(true); + + $this->assertTrue($builder->dropDatabaseIfExists('my_temporary_database_b')); + + File::shouldReceive('exists') + ->once() + ->andReturn(false); + + $this->assertTrue($builder->dropDatabaseIfExists('my_temporary_database_c')); + + File::shouldReceive('exists') + ->once() + ->andReturn(true); + + File::shouldReceive('delete') + ->once() + ->with('my_temporary_database_c') + ->andReturn(false); + + $this->assertFalse($builder->dropDatabaseIfExists('my_temporary_database_c')); + } +} diff --git a/tests/Database/DatabaseSchemaBuilderTest.php b/tests/Database/DatabaseSchemaBuilderTest.php index 53a13c79128c..b22bfd7dc70e 100755 --- a/tests/Database/DatabaseSchemaBuilderTest.php +++ b/tests/Database/DatabaseSchemaBuilderTest.php @@ -4,6 +4,7 @@ use Illuminate\Database\Connection; use Illuminate\Database\Schema\Builder; +use LogicException; use Mockery as m; use PHPUnit\Framework\TestCase; use stdClass; @@ -15,6 +16,32 @@ protected function tearDown(): void m::close(); } + public function testCreateDatabase() + { + $connection = m::mock(Connection::class); + $grammar = m::mock(stdClass::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $builder = new Builder($connection); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support creating databases.'); + + $builder->createDatabase('foo'); + } + + public function testDropDatabaseIfExists() + { + $connection = m::mock(Connection::class); + $grammar = m::mock(stdClass::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $builder = new Builder($connection); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support dropping databases.'); + + $builder->dropDatabaseIfExists('foo'); + } + public function testHasTableCorrectlyCallsGrammar() { $connection = m::mock(Connection::class); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index acb2ed68367e..4513a93001a3 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -914,6 +914,42 @@ public function testQuoteStringOnArray() $this->assertSame("N'中文', N'測試'", $this->getGrammar()->quoteString(['中文', '測試'])); } + public function testCreateDatabase() + { + $connection = $this->getConnection(); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + + $this->assertSame( + 'create database "my_database_a"', + $statement + ); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + + $this->assertSame( + 'create database "my_database_b"', + $statement + ); + } + + public function testDropDatabaseIfExists() + { + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); + + $this->assertSame( + 'drop database if exists "my_database_a"', + $statement + ); + + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); + + $this->assertSame( + 'drop database if exists "my_database_b"', + $statement + ); + } + protected function getConnection() { return m::mock(Connection::class); diff --git a/tests/Database/SqlServerBuilderTest.php b/tests/Database/SqlServerBuilderTest.php new file mode 100644 index 000000000000..de82f796056c --- /dev/null +++ b/tests/Database/SqlServerBuilderTest.php @@ -0,0 +1,46 @@ +shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database "my_temporary_database_a"' + )->andReturn(true); + + $builder = new SqlServerBuilder($connection); + $builder->createDatabase('my_temporary_database_a'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new SqlServerGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists "my_temporary_database_b"' + )->andReturn(true); + + $builder = new SqlServerBuilder($connection); + + $builder->dropDatabaseIfExists('my_temporary_database_b'); + } +} diff --git a/tests/Testing/ParallelConsoleOutputTest.php b/tests/Testing/ParallelConsoleOutputTest.php new file mode 100644 index 000000000000..130b6ecada6a --- /dev/null +++ b/tests/Testing/ParallelConsoleOutputTest.php @@ -0,0 +1,25 @@ +write('Running phpunit in 12 processes with laravel/laravel.'); + $this->assertEmpty($original->fetch()); + + $output->write('Configuration read from phpunit.xml.dist'); + $this->assertEmpty($original->fetch()); + + $output->write('... 3/3 (100%)'); + $this->assertSame('... 3/3 (100%)', $original->fetch()); + } +} diff --git a/tests/Testing/ParallelTestingTest.php b/tests/Testing/ParallelTestingTest.php new file mode 100644 index 000000000000..25d41f7f1b5c --- /dev/null +++ b/tests/Testing/ParallelTestingTest.php @@ -0,0 +1,99 @@ +{$caller}($this); + $this->assertFalse($state); + + $parallelTesting->{$callback}(function ($token, $testCase = null) use ($callback, &$state) { + if (in_array($callback, ['setUpTestCase', 'tearDownTestCase'])) { + $this->assertSame($this, $testCase); + } else { + $this->assertNull($testCase); + } + + $this->assertEquals(1, $token); + $state = true; + }); + + $parallelTesting->{$caller}($this); + $this->assertFalse($state); + + $parallelTesting->resolveTokenUsing(function () { + return 1; + }); + + $parallelTesting->{$caller}($this); + $this->assertTrue($state); + } + + public function testOptions() + { + $parallelTesting = new ParallelTesting(Container::getInstance()); + + $this->assertFalse($parallelTesting->option('recreate_databases')); + + $parallelTesting->resolveOptionsUsing(function ($option) { + return $option == 'recreate_databases'; + }); + + $this->assertFalse($parallelTesting->option('recreate_caches')); + $this->assertTrue($parallelTesting->option('recreate_databases')); + } + + public function testToken() + { + $parallelTesting = new ParallelTesting(Container::getInstance()); + + $this->assertFalse($parallelTesting->token()); + + $parallelTesting->resolveTokenUsing(function () { + return 1; + }); + + $this->assertSame(1, $parallelTesting->token()); + } + + public function callbacks() + { + return [ + ['setUpProcess'], + ['setUpTestCase'], + ['tearDownTestCase'], + ['tearDownProcess'], + ]; + } + + public function tearDown(): void + { + parent::tearDown(); + + Container::setInstance(null); + + unset($_SERVER['LARAVEL_PARALLEL_TESTING']); + } +} From 10ab29e436b1a259cae1e20ceaa75a41af688249 Mon Sep 17 00:00:00 2001 From: Mo Khosh Date: Mon, 18 Jan 2021 19:33:17 +0330 Subject: [PATCH 085/194] [9.x] Remove reduceWithKeys and merge the functionality with reduce (#35901) * remove reduce from LazyCollection * remove reduce from Collection * add reduce to EnumeratesValues * move tap method a bit down to its alphabetically correct place * add test for reduce with keys * Remove testReduceWithKeys we don't have the method anymore so we're not testing it --- src/Illuminate/Collections/Collection.php | 30 ---------------- src/Illuminate/Collections/LazyCollection.php | 36 ------------------- .../Collections/Traits/EnumeratesValues.php | 28 ++++++++++++--- tests/Support/SupportCollectionTest.php | 12 ++----- 4 files changed, 26 insertions(+), 80 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 6a8ab88818aa..e4549d03ed11 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -872,36 +872,6 @@ public function random($number = null) return new static(Arr::random($this->items, $number)); } - /** - * Reduce the collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduce(callable $callback, $initial = null) - { - return array_reduce($this->items, $callback, $initial); - } - - /** - * Reduce an associative collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduceWithKeys(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this->items as $key => $value) { - $result = $callback($result, $value, $key); - } - - return $result; - } - /** * Replace the collection items with the given items. * diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index ca51626b071e..650213133ced 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -827,42 +827,6 @@ public function random($number = null) return is_null($number) ? $result : new static($result); } - /** - * Reduce the collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduce(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this as $value) { - $result = $callback($result, $value); - } - - return $result; - } - - /** - * Reduce an associative collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduceWithKeys(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this as $key => $value) { - $result = $callback($result, $value, $key); - } - - return $result; - } - /** * Replace the collection items with the given items. * diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 3355a9b2da29..61257390e004 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -704,16 +704,21 @@ public function pipeInto($class) } /** - * Pass the collection to the given callback and then return it. + * Reduce the collection to a single value. * * @param callable $callback - * @return $this + * @param mixed $initial + * @return mixed */ - public function tap(callable $callback) + public function reduce(callable $callback, $initial = null) { - $callback(clone $this); + $result = $initial; - return $this; + foreach ($this as $key => $value) { + $result = $callback($result, $value, $key); + } + + return $result; } /** @@ -733,6 +738,19 @@ public function reject($callback = true) }); } + /** + * Pass the collection to the given callback and then return it. + * + * @param callable $callback + * @return $this + */ + public function tap(callable $callback) + { + $callback(clone $this); + + return $this; + } + /** * Return only unique items from the collection array. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index b622884fe6c1..602805781bda 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3590,18 +3590,12 @@ public function testReduce($collection) $this->assertEquals(6, $data->reduce(function ($carry, $element) { return $carry += $element; })); - } - /** - * @dataProvider collectionClassProvider - */ - public function testReduceWithKeys($collection) - { $data = new $collection([ - 'foo' => 'bar', - 'baz' => 'qux', + 'foo' => 'bar', 'foo' => 'bar', + 'baz' => 'qux', 'baz' => 'qux', ]); - $this->assertEquals('foobarbazqux', $data->reduceWithKeys(function ($carry, $element, $key) { + $this->assertEquals('foobarbazqux', $data->reduce(function ($carry, $element, $key) { return $carry .= $key.$element; })); } From b9624ab7b3b3994a5e962d0f468fcf6c45a198d7 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 19 Jan 2021 20:01:18 +0100 Subject: [PATCH 086/194] Consolidate CHANGELOG.md for 9.x (#35943) --- CHANGELOG-6.x.md | 1015 ---------------------------------------------- CHANGELOG-8.x.md | 569 -------------------------- CHANGELOG.md | 8 + 3 files changed, 8 insertions(+), 1584 deletions(-) delete mode 100644 CHANGELOG-6.x.md delete mode 100644 CHANGELOG-8.x.md create mode 100644 CHANGELOG.md diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md deleted file mode 100644 index 3ab00165cccc..000000000000 --- a/CHANGELOG-6.x.md +++ /dev/null @@ -1,1015 +0,0 @@ -# Release Notes for 6.x - -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.10...6.x) - - -## [v6.20.10 (2021-01-12)](https://github.com/laravel/framework/compare/v6.20.9...v6.20.10) - -### Added -- Added new line to `DetectsLostConnections` ([#35790](https://github.com/laravel/framework/pull/35790)) - -### Fixed -- Fixed error from missing null check on PHP 8 in `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` ([#35797](https://github.com/laravel/framework/pull/35797)) - - -## [v6.20.9 (2021-01-05)](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) - -### Added -- [Updated Illuminate\Database\DetectsLostConnections with new strings](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) - - -## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) - -### Fixed -- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) -- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) - - -## [v6.20.7 (2020-12-08)](https://github.com/laravel/framework/compare/v6.20.6...v6.20.7) - -### Fixed -- Backport for fix issue with polymorphic morphMaps with literal 0 ([#35487](https://github.com/laravel/framework/pull/35487)) -- Fixed mime validation for jpeg files ([#35518](https://github.com/laravel/framework/pull/35518)) - - -## [v6.20.6 (2020-12-01)](https://github.com/laravel/framework/compare/v6.20.5...v6.20.6) - -### Fixed -- Backport Redis context option ([#35370](https://github.com/laravel/framework/pull/35370)) -- Fixed validating image/jpeg images after Symfony/Mime update ([#35419](https://github.com/laravel/framework/pull/35419)) - - -## [v6.20.5 (2020-11-24)](https://github.com/laravel/framework/compare/v6.20.4...v6.20.5) - -### Fixed -- Fixing BroadcastException message in PusherBroadcaster@broadcast ([#35290](https://github.com/laravel/framework/pull/35290)) -- Fixed generic DetectsLostConnection string ([#35323](https://github.com/laravel/framework/pull/35323)) - -### Changed -- Updated `aws/aws-sdk-php` suggest to `^3.155` ([#35267](https://github.com/laravel/framework/pull/35267)) - - -## [v6.20.4 (2020-11-17)](https://github.com/laravel/framework/compare/v6.20.3...v6.20.4) - -### Fixed -- Fixed pivot restoration ([#35218](https://github.com/laravel/framework/pull/35218)) - - -## [v6.20.3 (2020-11-10)](https://github.com/laravel/framework/compare/v6.20.2...v6.20.3) - -### Fixed -- Turn the eloquent collection into a base collection if mapWithKeys loses models ([#35129](https://github.com/laravel/framework/pull/35129)) - - -## [v6.20.2 (2020-10-29)](https://github.com/laravel/framework/compare/v6.20.1...v6.20.2) - -### Fixed -- [Add some fixes](https://github.com/laravel/framework/compare/v6.20.1...v6.20.2) - - -## [v6.20.1 (2020-10-29)](https://github.com/laravel/framework/compare/v6.20.0...v6.20.1) - -### Fixed -- Fixed alias usage in `Eloquent` ([6091048](https://github.com/laravel/framework/commit/609104806b8b639710268c75c22f43034c2b72db)) -- Fixed `Illuminate\Support\Reflector::isCallable()` ([a90f344](https://github.com/laravel/framework/commit/a90f344c66f0a5bb1d718f8bbd20c257d4de9e02)) - - -## [v6.20.0 (2020-10-28)](https://github.com/laravel/framework/compare/v6.19.1...v6.20.0) - -### Added -- Full PHP 8.0 Support ([#33388](https://github.com/laravel/framework/pull/33388)) -- Added `Illuminate\Support\Reflector::isCallable()` ([#34994](https://github.com/laravel/framework/pull/34994), [8c16891](https://github.com/laravel/framework/commit/8c16891c6e7a4738d63788f4447614056ab5136e), [31917ab](https://github.com/laravel/framework/commit/31917abcfa0db6ec6221bb07fc91b6e768ff5ec8), [11cfa4d](https://github.com/laravel/framework/commit/11cfa4d4c92bf2f023544d58d51b35c5d31dece0), [#34999](https://github.com/laravel/framework/pull/34999)) - -### Changed -- Bump minimum PHP version to v7.2.5 ([#34928](https://github.com/laravel/framework/pull/34928)) - -### Fixed -- Fixed ambigious column on many to many with select load ([5007986](https://github.com/laravel/framework/commit/500798623d100a9746b2931ae6191cb756521f05)) - - -## [v6.19.1 (2020-10-20)](https://github.com/laravel/framework/compare/v6.19.0...v6.19.1) - -### Fixed -- Fixed `bound()` method ([a7759d7](https://github.com/laravel/framework/commit/a7759d70e15b0be946569b8299ac694c08a35d7e)) - - -## [v6.19.0 (2020-10-20)](https://github.com/laravel/framework/compare/v6.18.43...v6.19.0) - -### Added -- Provisional support for PHP 8.0 ([#34884](https://github.com/laravel/framework/pull/34884), [28bb76e](https://github.com/laravel/framework/commit/28bb76efbcfc5fee57307ffa062b67ff709240dc)) - - -## [v6.18.43 (2020-10-13)](https://github.com/laravel/framework/compare/v6.18.42...v6.18.43) - -### Fixed -- Matched `symfony/debug` version with other symfony reqs ([6ce02a2](https://github.com/laravel/framework/commit/6ce02a21cf736f28beda2529d1e28849e86b0944)) - - -## [v6.18.42 (2020-10-06)](https://github.com/laravel/framework/compare/v6.18.41...v6.18.42) - -### Fixed -- Added missed RESET_THROTTLED constant to Password Facade ([#34641](https://github.com/laravel/framework/pull/34641)) - - -## [v6.18.41 (2020-09-29)](https://github.com/laravel/framework/compare/v6.18.40...v6.18.41) - -### Fixed -- Added support for stream reads in FileManager for S3 driver ([#34480](https://github.com/laravel/framework/pull/34480)) - - -## [v6.18.40 (2020-09-09)](https://github.com/laravel/framework/compare/v6.18.39...v6.18.40) - -### Revert -- Revert of ["Fixed for empty fallback_locale in `Illuminate\Translation\Translator`"](https://github.com/laravel/framework/pull/34136) ([7c54eb6](https://github.com/laravel/framework/commit/7c54eb678d58fb9ee7f532a5a5842e6f0e1fe4c9)) - - -## [v6.18.39 (2020-09-08)](https://github.com/laravel/framework/compare/v6.18.38...v6.18.39) - -### Fixed -- Fixed for empty fallback_locale in `Illuminate\Translation\Translator` ([#34136](https://github.com/laravel/framework/pull/34136)) - - -## [v6.18.38 (2020-09-01)](https://github.com/laravel/framework/compare/v6.18.37...v6.18.38) - -### Changed -- Changed postgres processor ([#34055](https://github.com/laravel/framework/pull/34055)) - - -## [v6.18.37 (2020-08-27)](https://github.com/laravel/framework/compare/v6.18.36...v6.18.37) - -### Fixed -- Fixed offset error on invalid remember token ([#34020](https://github.com/laravel/framework/pull/34020)) -- Only prepend scheme to PhpRedis host when necessary ([#34017](https://github.com/laravel/framework/pull/34017)) -- Fixed `whereKey` and `whereKeyNot` in `Illuminate\Database\Eloquent\Builder` ([#34031](https://github.com/laravel/framework/pull/34031)) - - -## [v6.18.36 (2020-08-25)](https://github.com/laravel/framework/compare/v6.18.35...v6.18.36) - -### Fixed -- Fix dimension ratio calculation in `Illuminate\Validation\Concerns\ValidatesAttributes::failsRatioCheck()` ([#34003](https://github.com/laravel/framework/pull/34003)) - -### Changed -- Normalize scheme in Redis connections ([#33892](https://github.com/laravel/framework/pull/33892)) -- Check no-interaction flag exists and is true for Artisan commands ([#33950](https://github.com/laravel/framework/pull/33950)) - - -## [v6.18.35 (2020-08-07)](https://github.com/laravel/framework/compare/v6.18.34...v6.18.35) - -### Changed -- Verify column names are actual columns when using guarded ([#33777](https://github.com/laravel/framework/pull/33777)) - - -## [v6.18.34 (2020-08-06)](https://github.com/laravel/framework/compare/v6.18.33...v6.18.34) - -### Fixed -- Fixed `Illuminate\Support\Arr::query()` ([c6f9ae2](https://github.com/laravel/framework/commit/c6f9ae2b6fdc3c1716938223de731b97f6a5a255)) -- Don't allow mass filling with table names ([9240404](https://github.com/laravel/framework/commit/9240404b22ef6f9e827577b3753e4713ddce7471), [f5fa6e3](https://github.com/laravel/framework/commit/f5fa6e3a0fbf9a93eab45b9ae73265b4dbfc3ad7)) - - -## [v6.18.33 (2020-08-06)](https://github.com/laravel/framework/compare/v6.18.32...v6.18.33) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Concerns\GuardsAttributes::isGuarded()` ([1b70bef](https://github.com/laravel/framework/commit/1b70bef5fd7cc5da74abcdf79e283f830fa3b0a4), [624d873](https://github.com/laravel/framework/commit/624d873733388aa2246553a3b465e38554953180), [b70876a](https://github.com/laravel/framework/commit/b70876ac80759fbf168c91cdffd7a2b2305e27cb)) -- Fixed escaping quotes ([687df01](https://github.com/laravel/framework/commit/687df01fa19c99546c1ae1dd53c2a465459b50dc)) - - -## [v6.18.32 (2020-08-04)](https://github.com/laravel/framework/compare/v6.18.31...v6.18.32) - -### Changed -- Ignore numeric field names in validators ([#33712](https://github.com/laravel/framework/pull/33712)) -- Fixed validation rule 'required_unless' when other field value is boolean. ([#33715](https://github.com/laravel/framework/pull/33715)) - - -## [v6.18.31 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.30...v6.18.31) - -### Update -- Update cookies encryption ([release](https://github.com/laravel/framework/compare/v6.18.30...v6.18.31)) - - -## [v6.18.30 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.29...v6.18.30) - -### Update -- Update cookies encryption ([release](https://github.com/laravel/framework/compare/v6.18.29...v6.18.30)) - - -## [v6.18.29 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.28...v6.18.29) - -### Fixed -- Fixed cookie issues encryption ([c9ce261](https://github.com/laravel/framework/commit/c9ce261a9f7b8e07c9ebc8a7d45651ee1cf86215), [5786aa4](https://github.com/laravel/framework/commit/5786aa4a388adfcc62862573275bd37d49aa07d7)) - - -## [v6.18.28 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.27...v6.18.28) - -### Fixed -- Fixed cookie issues ([bb9db21](https://github.com/laravel/framework/commit/bb9db21af137344feffa192fcabe4e439c8b0f60)) - - -## [v6.18.27 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.26...v6.18.27) - -### Fixed -- Don't decrement transaction below 0 in `Illuminate\Database\Concerns\ManagesTransactions::handleCommitTransactionException()` ([7681795](https://github.com/laravel/framework/commit/768179578e5492b5f80c391bd43b233938e16e27)) -- Fixed transaction problems on closure transaction ([c4cdfc7](https://github.com/laravel/framework/commit/c4cdfc7c54127b772ef10f37cfc9ef8e9d6b3227)) -- Prevent to serialize uninitialized properties ([#33644](https://github.com/laravel/framework/pull/33644)) -- Fixed missing statement preventing deletion in `Illuminate\Database\Eloquent\Relations\MorphPivot::delete()` ([#33648](https://github.com/laravel/framework/pull/33648)) - -### Changed -- Improve cookie encryption ([#33662](https://github.com/laravel/framework/pull/33662)) - - -## [v6.18.26 (2020-07-21)](https://github.com/laravel/framework/compare/v6.18.25...v6.18.26) - -### Fixed -- Align (fix) nested arrays support for `assertViewHas` & `assertViewMissing` in `Illuminate\Testing\TestResponse` ([#33566](https://github.com/laravel/framework/pull/33566)) - - -## [v6.18.25 (2020-07-10)](https://github.com/laravel/framework/compare/v6.18.24...v6.18.25) - -### Fixed -- Fixed `Illuminate\Cache\FileStore::flush()` ([#33458](https://github.com/laravel/framework/pull/33458)) -- Fixed auto creating model by class name ([#33481](https://github.com/laravel/framework/pull/33481)) -- Don't return nested data from validator when failing an exclude rule ([#33435](https://github.com/laravel/framework/pull/33435)) -- Fixed validation nested error messages ([6615371](https://github.com/laravel/framework/commit/6615371d7c0a7431372244d21eae54696b3c19f2)) -- Fixed `Illuminate\Support\Reflector` to handle parent ([#33502](https://github.com/laravel/framework/pull/33502)) - -### Revert -- Revert [Improve SQL Server last insert id retrieval](https://github.com/laravel/framework/pull/33453) ([#33496](https://github.com/laravel/framework/pull/33496)) - - -## [v6.18.24 (2020-07-07)](https://github.com/laravel/framework/compare/v6.18.23...v6.18.24) - -### Fixed -- Fixed notifications database channel for anonymous notifiables ([#33409](https://github.com/laravel/framework/pull/33409)) -- Added float comparison null checks ([#33421](https://github.com/laravel/framework/pull/33421)) -- Improve SQL Server last insert id retrieval ([#33453](https://github.com/laravel/framework/pull/33453)) - - -## [v6.18.23 (2020-06-30)](https://github.com/laravel/framework/compare/v6.18.22...v6.18.23) - -### Fixed -- Fixed `ConfigurationUrlParser` query decoding ([#33340](https://github.com/laravel/framework/pull/33340)) -- Correct implementation of float casting comparison ([#33322](https://github.com/laravel/framework/pull/33322)) - - -## [v6.18.22 (2020-06-24)](https://github.com/laravel/framework/compare/v6.18.21...v6.18.22) - -### Revert -- Revert "Fixed `Model::originalIsEquivalent()` with floats ([#33259](https://github.com/laravel/framework/pull/33259), [d68d915](https://github.com/laravel/framework/commit/d68d91516db6d1b9cba8a72f99b2c7e8223e988f))" [bf3cb6f](https://github.com/laravel/framework/commit/bf3cb6f6979df2d6965d2e0aa731724d0e2b15e5) - - -## [v6.18.21 (2020-06-23)](https://github.com/laravel/framework/compare/v6.18.20...v6.18.21) - -### Fixed -- Fixed `Model::originalIsEquivalent()` with floats ([#33259](https://github.com/laravel/framework/pull/33259), [d68d915](https://github.com/laravel/framework/commit/d68d91516db6d1b9cba8a72f99b2c7e8223e988f)) - - -## [v6.18.20 (2020-06-16)](https://github.com/laravel/framework/compare/v6.18.19...v6.18.20) - -### Changed -- Improved the reflector ([#33184](https://github.com/laravel/framework/pull/33184)) - - -## [v6.18.19 (2020-06-09)](https://github.com/laravel/framework/compare/v6.18.18...v6.18.19) - -### Fixed -- Fixed `Model::withoutEvents()` not registering listeners inside boot() ([#33149](https://github.com/laravel/framework/pull/33149), [4bb32ae](https://github.com/laravel/framework/commit/4bb32aea50eec4c3cc8b77f463e4a96213a0af09)) - - -## [v6.18.18 (2020-06-03)](https://github.com/laravel/framework/compare/v6.18.17...v6.18.18) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Relations\MorphToMany::getCurrentlyAttachedPivots()` ([110b129](https://github.com/laravel/framework/commit/110b129531df172f03bf163f561c71123fac6296)) - - -## [v6.18.17 (2020-06-02)](https://github.com/laravel/framework/compare/v6.18.16...v6.18.17) - -### Added -- Support PHP 8's reflection API ([#33039](https://github.com/laravel/framework/pull/33039)) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Collection::getQueueableRelations()` ([00e9ed7](https://github.com/laravel/framework/commit/00e9ed76483ea6ad1264676e7b1095b23e16a433)) -- Fixed bug with update existing pivot and polymorphic many to many ([684208b](https://github.com/laravel/framework/commit/684208b10460b49fa34354cc42f33b9b7135814f)) - - -## [v6.18.15 (2020-05-19)](https://github.com/laravel/framework/compare/v6.18.14...v6.18.15) - -### Added -- Added `Illuminate\Http\Middleware\TrustHosts` ([9229264](https://github.com/laravel/framework/commit/92292649621f2aadc84ab94376244650a9f55696)) - -### Fixed -- Revert of ["Remove `strval` from `Illuminate/Validation/ValidationRuleParser::explodeWildcardRules()`"](https://github.com/laravel/framework/commit/1c76a6f3a80fa8f756740566dffd9fa1be65c123) ([52940cf](https://github.com/laravel/framework/commit/52940cf3275cfebd47ec008fd8ae5bc6d6a42dfd)) -- Fixed Queued Mail MessageSent Listener With Attachments ([#32795](https://github.com/laravel/framework/pull/32795)) -- Added error clearing before sending in `Illuminate\Mail\Mailer::sendSwiftMessage()` ([#32799](https://github.com/laravel/framework/pull/32799)) -- Avoid foundation function call in the auth component ([#32805](https://github.com/laravel/framework/pull/32805)) - -### Changed -- Added explicit `symfony/polyfill-php73` dependency ([5796b1e](https://github.com/laravel/framework/commit/5796b1e43dfe14914050a7e5dd24ddf803ec99b8)) -- Set `Cache\FileStore` file permissions only once ([#32845](https://github.com/laravel/framework/pull/32845), [11c533b](https://github.com/laravel/framework/commit/11c533b9aa062f4cba1dd0fe3673bf33d275480f)) - - -## [v6.18.14 (2020-05-12)](https://github.com/laravel/framework/compare/v6.18.13...v6.18.14) - -### Added -- Added SSL SYSCALL EOF as a lost connection message ([#32697](https://github.com/laravel/framework/pull/32697)) - -### Fixed -- Fixed `FakerGenerator` Unique caching issue ([#32703](https://github.com/laravel/framework/pull/32703)) -- Added boolean to types that don't need character options ([#32716](https://github.com/laravel/framework/pull/32716)) -- Fixed `Illuminate\Foundation\Testing\PendingCommand` that do not resolve 'OutputStyle::class' from the container ([#32687](https://github.com/laravel/framework/pull/32687)) -- Clear resolved event facade on `Illuminate\Foundation\Testing\Concerns\MocksApplicationServices::withoutEvents()` ([d1e7f85](https://github.com/laravel/framework/commit/d1e7f85dfd79abbe4f5e01818f620f6ecc67de4d)) -- Fixed deprecated "Doctrine/Common/Inflector/Inflector" class ([#32734](https://github.com/laravel/framework/pull/32734)) - -### Changed -- Remove the undocumented dot keys support in validators ([#32764](https://github.com/laravel/framework/pull/32764)) -- Remove `strval` from `Illuminate/Validation/ValidationRuleParser::explodeWildcardRules()` [1c76a6f](https://github.com/laravel/framework/commit/1c76a6f3a80fa8f756740566dffd9fa1be65c123) - - -## [v6.18.13 (2020-05-05)](https://github.com/laravel/framework/compare/v6.18.12...v6.18.13) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Collection::getQueueableRelations()` ([7b32460](https://github.com/laravel/framework/commit/7b32469420258e9e52b24b2ffa7f491e79a3a870)) - - -## [v6.18.12 (2020-05-05)](https://github.com/laravel/framework/compare/v6.18.11...v6.18.12) - -### Added -- Add pdo try again as lost connection message ([#32605](https://github.com/laravel/framework/pull/32605)) - -### Fixed -- Fixed `Illuminate\Foundation\Testing\TestResponse::assertSessionHasInput()` ([f0639fd](https://github.com/laravel/framework/commit/f0639fda45fc2874986fe409d944dde21d42c6f3)) -- Set relation connection on eager loaded MorphTo ([#32602](https://github.com/laravel/framework/pull/32602)) -- Fixed `Illuminate\Database\Schema\Grammars\SqlServerGrammar::compileDropDefaultConstraint()` was ignoring Table prefixes ([#32606](https://github.com/laravel/framework/pull/32606)) -- Filtering null's in `hasMorph()` ([#32614](https://github.com/laravel/framework/pull/32614)) -- Fixed `Illuminate\Console\Scheduling\Schedule::compileParameters()` ([cfc3ac9](https://github.com/laravel/framework/commit/cfc3ac9c8b0a593d264ae722ab90601fa4882d0e), [36e215d](https://github.com/laravel/framework/commit/36e215dd39cd757a8ffc6b17794de60476b2289d)) -- Fixed bug with model name in `Illuminate\Database\Eloquent\RelationNotFoundException::make()` ([f72a166](https://github.com/laravel/framework/commit/f72a1662ab64cc543c532941b1ab1279001af8e9)) -- Fixed `Illuminate\Foundation\Testing\TestResponse::assertJsonCount()` not accepting falsey keys ([#32655](https://github.com/laravel/framework/pull/32655)) - -### Changed -- Changed `Illuminate/Database/Eloquent/Relations/Concerns/AsPivot::fromRawAttributes()` ([6c502c1](https://github.com/laravel/framework/commit/6c502c1135082e8b25f2720931b19d36eeec8f41)) -- Restore оnly common relations ([#32613](https://github.com/laravel/framework/pull/32613), [d82f78b](https://github.com/laravel/framework/commit/d82f78b13631c4a04b9595099da0022ca3d8b94e), [48e4d60](https://github.com/laravel/framework/commit/48e4d602d4f8fe9304e8998c5893206f67504dbf)) -- Use single space if plain email is empty in `Illuminate\Mail\Mailer::addContent()` ([0557622](https://github.com/laravel/framework/commit/055762286132d545cbc064dce645562c0d51532f)) -- Remove wasted file read when loading package manifest in `Illuminate\Foundation\PackageManifest::getManifest()` ([#32646](https://github.com/laravel/framework/pull/32646)) -- Cache `FakerGenerator` instances ([#32585](https://github.com/laravel/framework/pull/32585)) -- Do not change `character` and `collation` for some columns on change ([fccdf7c](https://github.com/laravel/framework/commit/fccdf7c42d5ceb50985b3e8243d7ba650de996d6)) - - -## [v6.18.11 (2020-04-28)](https://github.com/laravel/framework/compare/v6.18.10...v6.18.11) - -### Fixed -- Auth with each master on flushdb ([d0afa58](https://github.com/laravel/framework/commit/d0afa5846ca1d85ca07cdb580d3b9e9768ebdf41)) -- Clear resolved facades earlier ([f2ea1a2](https://github.com/laravel/framework/commit/f2ea1a23fdac94d3f0818e7ff514fbaed3f45643)) -- Register opis key so it is not tied to a deferred service provider ([a4574ea](https://github.com/laravel/framework/commit/a4574ea973bab9bd6a2ba34d36dfb8f9b55d5a4a)) -- Pass status code to schedule finish ([b815dc6](https://github.com/laravel/framework/commit/b815dc6c1b1c595f3241c493255f0fbfd67a6131)) -- Fix firstWhere behavior for relations ([#32525](https://github.com/laravel/framework/pull/32525)) -- Fixed boolean value in `Illuminate\Foundation\Testing\TestResponse::assertSessionHasErrors()` ([#32555](https://github.com/laravel/framework/pull/32555)) - - -## [v6.18.10 (2020-04-21)](https://github.com/laravel/framework/compare/v6.18.9...v6.18.10) - -### Fixed -- Check if object ([1b0bdb4](https://github.com/laravel/framework/commit/1b0bdb43062a2792befe6fd754140124a8e4dc35)) - - -## [v6.18.9 (2020-04-21)](https://github.com/laravel/framework/compare/v6.18.8...v6.18.9) - -### Fixed -- Fix `refresh()` to support `AsPivot` trait ([#32420](https://github.com/laravel/framework/pull/32420)) -- Fix orderBy with callable ([#32471](https://github.com/laravel/framework/pull/32471)) - - -## [v6.18.8 (2020-04-15)](https://github.com/laravel/framework/compare/v6.18.7...v6.18.8) - -### Fixed -- Removed dots ([e78d24f](https://github.com/laravel/framework/commit/e78d24f31b84cd81c30b5d8837731d77ec089761)) -- Duplicated mailable in-memory data attachments with different names ([#32392](https://github.com/laravel/framework/pull/32392)) -- Fix a regression caused by #32315 ([#32388](https://github.com/laravel/framework/pull/32388)) -- Duplicated mailable storage attachments with different names ([#32394](https://github.com/laravel/framework/pull/32394)) - - -## [v6.18.7 (2020-04-14)](https://github.com/laravel/framework/compare/v6.18.6...v6.18.7) - -### Fixed -- Call setlocale ([1c6a504](https://github.com/laravel/framework/commit/1c6a50424c5558782a55769a226ab834484282e1)) -- Use a map to prevent unnecessary array access ([#32296](https://github.com/laravel/framework/pull/32296)) -- Prevent timestamp update when pivot is not dirty ([#32311](https://github.com/laravel/framework/pull/32311)) -- Add support for the new composer installed.json format ([#32310](https://github.com/laravel/framework/pull/32310)) -- ValidatesAttributes::validateUrl use Symfony/Validator 5.0.7 regex ([#32315](https://github.com/laravel/framework/pull/32315)) -- Fix *scan methods for phpredis ([#32336](https://github.com/laravel/framework/pull/32336)) -- Use the router for absolute urls ([#32345](https://github.com/laravel/framework/pull/32345)) - - -## [v6.18.6 (2020-04-08)](https://github.com/laravel/framework/compare/v6.18.5...v6.18.6) - -### Security -- Prevent insecure characters in locale ([c248521](https://github.com/laravel/framework/commit/c248521f502c74c6cea7b0d221639d4aa752d5db)) - - -## [v6.18.5 (2020-04-07)](https://github.com/laravel/framework/compare/v6.18.4...v6.18.5) - -### Fixed -- Revert "Fix setting mail header" ([#32278](https://github.com/laravel/framework/pull/32278)) - - -## [v6.18.4 (2020-04-07)](https://github.com/laravel/framework/compare/v6.18.3...v6.18.4) - -### Fixed -- Added missing return in the sendNow pending mail fake ([#32095](https://github.com/laravel/framework/pull/32095)) -- Prevent long URLs from breaking email layouts ([#32189](https://github.com/laravel/framework/pull/32189)) -- Fix setting mail header ([#32272](https://github.com/laravel/framework/pull/32272)) - - -## [v6.18.3 (2020-03-24)](https://github.com/laravel/framework/compare/v6.18.2...v6.18.3) - -### Fixed -- Corrected suggested dependencies ([#32072](https://github.com/laravel/framework/pull/32072), [c01a70e](https://github.com/laravel/framework/commit/c01a70e33198e81d06d4b581e36e25a80acf8a68)) -- Avoid deadlock in test when sharing process group ([#32067](https://github.com/laravel/framework/pull/32067)) - - -## [v6.18.2 (2020-03-17)](https://github.com/laravel/framework/compare/v6.18.1...v6.18.2) - -### Fixed -- Fixed scheduler dependency assumptions ([#31894](https://github.com/laravel/framework/pull/31894)) -- Corrected suggested dependencies ([bb0ec42](https://github.com/laravel/framework/commit/bb0ec42b5a55b3ebf3a5a35cc6df01eec290dfa9)) -- Unset `pivotParent` on `Pivot::unsetRelations()` ([#31956](https://github.com/laravel/framework/pull/31956)) -- Fixed `cookie` helper signature , matching match `CookieFactory` ([#31974](https://github.com/laravel/framework/pull/31974)) - - -## [v6.18.1 (2020-03-10)](https://github.com/laravel/framework/compare/v6.18.0...v6.18.1) - -### Fixed -- Fixed array lock release behavior ([#31795](https://github.com/laravel/framework/pull/31795)) -- Fixed model restoring right after being soft deleting ([#31719](https://github.com/laravel/framework/pull/31719)) -- Fixed phpredis "zadd" and "exists" on cluster ([#31838](https://github.com/laravel/framework/pull/31838)) -- Fixed "srid" mysql schema ([#31852](https://github.com/laravel/framework/pull/31852)) -- Fixed Microsoft ODBC lost connection handling ([#31879](https://github.com/laravel/framework/pull/31879)) - - -## [v6.18.0 (2020-03-03)](https://github.com/laravel/framework/compare/v6.17.1...v6.18.0) - -### Added -- Added `Arr::hasAny()` method ([#31636](https://github.com/laravel/framework/pull/31636)) - -### Fixed -- Use correct locale when resolving Faker from the container ([#31615](https://github.com/laravel/framework/pull/31615)) -- Fixed loading deferred providers for binding interfaces and implementations ([#31629](https://github.com/laravel/framework/pull/31629), [1764ff7](https://github.com/laravel/framework/commit/1764ff762966083a12dd2c9b522cec5f1bbda967)) - -### Changed -- Make `newPivotQuery()` method public ([#31677](https://github.com/laravel/framework/pull/31677)) -- Allowed easier customization of the queued mailable job ([#31684](https://github.com/laravel/framework/pull/31684)) -- Expose Notification Id within Message Data in `Illuminate\Notifications\Channels\MailChannel` ([#31632](https://github.com/laravel/framework/pull/31632)) - - -## [v6.17.1 (2020-02-26)](https://github.com/laravel/framework/compare/v6.17.0...v6.17.1) - -### Changed -- Don`t do chmod in File cache in case if permission not set ([#31593](https://github.com/laravel/framework/pull/31593)) - - -## [v6.17.0 (2020-02-25)](https://github.com/laravel/framework/compare/v6.16.0...v6.17.0) - -### Added -- Allowed private-encrypted pusher channels ([#31559](https://github.com/laravel/framework/pull/31559), [ceabaef](https://github.com/laravel/framework/commit/ceabaef88741c0c6a891166cf14eb967fdf4e8ee), [8215e0d](https://github.com/laravel/framework/commit/8215e0dc66bf71a7ff4e9bf260380cf4a26f28a6)) -- Added file `permission` config option for the File cache store ([#31579](https://github.com/laravel/framework/pull/31579)) -- Added `Connection refused` and `running with the --read-only option so it cannot execute this statement` to `DetectsLostConnections` ([#31539](https://github.com/laravel/framework/pull/31539)) - -### Reverted -- Reverted ["Fixed memory usage on downloading large files"](https://github.com/laravel/framework/pull/31163) ([#31587](https://github.com/laravel/framework/pull/31587)) - -### Fixed -- Fixed issue `Content Type not specified` ([#31533](https://github.com/laravel/framework/pull/31533)) - -### Changed -- Allowed `cache` helper to have an optional `expiration` parameter ([#31554](https://github.com/laravel/framework/pull/31554)) -- Allowed passing of strings to `TestResponse::dumpSession()` method ([#31583](https://github.com/laravel/framework/pull/31583)) -- Consider mailto: and tel: links in the subcopy actionUrl label in emails ([#31523](https://github.com/laravel/framework/pull/31523), [641a7cd](https://github.com/laravel/framework/commit/641a7cda8280ecd3035616d4ce6434434b116624)) -- Exclude mariaDB from database queue support for new SKIP LOCKED ([fff96e7](https://github.com/laravel/framework/commit/fff96e7df7de470e162a6b7f6dd528e6fe17aadc)) - - -## [v6.16.0 (2020-02-18)](https://github.com/laravel/framework/compare/v6.15.1...v6.16.0) - -### Added -- Added Guzzle 7 support ([#31484](https://github.com/laravel/framework/pull/31484)) -- Added `Illuminate\Database\Query\Builder::groupByRaw()` ([#31498](https://github.com/laravel/framework/pull/31498)) -- Added SQLite JSON update support with json_patch ([#31492](https://github.com/laravel/framework/pull/31492)) - -### Fixed -- Fixed `appendRow` on console table ([#31469](https://github.com/laravel/framework/pull/31469)) -- Fixed password check in `EloquentUserProvider::retrieveByCredentials()` ([4436662](https://github.com/laravel/framework/commit/4436662a1ee19fc5e9eb76a0651d0de1aedb3ee2)) - -### Revert -- Revert table feature in the console output ([4094d78](https://github.com/laravel/framework/commit/4094d785269ce7849557b792f650fb278d48978e)) - -### Changed -- Change MySql nullable modifier to allow generated columns to be not null ([#31452](https://github.com/laravel/framework/pull/31452)) -- Throw exception on empty collection in `assertSentTo()` \ `assertNotSentTo()` methods in `NotificationFake` class ([#31471](https://github.com/laravel/framework/pull/31471)) - - -## [v6.15.1 (2020-02-12)](https://github.com/laravel/framework/compare/v6.15.0...v6.15.1) - -### Added -- Added `whereNull` and `whereNotNull` to `Collection` ([#31425](https://github.com/laravel/framework/pull/31425)) -- Added `Illuminate\Foundation\Testing\MockStream` class ([#31447](https://github.com/laravel/framework/pull/31447)) - -### Fixed -- Fixed `event:list` command for shows non-registered events ([#31444](https://github.com/laravel/framework/pull/31444)) -- Fixed postgres grammar for nested json arrays with ([#31448](https://github.com/laravel/framework/pull/31448), [b3d0da1](https://github.com/laravel/framework/commit/b3d0da164bdf3d5d829384025476ca1b2065c97e)) - - -## [v6.15.0 (2020-02-11)](https://github.com/laravel/framework/compare/v6.14.0...v6.15.0) - -### Added -- Added `Illuminate\Auth\Events\Validated` event ([#31357](https://github.com/laravel/framework/pull/31357), [7ddac28](https://github.com/laravel/framework/commit/7ddac28bc08b99ee248b1e4aa559efc3a8bfec8c)) -- Make `Blueprint` support Grammar's `macro` ([#31365](https://github.com/laravel/framework/pull/31365)) -- Added `Macroable` trait to `Illuminate\Console\Scheduling\Schedule` class ([#31354](https://github.com/laravel/framework/pull/31354)) -- Added support `dispatchAfterResponse` in `BusFake` ([#31418](https://github.com/laravel/framework/pull/31418), [e59597f](https://github.com/laravel/framework/commit/e59597f13af3ee6e6467bdb8593844f9db6bb789)) -- Added `Illuminate\Foundation\Exceptions\Handler::getHttpExceptionView()` ([#31420](https://github.com/laravel/framework/pull/31420)) -- Allowed appending of rows to Artisan tables ([#31426](https://github.com/laravel/framework/pull/31426)) - -### Fixed -- Fixed `locks` for `sqlsrv` queue ([5868066](https://github.com/laravel/framework/commit/58680668102282fcc4215a48e8947c2c1b051201)) -- Fixed `Illuminate\Events\Dispatcher::hasListeners()` ([#31403](https://github.com/laravel/framework/pull/31403), [c80302e](https://github.com/laravel/framework/commit/c80302e6e9403f9fad71f114d94e758ee0fcbff7)) -- Fixed testing with unencrypted cookies ([#31390](https://github.com/laravel/framework/pull/31390)) - -### Changed -- Allowed multiple paths to be passed to migrate fresh and migrate refresh commands ([#31381](https://github.com/laravel/framework/pull/31381)) -- Split Console InteractsWithIO to external trait ([#31376](https://github.com/laravel/framework/pull/31376)) -- Added sms link as valid URL in `UrlGenerator::isValid()` method ([#31382](https://github.com/laravel/framework/pull/31382)) -- Upgrade CommonMark and use the bundled table extension ([#31411](https://github.com/laravel/framework/pull/31411)) -- Ensure `Application::$terminatingCallbacks` are reset on `Application::flush()` ([#31413](https://github.com/laravel/framework/pull/31413)) -- Remove serializer option in `PhpRedisConnector::createClient()` ([#31417](https://github.com/laravel/framework/pull/31417)) - - -## [v6.14.0 (2020-02-04)](https://github.com/laravel/framework/compare/v6.13.1...v6.14.0) - -### Added -- Added `Illuminate\Bus\Dispatcher::dispatchAfterResponse()` method ([#31300](https://github.com/laravel/framework/pull/31300), [8a3cdb0](https://github.com/laravel/framework/commit/8a3cdb0622047b1d94b4a754bfe98fb7dc1c174a)) -- Added `Illuminate\Support\Testing\Fakes\QueueFake::assertPushedWithoutChain()` method ([#31332](https://github.com/laravel/framework/pull/31332), [7fcc6b5](https://github.com/laravel/framework/commit/7fcc6b5feb004f57aa61a0fa93c340694ae6a980)) -- Added `Macroable` trait to the `Illuminate\Events\Dispatcher` ([#31317](https://github.com/laravel/framework/pull/31317)) -- Added `NoPendingMigrations` event ([#31289](https://github.com/laravel/framework/pull/31289), [739fcea](https://github.com/laravel/framework/commit/739fcea5cfcc9079d3ca8e5aa9673f706741418e)) - -### Fixed -- Used current DB to create Doctrine Connections ([#31278](https://github.com/laravel/framework/pull/31278)) -- Removed duplicate output when publishing tags in `vendor:publish` command ([#31333](https://github.com/laravel/framework/pull/31333)) -- Fixed plucking column name containing a space ([#31299](https://github.com/laravel/framework/pull/31299)) -- Fixed bug with wildcard caching in event dispatcher ([#31313](https://github.com/laravel/framework/pull/31313)) -- Fixed infinite value for RedisStore ([#31348](https://github.com/laravel/framework/pull/31348)) -- Fixed dropping columns in SQLServer with default value ([#31341](https://github.com/laravel/framework/pull/31341)) - -### Changed -- Use SKIP LOCKED for mysql 8.1 and pgsql 9.5 queue workers ([#31287](https://github.com/laravel/framework/pull/31287)) -- Don't merge middleware from method and property in `Illuminate\Bus\Queueable::middleware()` ([#31301](https://github.com/laravel/framework/pull/31301)) -- Split `specifyParameter()` from `Illuminate\Console\Command` to `HasParameters` trait ([#31254](https://github.com/laravel/framework/pull/31254)) -- Make sure changing a database field to json does not include charset ([#31343](https://github.com/laravel/framework/pull/31343)) - - -## [v6.13.1 (2020-01-28)](https://github.com/laravel/framework/compare/v6.13.0...v6.13.1) - -### Fixed -- Fixed error on `queue:work` database on Windows ([#31277](https://github.com/laravel/framework/pull/31277)) - - -## [v6.13.0 (2020-01-28)](https://github.com/laravel/framework/compare/v6.12.0...v6.13.0) - -### Added -- Added `--api` option to the `make:model` command ([#31197](https://github.com/laravel/framework/pull/31197), [#31222](https://github.com/laravel/framework/pull/31222)) -- Added `PendingResourceRegistration::shallow()` method ([#31208](https://github.com/laravel/framework/pull/31208), [104c539](https://github.com/laravel/framework/commit/104c539c342d395e2f3c4ba7339df095f83f6352)) -- Allowed formatting an implicit attribute using a closure ([#31246](https://github.com/laravel/framework/pull/31246)) -- Added `Filesystem::ensureDirectoryExists()` method ([8a8eed4](https://github.com/laravel/framework/commit/8a8eed4d157102ef77527891ac1d8f8e85e7afee)) -- Added support to `Storage::url()` for the Ftp driver ([#31258](https://github.com/laravel/framework/pull/31258), [b8790e5](https://github.com/laravel/framework/commit/b8790e56bb7333943db799e6ff6e21a7b01218e0)) - -### Fixed -- Fixed laravel migrations when migrating to sql server (dropColumn with default value) ([#31229](https://github.com/laravel/framework/pull/31229)) -- Fixed `handleBeginTransactionException()` method calling pdo property instead of getPdo() method ([#31233](https://github.com/laravel/framework/pull/31233)) -- Fixed channel names when broadcasting via redis ([#31261](https://github.com/laravel/framework/pull/31261)) -- Replace asterisks before validation ([#31257](https://github.com/laravel/framework/pull/31257)) - -### Changed -- Reset timeout handler after worker loop ([#31198](https://github.com/laravel/framework/pull/31198)) - - -## [v6.12.0 (2020-01-21)](https://github.com/laravel/framework/compare/v6.11.0...v6.12.0) - -### Added -- Added `ServiceProvider::loadFactoriesFrom()` method ([#31133](https://github.com/laravel/framework/pull/31133)) -- Added `TestResponse::dumpSession()` method ([#31131](https://github.com/laravel/framework/pull/31131)) -- Added `Str::isUuid()` method ([#31148](https://github.com/laravel/framework/pull/31148)) -- Restored phpunit 7 support ([#31113](https://github.com/laravel/framework/pull/31113)) -- Added `Request::boolean()` method ([#31160](https://github.com/laravel/framework/pull/31160)) -- Added `Database\Eloquent\FactoryBuilder::createMany()` ([#31171](https://github.com/laravel/framework/pull/31171), [6553d59](https://github.com/laravel/framework/commit/6553d5923959bd947b49eb089053cd430d8968d4)) -- Added missing options for PhpRedis ([#31182](https://github.com/laravel/framework/pull/31182)) - -### Fixed -- Fixed `Cache\RedisLock::acquire()` ([#31168](https://github.com/laravel/framework/pull/31168), [8683a3d](https://github.com/laravel/framework/commit/8683a3d721f92e512a83a3e5feb3d0a9bb682560)) -- Fixed database url parsing for connections with no database specified ([#31185](https://github.com/laravel/framework/pull/31185)) -- Prevent ambiguous column with table name prefix ([#31174](https://github.com/laravel/framework/pull/31174)) - -### Optimization -- Fixed memory usage on downloading large files ([#31163](https://github.com/laravel/framework/pull/31163)) - -### Changed -- Replace Event Dispatcher in resolved cache repositories when `Event::fake()` is used ([#31119](https://github.com/laravel/framework/pull/31119), [0a70beb](https://github.com/laravel/framework/commit/0a70bebd5ecfd51185a312bbfb60ee7f8ff7eb09)) - - -## [v6.11.0 (2020-01-14)](https://github.com/laravel/framework/compare/v6.10.1...v6.11.0) - -### Added -- Added `Illuminate\Database\Eloquent\Builder::firstWhere()` method ([#31089](https://github.com/laravel/framework/pull/31089)) -- Redis Broadcaster: Broadcast to multiple channels at once ([#31108](https://github.com/laravel/framework/pull/31108)) - -### Fixed -- Fixed undefined property in `WithFaker::makeFaker()` ([#31083](https://github.com/laravel/framework/pull/31083)) -- Fixed `Str::afterLast()` method ([#31095](https://github.com/laravel/framework/pull/31095)) -- Fixed insert float into MySQL with PHP 7.3 ([#31100](https://github.com/laravel/framework/pull/31100)) -- Fixed refresh on Model with customized pivot attribute name ([#31125](https://github.com/laravel/framework/pull/31125), [678b26b](https://github.com/laravel/framework/commit/678b26b1a9cd0d8a6bef85932420e67a1b20e677)) - -### Changed -- Remove all indentation in blade templates ([917ee51](https://github.com/laravel/framework/commit/917ee514d4bbd4162b6ddb385c643df97dcfa7d3)) -- Added mailable names to assertion messages in `MailFake::assertNothingSent()` and `MailFake::assertNothingQueued()` ([#31106](https://github.com/laravel/framework/pull/31106)) -- Search for similar results in `assertDatabaseHas()` ([#31042](https://github.com/laravel/framework/pull/31042), [2103eb7](https://github.com/laravel/framework/commit/2103eb7ccfbb6798e9078d82e0ebffcf87d95b14)) - - -## [v6.10.1 (2020-01-08)](https://github.com/laravel/framework/compare/v6.10.0...v6.10.1) - -### Changed -- Updated some blade templates ([f17e347](https://github.com/laravel/framework/commit/f17e347b15e8d27b4e775a8f961bda083326ee8f)) - - -## [v6.10.0 (2020-01-07)](https://github.com/laravel/framework/compare/v6.9.0...v6.10.0) - -### Added -- Added `withoutMix()` and `withMix()` test helpers ([#30900](https://github.com/laravel/framework/pull/30900)) -- Added `validateWithBag()` macro to `Request` ([#30896](https://github.com/laravel/framework/pull/30896)) -- Added PHPUnit 9 support ([#30947](https://github.com/laravel/framework/pull/30947), [#30989](https://github.com/laravel/framework/pull/30989)) -- Added `exclude_if` and `exclude_unless` validation rules ([#30835](https://github.com/laravel/framework/pull/30835), [c0fdb56](https://github.com/laravel/framework/commit/c0fdb566831b7ebf34a15bbdfec81dd0039c76f0)) -- Added generated columns (virtual/stored) support for PostgreSQL ([#30971](https://github.com/laravel/framework/pull/30971)) -- Added `mixin` support to Eloquent builder ([#30978](https://github.com/laravel/framework/pull/30978), [28fa74e](https://github.com/laravel/framework/commit/28fa74e8222a57118ae1b590101a35f63b964f81)) -- Make the Redis Connection `Macroable` ([#31020](https://github.com/laravel/framework/pull/31020)) -- Added `PackageManifest::config()` method ([#31039](https://github.com/laravel/framework/pull/31039), [9b73540](https://github.com/laravel/framework/commit/9b73540cbe7ebb67b0a0a127743791511e5ae8fe)) -- Added `redis.connection` aliases in container ([#31034](https://github.com/laravel/framework/pull/31034)) -- Extracted `CallsCommands` feature from `Illuminate\Console\Command` ([#31026](https://github.com/laravel/framework/pull/31026), [ef72716](https://github.com/laravel/framework/commit/ef72716db85f36e003fb92d2625adabbf94d5afe)) -- Allowed absolute file path for `Storage::putFile()` ([#31040](https://github.com/laravel/framework/pull/31040)) - -### Changed -- Handled passing too many arguments to `@slot` ([#30893](https://github.com/laravel/framework/pull/30893), [878f159](https://github.com/laravel/framework/commit/878f15922523e748bfbfdf50f40269f8ffe20d9d)) -- Make `ThrottleRequestsException` extend `TooManyRequestsHttpException` ([#30943](https://github.com/laravel/framework/pull/30943)) -- Used `league/commonmark` instead of `erusev/parsedown` for mail markdown ([#30982](https://github.com/laravel/framework/pull/30982)) -- Regenerate token on logout ([b2af428](https://github.com/laravel/framework/commit/b2af428e60188ea55fb06f3a1e0b0b0c690bbe86)) -- Make `RedisQueue::getConnection()` public ([#31016](https://github.com/laravel/framework/pull/31016)) -- Resolve `Faker\Generator` out of the container if it is bound ([#30992](https://github.com/laravel/framework/pull/30992)) - -### Fixed -- Fixed `float` database types in `Blueprint` ([#30891](https://github.com/laravel/framework/pull/30891)) -- Fixed code that depended on `getenv()` ([#30924](https://github.com/laravel/framework/pull/30924)) -- Prevented making actual pdo connections while reconnecting ([#30998](https://github.com/laravel/framework/pull/30998)) -- Fixed `exclude_if` \ `exclude_unless` validation rules for nested data ([#31006](https://github.com/laravel/framework/pull/31006)) -- Update `dev-master` branch aliases from `6.0-dev` to `6.x-dev` ([d06cc79](https://github.com/laravel/framework/commit/d06cc79d92c18b0ff423466554eeed0aea09ae51)) -- Utilize Symfony’s PSR Factory. Fixed [#31017](https://github.com/laravel/framework/issues/31017) ([#31018](https://github.com/laravel/framework/pull/31018), [#31027](https://github.com/laravel/framework/pull/31027)) -- Used model connection by default in the database validators ([#31037](https://github.com/laravel/framework/pull/31037)) - -### Optimization -- Optimize Service Provider registration ([#30960](https://github.com/laravel/framework/pull/30960)) -- Optimize `runningInConsole` method ([#30922](https://github.com/laravel/framework/pull/30922)) -- Delay instantiation of translator and view factory ([#31009](https://github.com/laravel/framework/pull/31009)) - -### Deprecated -- Deprecate `PendingMail::sendNow()` and remove unneeded check ([#30999](https://github.com/laravel/framework/pull/30999)) - -### Reverted -- Reverted [TransactionCommitted event doesn’t contain transaction level I’d expect it to](https://github.com/laravel/framework/pull/30883) ([#31051](https://github.com/laravel/framework/pull/31051)) - -### Refactoring -- Refactoring of `BladeCompiler::compileString()` method ([08887f9](https://github.com/laravel/framework/commit/08887f99d05bb85affd3cbc6f7fdbc32a9297eea)) - - -## [v6.9.0 (2019-12-19)](https://github.com/laravel/framework/compare/v6.8.0...v6.9.0) - -### Added -- Added `MIME` type argument to `Testing/FileFactory::create()` ([#30870](https://github.com/laravel/framework/pull/30870)) -- Added `seed` to `all` option when creating the model (`make:model` command) ([#30874](https://github.com/laravel/framework/pull/30874)) -- Allowed configurable emergency logger ([#30873](https://github.com/laravel/framework/pull/30873)) -- Added `prependMiddlewareToGroup()` / `appendMiddlewareToGroup()` / `prependToMiddlewarePriority()` / `appendToMiddlewarePriority()` to `Kernal` for manipulating middleware ([6f33feb](https://github.com/laravel/framework/commit/6f33feba124d4a7ff2af4f3ed18583d67fb68f7c)) - -### Reverted -- Reverted [Added `Model::setRawAttribute()`](https://github.com/laravel/framework/pull/30853) ([#30885](https://github.com/laravel/framework/pull/30885)) - -### Fixed -- Fixed `Builder::withCount()` binding error when a scope is added into related model with binding in a sub-select ([#30869](https://github.com/laravel/framework/pull/30869)) - -### Changed -- Don't throw exception when session is not set in `AuthenticateSession` middleware ([4de1d24](https://github.com/laravel/framework/commit/4de1d24cf390f07d4f503973e5556f73060fbb31)) - - -## [v6.8.0 (2019-12-17)](https://github.com/laravel/framework/compare/v6.7.0...v6.8.0) - -### Added -- Allowed packages to use custom markdown mail themes ([#30814](https://github.com/laravel/framework/pull/30814), [2206d52](https://github.com/laravel/framework/commit/2206d5223606f5a24e7e3bf0ba1f25b343dfcc6b)) -- Added more quotes to `Inspiring` ([4a7d566](https://github.com/laravel/framework/commit/4a7d566ff4a330970cfaa03df4c988c580804a7f), [9693ced](https://github.com/laravel/framework/commit/9693cedbfc1fb0e38a8e688375e5b2ce5273b75f)) -- Added support for nested arrays in `TestResponse::assertViewHas()` ([#30837](https://github.com/laravel/framework/pull/30837)) -- Added `Model::setRawAttribute()` ([#30853](https://github.com/laravel/framework/pull/30853)) -- Added `--force` option to the `make:controller` resource ([#30856](https://github.com/laravel/framework/pull/30856)) -- Allowed passing an array to `Resource::collection()` ([#30800](https://github.com/laravel/framework/pull/30800)) -- Implemented ArrayAccess on `JsonResponse` and `TestResponse` ([#30817](https://github.com/laravel/framework/pull/30817)) -- Added `--seed` option to the `make::model` resource ([#30828](https://github.com/laravel/framework/pull/30828), [2cd9417](https://github.com/laravel/framework/commit/2cd9417064123fd6c9114788d331659ede568dbf)) - -### Fixed -- Fixed two index creation instead of one when using `change()` ([#30843](https://github.com/laravel/framework/pull/30843)) -- Prevent duplicate attachments in the `Mailable` ([3c8ccc2](https://github.com/laravel/framework/commit/3c8ccc2fb4ec03572076e6df71608f6bbb7d71e1)) -- Fixed `ServiceProvider` for PHP 7.4 in `Lumen` ([#30819](https://github.com/laravel/framework/pull/30819)) -- Fixed non-eloquent model validation in database validation rules ([#30840](https://github.com/laravel/framework/pull/30840)) - -### Changed -- Changed `rescue()` helper ([#30838](https://github.com/laravel/framework/pull/30838)) -- Added previous exception to `EntryNotFoundException` thrown in `Container.php` ([#30862](https://github.com/laravel/framework/pull/30862)) -- Changed `DatabaseNotification::$keyType` to match `uuid` ([#30823](https://github.com/laravel/framework/pull/30823)) - - -## [v6.7.0 (2019-12-10)](https://github.com/laravel/framework/compare/v6.6.2...v6.7.0) - -### Added -- Added `getQualifiedCreatedAtColumn()` and `getQualifiedUpdatedAtColumn()` methods to `HasTimestamps` concern ([#30792](https://github.com/laravel/framework/pull/30792)) -- Added `exceptionContext()` method to the `Exceptions\Handler` ([#30780](https://github.com/laravel/framework/pull/30780)) -- Added ability for postmark transport to throw errors ([#30799](https://github.com/laravel/framework/pull/30799), [4320b82](https://github.com/laravel/framework/commit/4320b82f848d63d41df95860ed3bf595202873a9)) -- Added `withoutRelations()` and `unsetRelations()` methods to `HasRelationships` ([#30802](https://github.com/laravel/framework/pull/30802)) -- Added `ResourceCollection::preserveQueryParameters()` for preserve query parameters on paginated api resources ([#30745](https://github.com/laravel/framework/pull/30745), [e92a708](https://github.com/laravel/framework/commit/e92a70800671187cc30a39e965144101d5db169a)) - -### Fixed -- Fixed explicit models in string-based database validation rules ([#30790](https://github.com/laravel/framework/pull/30790)) -- Fixed `Routing\RedirectController()` ([#30783](https://github.com/laravel/framework/pull/30783)) - -### Changed -- Reconnect `PhpRedisConnection` on connection missing ([#30778](https://github.com/laravel/framework/pull/30778)) -- Improved ShouldBroadcastNow performance ([#30797](https://github.com/laravel/framework/pull/30797), [5b3cc97](https://github.com/laravel/framework/commit/5b3cc9752d873be96ac34d9062cc35aa9c95bd59)) - - -## [v6.6.2 (2019-12-05)](https://github.com/laravel/framework/compare/v6.6.1...v6.6.2) - -### Added -- Added `Illuminate\Support\Facades\Facade::partialMock()` method ([#30754](https://github.com/laravel/framework/pull/30754)) -- Added of support `retryAfter` option on queued listeners ([#30743](https://github.com/laravel/framework/pull/30743)) - -### Fixed -- Fixed zero parameter for routes ([#30768](https://github.com/laravel/framework/pull/30768)) - -### Changed -- Changed `getAllViews()` method visibility from `protected` to `public` in all schema builders ([#30757](https://github.com/laravel/framework/pull/30757)) - - -## [v6.6.1 (2019-12-03)](https://github.com/laravel/framework/compare/v6.6.0...v6.6.1) - -### Added -- Added `setInput()` and `setOutput()` methods to `Illuminate\Console\Command` ([#30706](https://github.com/laravel/framework/pull/30706)) - -### Fixed -- Fixed RouteUrlGenerator with empty string for required parameter ([#30714](https://github.com/laravel/framework/pull/30714)) - -### Changed -- Force usage getting timestamps columns in model ([#30697](https://github.com/laravel/framework/pull/30697)) - -### Reverted -- Revert [Added `Illuminate\Routing\Router::head()`](https://github.com/laravel/framework/pull/30646) ([#30710](https://github.com/laravel/framework/pull/30710)) - - -## [v6.6.0 (2019-11-26)](https://github.com/laravel/framework/compare/v6.5.2...v6.6.0) - -### Added -- Allowed explicit Model definitions in database rules ([#30653](https://github.com/laravel/framework/pull/30653), [9beceac](https://github.com/laravel/framework/commit/9beceacb1a1b8ba37cd0f775cb2fb81e21ba4c31)) -- Allowed `ResponseFactory::view()` to return first view ([#30651](https://github.com/laravel/framework/pull/30651)) -- Added `Foundation\Testing\Concerns\InteractsWithDatabase::assertDeleted()` method ([#30648](https://github.com/laravel/framework/pull/30648)) -- Added `Illuminate\Routing\Router::head()` ([#30646](https://github.com/laravel/framework/pull/30646)) -- Added `wherePivotNotIn()` and `orWherePivotNotIn()` methods to `BelongsToMany` ([#30671](https://github.com/laravel/framework/pull/30671)) -- Added options in `SqlServerConnector` to encrypt data with Azure Key vault ([#30636](https://github.com/laravel/framework/pull/30636)) - -### Fixed -- Fixed errors in `Illuminate\Http\Testing\FileFactory::create()` ([#30632](https://github.com/laravel/framework/pull/30632)) -- Fixed routing bug that causes missing parameters to be ignored ([#30659](https://github.com/laravel/framework/pull/30659)) - -### Changed -- Updated error message in `PhpRedisConnector::createClient()` if redis extension is not loaded ([#30673](https://github.com/laravel/framework/pull/30673), [184a0f4](https://github.com/laravel/framework/commit/184a0f45bc9959ebadf36a7dd6966c2bfcb96191)) -- Updated `windows_os()` helper to use PHP_OS_FAMILY ([#30660](https://github.com/laravel/framework/pull/30660)) - - -## [v6.5.2 (2019-11-19)](https://github.com/laravel/framework/compare/v6.5.1...v6.5.2) - -### Added -- Allowed model serialization on jobs for typed properties ([#30604](https://github.com/laravel/framework/pull/30604), [#30605](https://github.com/laravel/framework/pull/30605), [920c364](https://github.com/laravel/framework/commit/920c3640269b7c1dd0f26e5b6f765ca9b7f99366)) -- Allowed fallback when facade root accessor has previously been resolved ([#30616](https://github.com/laravel/framework/pull/30616)) -- Added support for separation between `geometry` and `geography` types for `Postgres` ([#30545](https://github.com/laravel/framework/pull/30545)) -- Added `createWithContent()` method to `Illuminate\Http\Testing\File` and `Illuminate\Http\Testing\FileFactory` ([2cc6fa3](https://github.com/laravel/framework/commit/2cc6fa33732118cc71c74209b02382b989689b63), [181db51](https://github.com/laravel/framework/commit/181db51595d546cbd24b3fac0cb276255e147286)) - -### Refactoring -- Improved `PostgresGrammar::formatPostGisType()` method readability ([#30593](https://github.com/laravel/framework/pull/30593)) - -### Changed -- Added `symfony/debug` dependency to `illuminate/pipeline` ([#30611](https://github.com/laravel/framework/pull/30611)) -- Override `BelongsToMany::cursor()` to hydrate pivot relations ([#30580](https://github.com/laravel/framework/pull/30580)) -- Ignore Redis prefix when verifying channel access in RedisBroadcaster ([#30597](https://github.com/laravel/framework/pull/30597), [d77ce36](https://github.com/laravel/framework/commit/d77ce36917510d5a6800dd4116a4e18b7bf720b3)) - - -## [v6.5.1 (2019-11-12)](https://github.com/laravel/framework/compare/v6.5.0...v6.5.1) - -### Added -- Added `includeUnless` Blade directive ([#30538](https://github.com/laravel/framework/pull/30538)) - -### Fixed -- Fixed default value for $count in `PhpRedisConnection::spop()` method ([#30546](https://github.com/laravel/framework/pull/30546)) -- Fixed breaking compatibility with multi-schema postgres ([#30562](https://github.com/laravel/framework/pull/30562), [6460d2b](https://github.com/laravel/framework/commit/6460d2b1bd89f470a76f5c2c3bddd390fe430e0f)) -- Fixed `Model::isDirty()` with `collection` / `object` casts ([#30565](https://github.com/laravel/framework/pull/30565)) -- Fixed `bcc` in `MailgunTransport::send()` ([#30569](https://github.com/laravel/framework/pull/30569)) - -### Changed -- Remove `illuminate/support` dependency from `Container` package ([#30518](https://github.com/laravel/framework/pull/30518), [#30528](https://github.com/laravel/framework/pull/30528)) - - -## [v6.5.0 (2019-11-05)](https://github.com/laravel/framework/compare/v6.4.1...v6.5.0) - -### Added -- Added `LazyCollection::remember()` method ([#30443](https://github.com/laravel/framework/pull/30443)) -- Added `Str::afterLast()` and `Str::beforeLast()` methods ([#30507](https://github.com/laravel/framework/pull/30507)) -- Added `existsOr()` and `doesntExistOr()` methods to the query builder ([#30495](https://github.com/laravel/framework/pull/30495)) -- Added `unless` condition to Blade custom `if` directives ([#30492](https://github.com/laravel/framework/pull/30492)) - -### Changed -- Added reconnect if missing connection when beginning transaction ([#30474](https://github.com/laravel/framework/pull/30474)) -- Set Redis cluster prefix with PhpRedis ([#30461](https://github.com/laravel/framework/pull/30461)) - - -## [v6.4.1 (2019-10-29)](https://github.com/laravel/framework/compare/v6.4.0...v6.4.1) - -### Added -- Added `ScheduledTaskSkipped` event when a scheduled command was filtered from running ([#30407](https://github.com/laravel/framework/pull/30407)) -- Added `Login timeout expired` to `DetectsLostConnections` ([#30362](https://github.com/laravel/framework/pull/30362)) -- Added `missing` method to `Illuminate\Filesystem\Filesystem` and `Illuminate\Filesystem\FilesystemAdapter` classes ([#30441](https://github.com/laravel/framework/pull/30441)) - -### Changed -- Make `vendor:publish` command more informative ([#30408](https://github.com/laravel/framework/pull/30408), [65d040d](https://github.com/laravel/framework/commit/65d040d44f1cef3830748ec59c0056bc2418dca6)) -- Accepted underscores URL in the `URL` validator ([#30417](https://github.com/laravel/framework/pull/30417)) -- Updated `artisan down` output to be consistent with `artisan up` ([#30422](https://github.com/laravel/framework/pull/30422)) -- Changed `!empty` to `isset` for changing redis database ([#30420](https://github.com/laravel/framework/pull/30420)) -- Throw an exception when signing route got in parameter keys `signature` ([#30444](https://github.com/laravel/framework/pull/30444), [71af732](https://github.com/laravel/framework/commit/71af732b6b00ab148cd23b95aca4e05bcb86c242)) - -### Fixed -- Fixed of retrieving view config in `ServiceProvider::loadViewsFrom()` for Lumen ([#30404](https://github.com/laravel/framework/pull/30404)) - - -## [v6.4.0 (2019-10-23)](https://github.com/laravel/framework/compare/v6.3.0...v6.4.0) - -### Added -- Added `missing()` method to `Request` class ([#30320](https://github.com/laravel/framework/pull/30320)) -- Added `Pipeline::pipes()` method ([#30346](https://github.com/laravel/framework/pull/30346)) -- Added `TestResponse::assertCreated()` method ([#30368](https://github.com/laravel/framework/pull/30368)) - -### Changed -- Added `connection is no longer usable` to `DetectsLostConnections` ([#30362](https://github.com/laravel/framework/pull/30362)) -- Implemented parse ID on find method for many to many relation ([#30359](https://github.com/laravel/framework/pull/30359)) -- Improvements on subqueries ([#30307](https://github.com/laravel/framework/pull/30307), [3f3b621](https://github.com/laravel/framework/commit/3f3b6214cc3353156a490d88fc8f0c148da400d5)) -- Pass mail data to theme css in `Markdown::render()` method ([#30376](https://github.com/laravel/framework/pull/30376)) -- Handle ajax requests in RequirePassword middleware ([#30390](https://github.com/laravel/framework/pull/30390), [331c354](https://github.com/laravel/framework/commit/331c354e586a5a27a9edc9b9a49d23aa872e4b32)) - -### Fixed -- Fixed `retry()` with `$times` value less then 1 ([#30356](https://github.com/laravel/framework/pull/30356)) -- Fixed `last_modified` option in `SetCacheHeader` ([#30335](https://github.com/laravel/framework/pull/30335)) -- Fixed the Filesystem manager's exception on unsupported driver ([#30331](https://github.com/laravel/framework/pull/30331), [#30369](https://github.com/laravel/framework/pull/30369)) -- Fixed `shouldQueue()` check for bound event listeners ([#30378](https://github.com/laravel/framework/pull/30378)) -- Used exit code `1` when migration table not found ([#30321](https://github.com/laravel/framework/pull/30321)) -- Alleviate breaking change introduced by password confirm feature ([#30389](https://github.com/laravel/framework/pull/30389)) - -### Security: -- Password Reset Security fix ([23041e9](https://github.com/laravel/framework/commit/23041e99833630d93cc7672bd7087eaa350c3a59), [a934160](https://github.com/laravel/framework/commit/a9341609705e2f8febcd356cdfa33391ec6538c7)) - - -## [v6.3.0 (2019-10-15)](https://github.com/laravel/framework/compare/v6.2.0...v6.3.0) - -### Added -- Added ability to override `setUserPassword` on password reset ([#30218](https://github.com/laravel/framework/pull/30218)) -- Added firing `deleting` / `deleted` events in `MorphPivot` ([#30229](https://github.com/laravel/framework/pull/30229)) -- Added locking mechanism for the array cache driver ([#30253](https://github.com/laravel/framework/pull/30253)) -- Added `dropAllViews` functionality to the SQL Server builder ([#30222](https://github.com/laravel/framework/pull/30222)) - -### Optimization -- Optimize eager loading memory handling ([#30248](https://github.com/laravel/framework/pull/30248)) - -### Fixed -- Fixed extra `?` for empty query string in `RouteUrlGenerator::getRouteQueryString()` ([#30280](https://github.com/laravel/framework/pull/30280)) - -### Changed -- Updated list of URI schemes for `Url` validator ([#30220](https://github.com/laravel/framework/pull/30220)) -- Added schema name when dropping all FKs in SQL Server ([#30221](https://github.com/laravel/framework/pull/30221)) -- Used contracts in `RequirePassword` middleware ([#30215](https://github.com/laravel/framework/pull/30215)) -- Added ability to return array in `receivesBroadcastNotificationsOn` if `channelName` is array ([#30242](https://github.com/laravel/framework/pull/30242), [2faadcd](https://github.com/laravel/framework/commit/2faadcd288cdc86cf7a1a3644e68e5e0ce641a8b)) - - -## [v6.2.0 (2019-10-08)](https://github.com/laravel/framework/compare/v6.1.0...v6.2.0) - -### Added -- Added support for callable objects in `Container::call()` ([#30156](https://github.com/laravel/framework/pull/30156)) -- Add multipolygonz type for postgreSQL ([#30173](https://github.com/laravel/framework/pull/30173)) -- Add "unauthenticated" method in auth middleware ([#30177](https://github.com/laravel/framework/pull/30177)) -- Add partialMock shorthand ([#30202](https://github.com/laravel/framework/pull/30202)) -- Allow Storage::put to accept a Psr StreamInterface ([#30179](https://github.com/laravel/framework/pull/30179)) -- Implement new password rule and password confirmation ([#30214](https://github.com/laravel/framework/pull/30214)) - -### Changed -- Remove unnecessary param passed to updatePackageArray method ([#30155](https://github.com/laravel/framework/pull/30155)) -- Add optional connection name to DatabaseUserProvider ([#30154](https://github.com/laravel/framework/pull/30154)) -- Remove brackets arround URL php artisan serve ([#30168](https://github.com/laravel/framework/pull/30168)) -- Apply limit to database rather than collection ([#30148](https://github.com/laravel/framework/pull/30148)) -- Allow to use scoped macro in nested queries ([#30127](https://github.com/laravel/framework/pull/30127)) -- Added array to json conversion for sqlite ([#30133](https://github.com/laravel/framework/pull/30133)) -- Use the `policies()` method instead of the property policies ([#30189](https://github.com/laravel/framework/pull/30189)) -- Split hasValidSignature method ([#30208](https://github.com/laravel/framework/pull/30208)) - -### Fixed -- `validateDimensions()` handle `image/svg` MIME ([#30204](https://github.com/laravel/framework/pull/30204)) - - -## [v6.1.0 (2019-10-01)](https://github.com/laravel/framework/compare/v6.0.4...v6.1.0) - -### Added -- Added `Illuminate\Support\LazyCollection::eager()` method ([#29832](https://github.com/laravel/framework/pull/29832)) -- Added `forgetChannel()` and `getChannels()` methods to `Illuminate\Log\LogManager` ([#30132](https://github.com/laravel/framework/pull/30132), [a52a0dd](https://github.com/laravel/framework/commit/a52a0dd239262f31edfaefe9a99213cccefc2f36)) -- Added `Illuminate\Foundation\Testing\TestResponse::assertNoContent()` method ([#30125](https://github.com/laravel/framework/pull/30125)) -- Added `InteractsWithQueue` to `SendQueueNotifications` ([#30140](https://github.com/laravel/framework/pull/30140)) -- Added `SendQueueNotifications::retryUntil()` method ([#30141](https://github.com/laravel/framework/pull/30141)) -- Added methods for sending cookies with test requests ([#30101](https://github.com/laravel/framework/pull/30101)) -- Added support of job middleware for queued notifications ([#30070](https://github.com/laravel/framework/pull/30070)) - -### Fixed -- Fixed migration class duplicate check in `make:migration` command ([#30095](https://github.com/laravel/framework/pull/30095)) -- Fixed monolog v2 handler preparation ([#30123](https://github.com/laravel/framework/pull/30123)) -- Fixed return of callback value for DurationLimiter ([#30143](https://github.com/laravel/framework/pull/30143)) - -### Changed -- Added runtime information output for seeders ([#30086](https://github.com/laravel/framework/pull/30086)) -- Added strict parameter to `Illuminate\Foundation\Testing\TestResponse::assertJsonPath()` ([#30142](https://github.com/laravel/framework/pull/30142)) -- Added `deletedAtColumn` optional parameter to `Foundation\Testing\Concerns\InteractsWithDatabase::assertSoftDeleted()` ([#30111](https://github.com/laravel/framework/pull/30111)) - -### Improved -- Improved `AuthServiceProvider::registerEventRebindHandler()` in case if guard is not initialized ([#30105](https://github.com/laravel/framework/pull/30105)) - - -## [v6.0.4 (2019-09-24)](https://github.com/laravel/framework/compare/v6.0.3...v6.0.4) - -### Added -- Added `TestResponse::assertJsonPath()` method ([#29957](https://github.com/laravel/framework/pull/29957)) -- Added `hasMacro` / `getGlobalMacro` / `hasGlobalMacro` methods to `Eloquent Builder` ([#30008](https://github.com/laravel/framework/pull/30008)) -- Added `Illuminate\Database\Eloquent\Relations\BelongsToMany::getPivotColumns()` method ([#30049](https://github.com/laravel/framework/pull/30049)) -- Added `ScheduledTaskFinished` / `ScheduledTaskStarting` events to signal when scheduled task runs ([#29888](https://github.com/laravel/framework/pull/29888)) -- Allowing adding command arguments and options with `InputArgument` / `InputOption` objects ([#29987](https://github.com/laravel/framework/pull/29987)) - -### Fixed -- Fixed `__()` with `null` parameter ([#29967](https://github.com/laravel/framework/pull/29967)) -- Fixed modifying `updated_at` column on custom pivot model ([#29970](https://github.com/laravel/framework/pull/29970)) -- Fixed `Illuminate\Redis\Limiters\ConcurrencyLimiter` ([#30005](https://github.com/laravel/framework/pull/30005)) -- Fixed `VerifyCsrfToken` middleware when response object instance of `Responsable` interface ([#29972](https://github.com/laravel/framework/pull/29972)) -- Fixed Postgresql column creation without optional precision ([#29873](https://github.com/laravel/framework/pull/29873)) -- Fixed migrations orders with multiple path with certain filenames ([#29996](https://github.com/laravel/framework/pull/29996)) -- Fixed adding `NotFoundHttpException` to "allowed" exceptions in tests ([#29975](https://github.com/laravel/framework/pull/29975)) - -### Changed -- Make it possible to disable encryption via `0` / `false` ([#29985](https://github.com/laravel/framework/pull/29985)) -- Allowed a symfony file instance in validate dimensions ([#30009](https://github.com/laravel/framework/pull/30009)) -- Create storage fakes with custom configuration ([#29999](https://github.com/laravel/framework/pull/29999)) -- Set locale in `PendingMail` only if locale present conditionally ([dd1e0a6](https://github.com/laravel/framework/commit/dd1e0a604713ddae21e6a893e4f605a6777300e8)) -- Improved sorting of imports alphabetically on class generation from stub ([#29951](https://github.com/laravel/framework/pull/29951)) - -### Refactoring -- Changed imports to Alpha ordering in stubs ([#29954](https://github.com/laravel/framework/pull/29954), [#29958](https://github.com/laravel/framework/pull/29958)) -- Used value helper where possible ([#29959](https://github.com/laravel/framework/pull/29959)) -- Improved readability in `auth.throttle` translation ([#30011](https://github.com/laravel/framework/pull/30011), [#30017](https://github.com/laravel/framework/pull/30017)) - - -## [v6.0.3 (2019-09-10)](https://github.com/laravel/framework/compare/v6.0.2...v6.0.3) - -### Reverted -- Reverted [Wrapped `MySQL` default values in parentheses](https://github.com/laravel/framework/pull/29878) ([#29943](https://github.com/laravel/framework/pull/29943)) - -### Refactoring -- Converted `call_user_func` where appropriate to native calls ([#29932](https://github.com/laravel/framework/pull/29932)) -- Changed imports to Alpha ordering ([#29933](https://github.com/laravel/framework/pull/29933)) - - -## [v6.0.2 (2019-09-10)](https://github.com/laravel/framework/compare/v6.0.1...v6.0.2) - -### Changed -- Used `Application::normalizeCachePath()` method to define cache path`s ([#29890](https://github.com/laravel/framework/pull/29890), [ac9dbf6](https://github.com/laravel/framework/commit/ac9dbf6beaded2ad86f5595958c75e3c4b1147ae)) -- Wrapped `MySQL` default values in parentheses ([#29878](https://github.com/laravel/framework/pull/29878)) - -### Fixed -- Prevent `event auto discovery` from crashing when trying to instantiate files without php classes ([#29895](https://github.com/laravel/framework/pull/29895)) -- Fix resolving class command via container ([#29869](https://github.com/laravel/framework/pull/29869)) - - -## [v6.0.1 (2019-09-06)](https://github.com/laravel/framework/compare/v6.0.0...v6.0.1) - -### Fixed -- Fixed `Schedule::runInBackground()` not fired on Windows ([#29826](https://github.com/laravel/framework/pull/29826)) - -### Changed -- Throw `Symfony\Component\Routing\Exception\RouteNotFoundException` instead of `InvalidArgumentException` in `UrlGenerator::route()` ([#29861](https://github.com/laravel/framework/pull/29861)) - -### Reverted -- Reverted: [`Extract registered event and login to registered method`](https://github.com/laravel/framework/pull/27807) ([#29875](https://github.com/laravel/framework/pull/29875)) - - -## [v6.0.0 (2019-09-03)](https://github.com/laravel/framework/compare/5.8...v6.0.0) - -Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/6.0/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/6.x/releases). diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md deleted file mode 100644 index 6879551e0a1e..000000000000 --- a/CHANGELOG-8.x.md +++ /dev/null @@ -1,569 +0,0 @@ -# Release Notes for 8.x - -## [Unreleased](https://github.com/laravel/framework/compare/v8.22.0...8.x) - - -## [v8.22.0 (2021-01-12)](https://github.com/laravel/framework/compare/v8.21.0...v8.22.0) - -### Added -- Added new lines to `DetectsLostConnections` ([#35752](https://github.com/laravel/framework/pull/35752), [#35790](https://github.com/laravel/framework/pull/35790)) -- Added `Illuminate\Support\Testing\Fakes\EventFake::assertNothingDispatched()` ([#35835](https://github.com/laravel/framework/pull/35835)) -- Added reduce with keys to collections and lazy collections ([#35839](https://github.com/laravel/framework/pull/35839)) - -### Fixed -- Fixed error from missing null check on PHP 8 in `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` ([#35797](https://github.com/laravel/framework/pull/35797)) -- Fix bug with RetryCommand ([4415b94](https://github.com/laravel/framework/commit/4415b94623358bfd1dc2e8f20e4deab0025d2d03), [#35828](https://github.com/laravel/framework/pull/35828)) -- Fixed `Illuminate\Testing\PendingCommand::expectsTable()` ([#35820](https://github.com/laravel/framework/pull/35820)) -- Fixed `morphTo()` attempting to map an empty string morph type to an instance ([#35824](https://github.com/laravel/framework/pull/35824)) - -### Changes -- Update `Illuminate\Http\Resources\CollectsResources::collects()` ([1fa20dd](https://github.com/laravel/framework/commit/1fa20dd356af21af6e38d95e9ff2b1d444344fbe)) -- "null" constraint prevents aliasing SQLite ROWID ([#35792](https://github.com/laravel/framework/pull/35792)) -- Allow strings to be passed to the `report` function ([#35803](https://github.com/laravel/framework/pull/35803)) - - -## [v8.21.0 (2021-01-05)](https://github.com/laravel/framework/compare/v8.20.1...v8.21.0) - -### Added -- Added command to clean batches table ([#35694](https://github.com/laravel/framework/pull/35694), [33f5ac6](https://github.com/laravel/framework/commit/33f5ac695a55d6cdbadcfe1b46e3409e4a66df16)) -- Added item to list of causedByLostConnection errors ([#35744](https://github.com/laravel/framework/pull/35744)) -- Make it possible to set Postmark Message Stream ID ([#35755](https://github.com/laravel/framework/pull/35755)) - -### Fixed -- Fixed `php artisan db` command for the Postgres CLI ([#35725](https://github.com/laravel/framework/pull/35725)) -- Fixed OPTIONS method bug with use same path and diff domain when cache route ([#35714](https://github.com/laravel/framework/pull/35714)) - -### Changed -- Ensure DBAL custom type doesn't exists in `Illuminate\Database\DatabaseServiceProvider::registerDoctrineTypes()` ([#35704](https://github.com/laravel/framework/pull/35704)) -- Added missing `dispatchAfterCommit` to `DatabaseQueue` ([#35715](https://github.com/laravel/framework/pull/35715)) -- Set chain queue when inside a batch ([#35746](https://github.com/laravel/framework/pull/35746)) -- Give a more meaningul message when route parameters are missing ([#35706](https://github.com/laravel/framework/pull/35706)) -- Added table prefix to `Illuminate\Database\Console\DumpCommand::schemaState()` ([4ffe40f](https://github.com/laravel/framework/commit/4ffe40fb169c6bcce9193ff56958eca41e64294f)) -- Refresh the retryUntil time on job retry ([#35780](https://github.com/laravel/framework/pull/35780), [45eb7a7](https://github.com/laravel/framework/commit/45eb7a7b1706ae175268731a673f369c0e556805)) - - -## [v8.20.1 (2020-12-22)](https://github.com/laravel/framework/compare/v8.20.0...v8.20.1) - -### Revert -- Revert [Clear a cached user in RequestGuard if a request is changed](https://github.com/laravel/framework/pull/35692) ([ca8ccd6](https://github.com/laravel/framework/commit/ca8ccd6757d5639f0e5fb241b3df6878da6ce34e)) - - -## [v8.20.0 (2020-12-22)](https://github.com/laravel/framework/compare/v8.19.0...v8.20.0) - -### Added -- Added `Illuminate\Database\DBAL\TimestampType` ([a5761d4](https://github.com/laravel/framework/commit/a5761d4187abea654cb422c2f70054a880ffd2e0), [cff3705](https://github.com/laravel/framework/commit/cff37055cbf031109ae769e8fd6ad1951be47aa6) [382445f](https://github.com/laravel/framework/commit/382445f8487de45a05ebe121837f917b92560a97), [810047e](https://github.com/laravel/framework/commit/810047e1f184f8a4def372885591e4fbb6996b51)) -- Added ability to specify a separate lock connection ([#35621](https://github.com/laravel/framework/pull/35621), [3d95235](https://github.com/laravel/framework/commit/3d95235a6ad8525886071ad68e818a225786064f)) -- Added `Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable::syncWithPivotValues()` ([#35644](https://github.com/laravel/framework/pull/35644), [49b3ce0](https://github.com/laravel/framework/commit/49b3ce098d8a612797b195c4e3774b1e00c604c8)) - -### Fixed -- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) -- Fixed `assertCookieExpired()` and `assertCookieNotExpired()` methods in `Illuminate\Testing\TestResponse` ([#35637](https://github.com/laravel/framework/pull/35637)) -- Fixed: Account for a numerical array of views in Mailable::renderForAssertions() ([#35662](https://github.com/laravel/framework/pull/35662)) -- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) - -### Changed -- Check configuration in `Illuminate\Foundation\Console\Kernel::scheduleCache()` ([a253d0e](https://github.com/laravel/framework/commit/a253d0e40d3deb293d54df9f4455879af5365aab)) -- Modify `Model::mergeCasts` to return `$this` ([#35683](https://github.com/laravel/framework/pull/35683)) -- Clear a cached user in RequestGuard if a request is changed ([#35692](https://github.com/laravel/framework/pull/35692)) - - -## [v8.19.0 (2020-12-15)](https://github.com/laravel/framework/compare/v8.18.1...v8.19.0) - -### Added -- Delay pushing jobs to queue until database transactions are committed ([#35422](https://github.com/laravel/framework/pull/35422), [095d922](https://github.com/laravel/framework/commit/095d9221e837e7a7d8bd00d14184e619b962173a), [fa34d93](https://github.com/laravel/framework/commit/fa34d93ad0cda78e8956b2680ba7bada02bcabb2), [db0d0ba](https://github.com/laravel/framework/commit/db0d0ba94cf8a5c1e1fa4621bd4a16032aff800d), [d9b803a](https://github.com/laravel/framework/commit/d9b803a1a4898e7d5b3145e51c77499815ce3401), [3e55841](https://github.com/laravel/framework/commit/3e5584165fb66d8228bae79a856eac51ce147df5)) -- Added `Illuminate\View\ComponentAttributeBag::has()` ([#35562](https://github.com/laravel/framework/pull/35562)) -- Create ScheduleListCommand ([#35574](https://github.com/laravel/framework/pull/35574), [97d7834](https://github.com/laravel/framework/commit/97d783449c5330b1e5fb9104f6073869ad3079c1)) -- Introducing Job Encryption ([#35527](https://github.com/laravel/framework/pull/35527), [f80f647](https://github.com/laravel/framework/commit/f80f647852106942e4a0ef3e9963f8f7a99122cf), [8c16156](https://github.com/laravel/framework/commit/8c16156636311e42883d9e84a6d71fa135bc2b73)) - -### Fixed -- Handle `Throwable` exceptions on `Illuminate\Redis\Limiters\ConcurrencyLimiter::block()` ([#35546](https://github.com/laravel/framework/pull/35546)) -- Fixed PDO passing in SqlServerDriver ([#35564](https://github.com/laravel/framework/pull/35564)) -- When following redirects, terminate each test request in proper order ([#35604](https://github.com/laravel/framework/pull/35604)) - - -## [v8.18.1 (2020-12-09)](https://github.com/laravel/framework/compare/v8.18.0...v8.18.1) - -### Fixed -- Bumped minimum Symfony version ([#35535](https://github.com/laravel/framework/pull/35535)) -- Fixed passing model instances to factories ([#35541](https://github.com/laravel/framework/pull/35541)) - - -## [v8.18.0 (2020-12-08)](https://github.com/laravel/framework/compare/v8.17.2...v8.18.0) - -### Added -- Added `Illuminate\Http\Client\Factory::assertSentInOrder()` ([#35525](https://github.com/laravel/framework/pull/35525), [d257ce2](https://github.com/laravel/framework/commit/d257ce2e93dfe52151be3d0386fcc4ea281ca8d5), [2fd1411](https://github.com/laravel/framework/commit/2fd141158eb5aead8aa2afff51bcd98250b6bbe6)) -- Added `Illuminate\Http\Client\Response::handlerStats()` ([#35520](https://github.com/laravel/framework/pull/35520)) -- Added support for attaching existing model instances in factories ([#35494](https://github.com/laravel/framework/pull/35494)) -- Added `assertChained()` and `assertDispatchedWithoutChain()` methods to `Illuminate\Support\Testing\Fakes\BusFake` class ([#35523](https://github.com/laravel/framework/pull/35523), [f1b8cac](https://github.com/laravel/framework/commit/f1b8cacfe2a8863894e258ce35a77decedbea36f), [236c67d](https://github.com/laravel/framework/commit/236c67db52f755bb475ba325148e9053733968aa)) -- Allow testing of html and plain text bodies right off mailables ([afb858a](https://github.com/laravel/framework/commit/afb858ad9c944bd3f9ad56c3e4485527d77a7327), [b7391e4](https://github.com/laravel/framework/commit/b7391e486fc68c1c422668a277eaac2bcbe72b2b)) - -### Fixed -- Fixed Application flush method ([#35482](https://github.com/laravel/framework/pull/35482)) -- Fixed mime validation for jpeg files ([#35518](https://github.com/laravel/framework/pull/35518)) - -### Revert -- Revert [Added ability to define table name as default morph type](https://github.com/laravel/framework/pull/35257) ([#35533](https://github.com/laravel/framework/pull/35533)) - - -## [v8.17.2 (2020-12-03)](https://github.com/laravel/framework/compare/v8.17.1...v8.17.2) - -### Added -- Added `Illuminate\Database\Eloquent\Relations\BelongsToMany::orderByPivot()` ([#35455](https://github.com/laravel/framework/pull/35455), [6f83a50](https://github.com/laravel/framework/commit/6f83a5099725dc47fbec1b0cf1bcc64f80f9dc86)) - - -## [v8.17.1 (2020-12-02)](https://github.com/laravel/framework/compare/v8.17.0...v8.17.1) - -### Fixed -- Fixed an issue with the database queue driver ([#35449](https://github.com/laravel/framework/pull/35449)) - - -## [v8.17.0 (2020-12-01)](https://github.com/laravel/framework/compare/v8.16.1...v8.17.0) - -### Added -- Added: Transaction aware code execution ([#35373](https://github.com/laravel/framework/pull/35373), [9565598](https://github.com/laravel/framework/commit/95655988ea1fb0c260ca792751e2e9da81afc3a7)) -- Added dd() and dump() to the request object ([#35384](https://github.com/laravel/framework/pull/35384), [c43e08f](https://github.com/laravel/framework/commit/c43e08f98afe5dcf742956510e9ab170ea11ce45)) -- Enqueue all jobs using a enqueueUsing method ([#35415](https://github.com/laravel/framework/pull/35415), [010d4d7](https://github.com/laravel/framework/commit/010d4d7ea7ec5581dfbf8b6ba84b812f8e4cb649), [#35437](https://github.com/laravel/framework/pull/35437)) - -### Fixed -- Fix issue with polymorphic morphMaps with literal 0 ([#35364](https://github.com/laravel/framework/pull/35364)) -- Fixed Self-Relation issue in withAggregate method ([#35392](https://github.com/laravel/framework/pull/35392), [aec5cca](https://github.com/laravel/framework/commit/aec5cca4ace65bc4b4ca054170b645f1073ac9ca), [#35394](https://github.com/laravel/framework/pull/35394)) -- Fixed Use PHP_EOL instead of `\n` in PendingCommand ([#35409](https://github.com/laravel/framework/pull/35409)) -- Fixed validating image/jpeg images after Symfony/Mime update ([#35419](https://github.com/laravel/framework/pull/35419)) -- Fixed fail to morph with custom casting to objects ([#35420](https://github.com/laravel/framework/pull/35420)) -- Fixed `Illuminate\Collections\Collection::sortBy()` ([307f6fb](https://github.com/laravel/framework/commit/307f6fb8d9579427a9521a07e8700355a3e9d948)) -- Don't overwrite minute and hour when specifying a time with twiceMonthly() ([#35436](https://github.com/laravel/framework/pull/35436)) - -### Changed -- Make DownCommand retryAfter available to prerendered view ([#35357](https://github.com/laravel/framework/pull/35357), [b1ee97e](https://github.com/laravel/framework/commit/b1ee97e5ae03dae293e3256b8c3013209d0fd9b0)) -- Set default value on cloud driver ([0bb7fe4](https://github.com/laravel/framework/commit/0bb7fe4758d617b07b84f6fabfcfe2ca2cdb0964)) -- Update Tailwind pagination focus styles ([#35365](https://github.com/laravel/framework/pull/35365)) -- Redis: allow to pass connection name ([#35402](https://github.com/laravel/framework/pull/35402)) -- Change Wormhole to use the Date Factory ([#35421](https://github.com/laravel/framework/pull/35421)) - - -## [v8.16.1 (2020-11-25)](https://github.com/laravel/framework/compare/v8.16.0...v8.16.1) - -### Fixed -- Fixed reflection exception in `Illuminate\Routing\Router::gatherRouteMiddleware()` ([c6e8357](https://github.com/laravel/framework/commit/c6e8357e19b10a800df8a67446f23310f4e83d1f)) - - -## [v8.16.0 (2020-11-24)](https://github.com/laravel/framework/compare/v8.15.0...v8.16.0) - -### Added -- Added `Illuminate\Console\Concerns\InteractsWithIO::withProgressBar()` ([4e52a60](https://github.com/laravel/framework/commit/4e52a606e91619f6082ed8d46f8d64f9d4dbd0b2), [169fd2b](https://github.com/laravel/framework/commit/169fd2b5156650a067aa77a38681875d2a6c5e57)) -- Added `Illuminate\Console\Concerns\CallsCommands::callSilently()` as alias for `callSilent()` ([7f3101b](https://github.com/laravel/framework/commit/7f3101bf6e8a0f048a243a55be7fc79eb359b609), [0294433](https://github.com/laravel/framework/commit/029443349294e3b6e7bebfe9c23a51a9821ec497)) -- Added option to release unique job locks before processing ([#35255](https://github.com/laravel/framework/pull/35255), [b53f13e](https://github.com/laravel/framework/commit/b53f13ef6c8625176defcb83d2fb8d4d5887d068)) -- Added ably broadcaster ([e0f3f8e](https://github.com/laravel/framework/commit/e0f3f8e8241e1ea34a3a3b8c543871cdc00290bf), [6381aa9](https://github.com/laravel/framework/commit/6381aa994756429156b7376e98606458b052b1d7)) -- Added ability to define table name as default morph type ([#35257](https://github.com/laravel/framework/pull/35257)) -- Allow overriding the MySQL server version for database queue driver ([#35263](https://github.com/laravel/framework/pull/35263)) -- Added `Illuminate\Foundation\Testing\Wormhole::back()` ([#35261](https://github.com/laravel/framework/pull/35261)) -- Support delaying notifications per channel ([#35273](https://github.com/laravel/framework/pull/35273)) -- Allow sorting on multiple criteria ([#35277](https://github.com/laravel/framework/pull/35277), [53eb307](https://github.com/laravel/framework/commit/53eb307fea077299d409adf3ba0307a8fda4c4d1)) -- Added `Illuminate/Database/Console/DbCommand.php` command ([#35304](https://github.com/laravel/framework/pull/35304), [b559b3e](https://github.com/laravel/framework/commit/b559b3e7c4995ef468b35e8a6117ef24fdeca053)) -- Added Collections `splitIn` methods ([#35295](https://github.com/laravel/framework/pull/35295)) - -### Fixed -- Fixed rendering of notifications with config custom theme ([325a335](https://github.com/laravel/framework/commit/325a335ccf45426eabb27131ed48aa6114434c99)) -- Fixing BroadcastException message in PusherBroadcaster@broadcast ([#35290](https://github.com/laravel/framework/pull/35290)) -- Fixed generic DetectsLostConnection string ([#35323](https://github.com/laravel/framework/pull/35323)) -- Fixed SQL Server command generation ([#35317](https://github.com/laravel/framework/pull/35317)) -- Fixed route model binding on cached closure routes ([eb3e262](https://github.com/laravel/framework/commit/eb3e262c870739a6e9705b851e0066b3473eed2b)) - -### Changed -- Disable CSRF on broadcast route ([acb4b77](https://github.com/laravel/framework/commit/acb4b77adc6e257e132e3b036abe1ec88885cfb7)) -- Easily set a null cache driver ([#35262](https://github.com/laravel/framework/pull/35262)) -- Updated `aws/aws-sdk-php` suggest to `^3.155` ([#35267](https://github.com/laravel/framework/pull/35267)) -- Ensure ShouldBeUniqueUntilProcessing job lock is released once ([#35270](https://github.com/laravel/framework/pull/35270)) -- Rename qualifyColumn to qualifyPivotColumn in BelongsToMany & MorphToMany ([#35276](https://github.com/laravel/framework/pull/35276)) -- Check if AsPivot trait is used instead of Pivot Model in `Illuminate\Database\Eloquent\Relations\BelongsToMany` ([#35271](https://github.com/laravel/framework/pull/35271)) -- Avoid no-op database query in Model::destroy() with empty ids ([#35294](https://github.com/laravel/framework/pull/35294)) -- Use --no-owner and --no-acl with pg_restore ([#35309](https://github.com/laravel/framework/pull/35309)) - - -## [v8.15.0 (2020-11-17)](https://github.com/laravel/framework/compare/v8.14.0...v8.15.0) - -### Added -- Added lock support for file and null cache drivers ([#35139](https://github.com/laravel/framework/pull/35139), [a345185](https://github.com/laravel/framework/commit/a3451859d1cff45fba423cf577d00f5b2b648c7a)) -- Added a `doesntExpectOutput` method for console command testing ([#35160](https://github.com/laravel/framework/pull/35160), [c90fc5f](https://github.com/laravel/framework/commit/c90fc5f6b8e91e3f6b0f2f3a74cad7d8a49bc71b)) -- Added support of MorphTo relationship eager loading constraints ([#35190](https://github.com/laravel/framework/pull/35190)) -- Added `Illuminate\Http\ResponseTrait::withoutCookie()` ([e9483c4](https://github.com/laravel/framework/commit/e9483c441d5f0c8598d438d6024db8b1a7aa55fe)) -- Use dynamic app namespace in Eloquent Factory instead of App\ string ([#35204](https://github.com/laravel/framework/pull/35204), [4885bd2](https://github.com/laravel/framework/commit/4885bd2d4ecf79de175d5308569ab0d608e8f55b)) -- Added `read` / `unread` scopes to database notifications ([#35215](https://github.com/laravel/framework/pull/35215)) -- Added `classBasename()` method to `Stringable` ([#35219](https://github.com/laravel/framework/pull/35219)) -- Added before resolving callbacks to container ([#35228](https://github.com/laravel/framework/pull/35228)) -- Adds the possibility of testing file upload content ([#35231](https://github.com/laravel/framework/pull/35231)) -- Added lost connection messages for MySQL persistent connections ([#35224](https://github.com/laravel/framework/pull/35224)) -- Added Support DBAL v3.0 ([#35236](https://github.com/laravel/framework/pull/35236)) - -### Fixed -- Update MySqlSchemaState.php to support MariaDB dump ([#35184](https://github.com/laravel/framework/pull/35184)) -- Fixed pivot and morphpivot fresh and refresh methods ([#35193](https://github.com/laravel/framework/pull/35193)) -- Fixed pivot restoration ([#35218](https://github.com/laravel/framework/pull/35218)) - -### Changed -- Updated `EmailVerificationRequest.php` to check if user is not already verified ([#35174](https://github.com/laravel/framework/pull/35174)) -- Make `Validator::parseNamedParameters()` public ([#35183](https://github.com/laravel/framework/pull/35183)) -- Ignore max attempts if retryUntil is set in `queue:work` ([#35214](https://github.com/laravel/framework/pull/35214)) -- Explode string channels on `Illuminate/Log/LogManager::createStackDriver()` ([e5b86f2](https://github.com/laravel/framework/commit/e5b86f2efec2959fb0e85ad5ee5de18f430643c4)) - - -## [v8.14.0 (2020-11-10)](https://github.com/laravel/framework/compare/v8.13.0...v8.14.0) - -### Added -- Added ability to dispatch unique jobs ([#35042](https://github.com/laravel/framework/pull/35042), [2123e60](https://github.com/laravel/framework/commit/2123e603af027e7590974864715c028357ea4969)) -- Added `Model::encryptUsing()` ([#35080](https://github.com/laravel/framework/pull/35080)) -- Added support to MySQL dump and import using socket ([#35083](https://github.com/laravel/framework/pull/35083), [c43054b](https://github.com/laravel/framework/commit/c43054b9decad4f66937c229e4ef0f32760c8611)) -- Allow custom broadcastWith in notification broadcast channel ([#35142](https://github.com/laravel/framework/pull/35142)) -- Added `Illuminate\Routing\CreatesRegularExpressionRouteConstraints::whereAlphaNumeric()` ([#35154](https://github.com/laravel/framework/pull/35154)) - -### Fixed -- Fixed typo in `make:seeder` command name inside ModelMakeCommand ([#35107](https://github.com/laravel/framework/pull/35107)) -- Fix SQL Server grammar for upsert (missing semicolon) ([#35112](https://github.com/laravel/framework/pull/35112)) -- Respect migration table name in config when dumping schema ([110eb15](https://github.com/laravel/framework/commit/110eb15a77f84da0d83ebc2bb123eec08ecc19ca)) -- Respect theme when previewing notification ([ed4411d](https://github.com/laravel/framework/commit/ed4411d310f259f75e95e882b748ba9d76d7cfad)) -- Fix appendable attributes in Blade components ([#35131](https://github.com/laravel/framework/pull/35131)) -- Remove decrypting array cookies from cookie decrypting ([#35130](https://github.com/laravel/framework/pull/35130)) -- Turn the eloquent collection into a base collection if mapWithKeys loses models ([#35129](https://github.com/laravel/framework/pull/35129)) - -### Changed -- Move dispatching of DatabaseRefreshed event to fire before seeders are run ([#35091](https://github.com/laravel/framework/pull/35091)) -- Handle returning false from reportable callback ([55f0b5e](https://github.com/laravel/framework/commit/55f0b5e7449b87b7340a761bf9e6456fdc8ffc4d)) -- Update `Illuminate\Database\Schema\Grammars\MySqlGrammar::typeTimestamp()` ([#35143](https://github.com/laravel/framework/pull/35143)) -- Remove expectedTables after converting to expectedOutput in PendingCommand ([#35163](https://github.com/laravel/framework/pull/35163)) -- Change SQLite schema command environment variables to work on Windows ([#35164](https://github.com/laravel/framework/pull/35164)) - - -## [v8.13.0 (2020-11-03)](https://github.com/laravel/framework/compare/v8.12.3...v8.13.0) - -### Added -- Added `loadMax()` | `loadMin()` | `loadSum()` | `loadAvg()` methods to `Illuminate\Database\Eloquent\Collection`. Added `loadMax()` | `loadMin()` | `loadSum()` | `loadAvg()` | `loadMorphMax()` | `loadMorphMin()` | `loadMorphSum()` | `loadMorphAvg()` methods to `Illuminate\Database\Eloquent\Model` ([#35029](https://github.com/laravel/framework/pull/35029)) -- Modify `Illuminate\Database\Eloquent\Concerns\QueriesRelationships::has()` method to support MorphTo relations ([#35050](https://github.com/laravel/framework/pull/35050)) -- Added `Illuminate\Support\Stringable::chunk()` ([#35038](https://github.com/laravel/framework/pull/35038)) - -### Fixed -- Fixed a few issues in `Illuminate\Database\Eloquent\Concerns\QueriesRelationships::withAggregate()` ([#35061](https://github.com/laravel/framework/pull/35061), [#35063](https://github.com/laravel/framework/pull/35063)) - -### Changed -- Set chain `queue` | `connection` | `delay` only when explicitly configured in ([#35047](https://github.com/laravel/framework/pull/35047)) - -### Refactoring -- Remove redundant unreachable return statements in some places ([#35053](https://github.com/laravel/framework/pull/35053)) - - -## [v8.12.3 (2020-10-30)](https://github.com/laravel/framework/compare/v8.12.2...v8.12.3) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Concerns\QueriesRelationships::withAggregate()` ([20b0c6e](https://github.com/laravel/framework/commit/20b0c6e19b635466f776502b3f1260c7c51b04ae)) - - -## [v8.12.2 (2020-10-29)](https://github.com/laravel/framework/compare/v8.12.1...v8.12.2) - -### Fixed -- [Add some fixes](https://github.com/laravel/framework/compare/v8.12.1...v8.12.2) - - -## [v8.12.1 (2020-10-29)](https://github.com/laravel/framework/compare/v8.12.0...v8.12.1) - -### Fixed -- Fixed alias usage in `Eloquent` ([6091048](https://github.com/laravel/framework/commit/609104806b8b639710268c75c22f43034c2b72db)) -- Fixed `Illuminate\Support\Reflector::isCallable()` ([a90f344](https://github.com/laravel/framework/commit/a90f344c66f0a5bb1d718f8bbd20c257d4de9e02)) - - -## [v8.12.0 (2020-10-29)](https://github.com/laravel/framework/compare/v8.11.2...v8.12.0) - -### Added -- Added ability to create observers with custom path via `make:observer` command ([#34911](https://github.com/laravel/framework/pull/34911)) -- Added `Illuminate\Database\Eloquent\Factories\Factory::lazy()` ([#34923](https://github.com/laravel/framework/pull/34923)) -- Added ability to make cast with custom stub file via `make:cast` command ([#34930](https://github.com/laravel/framework/pull/34930)) -- ADDED: Custom casts can implement increment/decrement logic ([#34964](https://github.com/laravel/framework/pull/34964)) -- Added encrypted Eloquent cast ([#34937](https://github.com/laravel/framework/pull/34937), [#34948](https://github.com/laravel/framework/pull/34948)) -- Added `DatabaseRefreshed` event to be emitted after database refreshed ([#34952](https://github.com/laravel/framework/pull/34952), [f31bfe2](https://github.com/laravel/framework/commit/f31bfe2fb83829a900f75fccd12af4b69ffb6275)) -- Added `withMax()`|`withMin()`|`withSum()`|`withAvg()` methods to `Illuminate/Database/Eloquent/Concerns/QueriesRelationships` ([#34965](https://github.com/laravel/framework/pull/34965), [f4e4d95](https://github.com/laravel/framework/commit/f4e4d95c8d4c2f63f9bd80c2a4cfa6b2c78bab1b), [#35004](https://github.com/laravel/framework/pull/35004)) -- Added `explain()` to `Query\Builder` and `Eloquent\Builder` ([#34969](https://github.com/laravel/framework/pull/34969)) -- Make `multiple_of` validation rule handle non-integer values ([#34971](https://github.com/laravel/framework/pull/34971)) -- Added `setKeysForSelectQuery` method and use it when refreshing model data in Models ([#34974](https://github.com/laravel/framework/pull/34974)) -- Full PHP 8.0 Support ([#33388](https://github.com/laravel/framework/pull/33388)) -- Added `Illuminate\Support\Reflector::isCallable()` ([#34994](https://github.com/laravel/framework/pull/34994), [8c16891](https://github.com/laravel/framework/commit/8c16891c6e7a4738d63788f4447614056ab5136e), [31917ab](https://github.com/laravel/framework/commit/31917abcfa0db6ec6221bb07fc91b6e768ff5ec8), [11cfa4d](https://github.com/laravel/framework/commit/11cfa4d4c92bf2f023544d58d51b35c5d31dece0), [#34999](https://github.com/laravel/framework/pull/34999)) -- Added route regex registration methods ([#34997](https://github.com/laravel/framework/pull/34997), [3d405cc](https://github.com/laravel/framework/commit/3d405cc2eb66bba97433b46abaca52623c64c94b), [c2df0d5](https://github.com/laravel/framework/commit/c2df0d5faddeb7e58d1832c1c1f0f309619969af)) -- Added dontRelease option to RateLimited and RateLimitedWithRedis job middleware ([#35010](https://github.com/laravel/framework/pull/35010)) - -### Fixed -- Fixed check of file path in `Illuminate\Database\Schema\PostgresSchemaState::load()` ([268237f](https://github.com/laravel/framework/commit/268237fcda420e5c26ab2f0fbdb9b8783c276ff8)) -- Fixed: `PhpRedis (v5.3.2)` cluster - set default connection context to `null` ([#34935](https://github.com/laravel/framework/pull/34935)) -- Fixed Eloquent Model `loadMorph` and `loadMorphCount` methods ([#34972](https://github.com/laravel/framework/pull/34972)) -- Fixed ambigious column on many to many with select load ([5007986](https://github.com/laravel/framework/commit/500798623d100a9746b2931ae6191cb756521f05)) -- Fixed Postgres Dump ([#35018](https://github.com/laravel/framework/pull/35018)) - -### Changed -- Changed `make:factory` command ([#34947](https://github.com/laravel/framework/pull/34947), [4f38176](https://github.com/laravel/framework/commit/4f3817654a6376a2f6cd59dc5fb529ebad1d951f)) -- Make assertSee, assertSeeText, assertDontSee and assertDontSeeText accept an array ([#34982](https://github.com/laravel/framework/pull/34982), [2b98bcc](https://github.com/laravel/framework/commit/2b98bcca598eb919b2afd61e5fb5cb86aec4c706)) - - -## [v8.11.2 (2020-10-20)](https://github.com/laravel/framework/compare/v8.11.1...v8.11.2) - -### Revert -- Revert ["Change loadRoutesFrom to accept $attributes](https://github.com/laravel/framework/pull/34866)" ([#34909](https://github.com/laravel/framework/pull/34909)) - - -## [v8.11.1 (2020-10-20)](https://github.com/laravel/framework/compare/v8.11.0...v8.11.1) - -### Fixed -- Fixed `bound()` method ([a7759d7](https://github.com/laravel/framework/commit/a7759d70e15b0be946569b8299ac694c08a35d7e)) - - -## [v8.11.0 (2020-10-20)](https://github.com/laravel/framework/compare/v8.10.0...v8.11.0) - -### Added -- Added job middleware to prevent overlapping jobs ([#34794](https://github.com/laravel/framework/pull/34794), [eed05b4](https://github.com/laravel/framework/commit/eed05b41097cfe62766d4086ede8dee97c057c29)) -- Bring Rate Limiters to Jobs ([#34829](https://github.com/laravel/framework/pull/34829), [ae00294](https://github.com/laravel/framework/commit/ae00294c418e431372bad0d09ac15d15925247f7)) -- Added `multiple_of` custom replacer in validator ([#34858](https://github.com/laravel/framework/pull/34858)) -- Preserve eloquent collection type after calling ->fresh() ([#34848](https://github.com/laravel/framework/pull/34848)) -- Provisional support for PHP 8.0 for 6.x (Changed some code in 8.x) ([#34884](https://github.com/laravel/framework/pull/34884), [28bb76e](https://github.com/laravel/framework/commit/28bb76efbcfc5fee57307ffa062b67ff709240dc)) - -### Fixed -- Fixed `fresh()` and `refresh()` on pivots and morph pivots ([#34836](https://github.com/laravel/framework/pull/34836)) -- Fixed config `batching` typo ([#34852](https://github.com/laravel/framework/pull/34852)) -- Fixed `Illuminate\Queue\Console\RetryBatchCommand` for un-found batch id ([#34878](https://github.com/laravel/framework/pull/34878)) - -### Changed -- Change `loadRoutesFrom()` to accept group $attributes ([#34866](https://github.com/laravel/framework/pull/34866)) - - -## [v8.10.0 (2020-10-13)](https://github.com/laravel/framework/compare/v8.9.0...v8.10.0) - -### Added -- Allow for chains to be added to batches ([#34612](https://github.com/laravel/framework/pull/34612), [7b4a9ec](https://github.com/laravel/framework/commit/7b4a9ec6c58906eb73957015e4c78f73e780e944)) -- Added `is()` method to 1-1 relations for model comparison ([#34693](https://github.com/laravel/framework/pull/34693), [7ba2577](https://github.com/laravel/framework/commit/7ba257732d2342175a6ffe7db7a4ca847ca1d353)) -- Added `upsert()` to Eloquent and Base Query Builders ([#34698](https://github.com/laravel/framework/pull/34698), [#34712](https://github.com/laravel/framework/pull/34712), [58a0e1b](https://github.com/laravel/framework/commit/58a0e1b7e2bb6df3923883c4fc8cf13b1bce7322)) -- Support psql and pg_restore commands in schema load ([#34711](https://github.com/laravel/framework/pull/34711)) -- Added `Illuminate\Database\Schema\Builder::dropColumns()` method on the schema class ([#34720](https://github.com/laravel/framework/pull/34720)) -- Added `yearlyOn()` method to scheduler ([#34728](https://github.com/laravel/framework/pull/34728)) -- Added `restrictOnDelete()` method to ForeignKeyDefinition class ([#34752](https://github.com/laravel/framework/pull/34752)) -- Added `newLine()` method to `InteractsWithIO` trait ([#34754](https://github.com/laravel/framework/pull/34754)) -- Added `isNotEmpty()` method to HtmlString ([#34774](https://github.com/laravel/framework/pull/34774)) -- Added `delay()` to PendingChain ([#34789](https://github.com/laravel/framework/pull/34789)) -- Added "multiple_of" validation rule ([#34788](https://github.com/laravel/framework/pull/34788)) -- Added custom methods proxy support for jobs `dispatch()` ([#34781](https://github.com/laravel/framework/pull/34781)) -- Added `QueryBuilder::clone()` ([#34780](https://github.com/laravel/framework/pull/34780)) -- Support bus chain on fake ([a952ac24](https://github.com/laravel/framework/commit/a952ac24f34b832270a2f80cd425c2afe4c61fc1)) -- Added missing force flag to `queue:clear` command ([#34809](https://github.com/laravel/framework/pull/34809)) -- Added `dropConstrainedForeignId()` to `Blueprint ([#34806](https://github.com/laravel/framework/pull/34806)) -- Implement `supportsTags()` on the Cache Repository ([#34820](https://github.com/laravel/framework/pull/34820)) -- Added `canAny` to user model ([#34815](https://github.com/laravel/framework/pull/34815)) -- Added `when()` and `unless()` methods to MailMessage ([#34814](https://github.com/laravel/framework/pull/34814)) - -### Fixed -- Fixed collection wrapping in `BelongsToManyRelationship` ([9245807](https://github.com/laravel/framework/commit/9245807f8a1132a30ce669513cf0e99e9e078267)) -- Fixed `LengthAwarePaginator` translations issue ([#34714](https://github.com/laravel/framework/pull/34714)) - -### Changed -- Improve `schedule:work` command ([#34736](https://github.com/laravel/framework/pull/34736), [bbddba2](https://github.com/laravel/framework/commit/bbddba279bc781fc2868a6967430943de636614f)) -- Guard against invalid guard in `make:policy` ([#34792](https://github.com/laravel/framework/pull/34792)) -- Fixed router inconsistency for namespaced route groups ([#34793](https://github.com/laravel/framework/pull/34793)) - - -## [v8.9.0 (2020-10-06)](https://github.com/laravel/framework/compare/v8.8.0...v8.9.0) - -### Added -- Added support `times()` with `raw()` from `Illuminate\Database\Eloquent\Factories\Factory` ([#34667](https://github.com/laravel/framework/pull/34667)) -- Added `Illuminate\Pagination\AbstractPaginator::through()` ([#34657](https://github.com/laravel/framework/pull/34657)) -- Added `extendsFirst()` method similar to `includesFirst()` to view ([#34648](https://github.com/laravel/framework/pull/34648)) -- Allowed `Illuminate\Http\Client\PendingRequest::attach()` method to accept many files ([#34697](https://github.com/laravel/framework/pull/34697), [1bb7ad6](https://github.com/laravel/framework/commit/1bb7ad664a3607f719af2d91c3f95cf71662dcd2)) -- Allowed serializing custom casts when converting a model to an array ([#34702](https://github.com/laravel/framework/pull/34702)) - -### Fixed -- Added missed RESET_THROTTLED constant to Password Facade ([#34641](https://github.com/laravel/framework/pull/34641)) -- Fixed queue clearing when blocking ([#34659](https://github.com/laravel/framework/pull/34659)) -- Fixed missing import in TestView.php ([#34677](https://github.com/laravel/framework/pull/34677)) -- Use `getRealPath` to ensure console command class names are generated correctly in `Illuminate\Foundation\Console\Kernel` ([#34653](https://github.com/laravel/framework/pull/34653)) -- Added `pg_dump --no-owner` and `--no-acl` to avoid owner/permission issues in `Illuminate\Database\Schema\PostgresSchemaState::baseDumpCommand()` ([#34689](https://github.com/laravel/framework/pull/34689)) -- Fixed `queue:failed` command when Class not exists ([#34696](https://github.com/laravel/framework/pull/34696)) - -### Performance -- Increase performance of `Str::before()` by over 60% ([#34642](https://github.com/laravel/framework/pull/34642)) - - -## [v8.8.0 (2020-10-02)](https://github.com/laravel/framework/compare/v8.7.1...v8.8.0) - -### Added -- Proxy URL Generation in `VerifyEmail` ([#34572](https://github.com/laravel/framework/pull/34572)) -- Added `Illuminate\Collections\Traits\EnumeratesValues::pipeInto()` ([#34600](https://github.com/laravel/framework/pull/34600)) -- Added `Illuminate\Http\Client\PendingRequest::withUserAgent()` ([#34611](https://github.com/laravel/framework/pull/34611)) -- Added `schedule:work` command ([#34618](https://github.com/laravel/framework/pull/34618)) -- Added support for appendable (prepends) component attributes ([09b887b](https://github.com/laravel/framework/commit/09b887b85614d3e2539e74f40d7aa9c1c9f903d3), [53fbc9f](https://github.com/laravel/framework/commit/53fbc9f3768f611c960a5d891a1abb259163978a)) - -### Fixed -- Fixed `Illuminate\Http\Client\Response::throw()` ([#34597](https://github.com/laravel/framework/pull/34597)) -- Fixed breaking change in migrate command ([b2a3641](https://github.com/laravel/framework/commit/b2a36411a774dba218fa312b8fd3bcf4be44a4e5)) - -### Changed -- Changing the dump and restore method for a PostgreSQL database ([#34293](https://github.com/laravel/framework/pull/34293)) - - -## [v8.7.1 (2020-09-29)](https://github.com/laravel/framework/compare/v8.7.0...v8.7.1) - -### Fixed -- Remove type hints ([1b3f62a](https://github.com/laravel/framework/commit/1b3f62aaeced2c9761a6052a7f0d3c1a046851c9)) - - -## [v8.7.0 (2020-09-29)](https://github.com/laravel/framework/compare/v8.6.0...v8.7.0) - -### Added -- Added `tg://` protocol in "url" validation rule ([#34464](https://github.com/laravel/framework/pull/34464)) -- Allow dynamic factory methods to obey newFactory method on model ([#34492](https://github.com/laravel/framework/pull/34492), [4708e9e](https://github.com/laravel/framework/commit/4708e9ef8f7cde617a5820f07cfd350daaba0e0f)) -- Added `no-reload` option to `serve` command ([9cc2622](https://github.com/laravel/framework/commit/9cc2622a9122f5108a694856055c13db8a5f80dc)) -- Added `perHour()` and `perDay()` methods to `Illuminate\Cache\RateLimiting\Limit` ([#34530](https://github.com/laravel/framework/pull/34530)) -- Added `Illuminate\Http\Client\Response::onError()` ([#34558](https://github.com/laravel/framework/pull/34558), [d034e2c](https://github.com/laravel/framework/commit/d034e2c55c6502fa0c2bebb6cbf99c5e685beaa5)) -- Added `X-Message-ID` to `Mailgun` and `Ses Transport` ([#34567](https://github.com/laravel/framework/pull/34567)) - -### Fixed -- Fixed incompatibility with Lumen route function in `Illuminate\Session\Middleware\StartSession` ([#34491](https://github.com/laravel/framework/pull/34491)) -- Fixed: Eager loading MorphTo relationship does not honor each models `$keyType` ([#34531](https://github.com/laravel/framework/pull/34531), [c3f44c7](https://github.com/laravel/framework/commit/c3f44c712833d83061452e9a362a5e10fa424863)) -- Fixed translation label ("Pagination Navigation") for the Tailwind blade ([#34568](https://github.com/laravel/framework/pull/34568)) -- Fixed save keys on increment / decrement in Model ([77db028](https://github.com/laravel/framework/commit/77db028225ccd6ec6bc3359f69482f2e4cc95faf)) - -### Changed -- Allow modifiers in date format in Model ([#34507](https://github.com/laravel/framework/pull/34507)) -- Allow for dynamic calls of anonymous component with varied attributes ([#34498](https://github.com/laravel/framework/pull/34498)) -- Cast `Expression` as string so it can be encoded ([#34569](https://github.com/laravel/framework/pull/34569)) - - -## [v8.6.0 (2020-09-22)](https://github.com/laravel/framework/compare/v8.5.0...v8.6.0) - -### Added -- Added `Illuminate\Collections\LazyCollection::takeUntilTimeout()` ([0aabf24](https://github.com/laravel/framework/commit/0aabf2472850a9d573907ca092bf5e3cfe26fab3)) -- Added `--schema-path` option to `migrate:fresh` command ([#34419](https://github.com/laravel/framework/pull/34419)) - -### Fixed -- Fixed problems with dots in validator ([#34355](https://github.com/laravel/framework/pull/34355)) -- Maintenance mode: Fix empty Retry-After header ([#34412](https://github.com/laravel/framework/pull/34412)) -- Fixed bug with error handling in closure scheduled tasks ([#34420](https://github.com/laravel/framework/pull/34420)) -- Don't double escape on `ComponentTagCompiler.php` ([12ba0d9](https://github.com/laravel/framework/commit/12ba0d937d54e81eccf8f0a80150f0d70604e1c2)) -- Fixed `mysqldump: unknown variable 'column-statistics=0` for MariaDB schema dump ([#34442](https://github.com/laravel/framework/pull/34442)) - - -## [v8.5.0 (2020-09-19)](https://github.com/laravel/framework/compare/v8.4.0...v8.5.0) - -### Added -- Allow clearing an SQS queue by `queue:clear` command ([#34383](https://github.com/laravel/framework/pull/34383), [de811ea](https://github.com/laravel/framework/commit/de811ea7f7dc7ecfc686b25fba48e4b0dac473e6)) -- Added `Illuminate\Foundation\Auth\EmailVerificationRequest` ([4bde31b](https://github.com/laravel/framework/commit/4bde31b24bf01b4d4a35ad31fafd8e4ca203b0f2)) -- Auto handle `Jsonable` values passed to `castAsJson()` ([#34392](https://github.com/laravel/framework/pull/34392)) -- Added `crossJoinSub()` method to the query builder ([#34400](https://github.com/laravel/framework/pull/34400)) -- Added `Illuminate\Session\Store::passwordConfirmed()` ([fb3f45a](https://github.com/laravel/framework/commit/fb3f45aa0142764c5c29b97e8bcf8328091986e9)) - -### Changed -- Check for view existence first in `Illuminate\Mail\Markdown::render()` ([5f78c90](https://github.com/laravel/framework/commit/5f78c90a7af118dd07703a78da06586016973a66)) -- Guess the model name when using the `make:factory` command ([#34373](https://github.com/laravel/framework/pull/34373)) - - -## [v8.4.0 (2020-09-16)](https://github.com/laravel/framework/compare/v8.3.0...v8.4.0) - -### Added -- Added SQLite schema dump support ([#34323](https://github.com/laravel/framework/pull/34323)) -- Added `queue:clear` command ([#34330](https://github.com/laravel/framework/pull/34330), [06b378c](https://github.com/laravel/framework/commit/06b378c07b2ea989aa3e947ca003e96ea277153c)) - -### Fixed -- Fixed `minimal.blade.php` ([#34379](https://github.com/laravel/framework/pull/34379)) -- Don't double escape on ComponentTagCompiler.php ([ec75487](https://github.com/laravel/framework/commit/ec75487062506963dd27a4302fe3680c0e3681a3)) -- Fixed dots in attribute names in `DynamicComponent` ([2d1d962](https://github.com/laravel/framework/commit/2d1d96272a94bce123676ed742af2d80ba628ba4)) - -### Changed -- Show warning when view exists when using artisan `make:component` ([#34376](https://github.com/laravel/framework/pull/34376), [0ce75e0](https://github.com/laravel/framework/commit/0ce75e01a66ba4b13bbe4cbed85564f1dc76bb05)) -- Call the booting/booted callbacks from the container ([#34370](https://github.com/laravel/framework/pull/34370)) - - -## [v8.3.0 (2020-09-15)](https://github.com/laravel/framework/compare/v8.2.0...v8.3.0) - -### Added -- Added `Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase::castAsJson()` ([#34302](https://github.com/laravel/framework/pull/34302)) -- Handle array hosts in `Illuminate\Database\Schema\MySqlSchemaState` ([0920c23](https://github.com/laravel/framework/commit/0920c23efb9d7042d074729f2f70acbfec629c14)) -- Added `Illuminate\Pipeline\Pipeline::setContainer()` ([#34343](https://github.com/laravel/framework/pull/34343)) -- Allow including a closure in a queued batch ([#34333](https://github.com/laravel/framework/pull/34333)) - -### Fixed -- Fixed broken Seeder ([9e4a866](https://github.com/laravel/framework/commit/9e4a866cfb0420f4ea6cb4e86b1fbd97a4b8c264)) - -### Changed -- Bumped minimum vlucas/phpdotenv version ([#34336](https://github.com/laravel/framework/pull/34336)) -- Pass an instance of the job to queued closures ([#34350](https://github.com/laravel/framework/pull/34350)) - - -## [v8.2.0 (2020-09-14)](https://github.com/laravel/framework/compare/v8.1.0...v8.2.0) - -### Added -- Added `Illuminate\Database\Eloquent\Factories\HasFactory::newFactory()` ([4a95372](https://github.com/laravel/framework/commit/4a953728f5e085342d793372329ae534e5885724), [a2cea84](https://github.com/laravel/framework/commit/a2cea84805f311be612fc36c403fcc6f90181ff4)) - -### Fixed -- Do not used `now` helper in `Illuminate/Cache/DatabaseLock::expiresAt()` ([#34262](https://github.com/laravel/framework/pull/34262)) -- Change placeholder in `Illuminate\Database\Schema\MySqlSchemaState::load()` ([#34303](https://github.com/laravel/framework/pull/34303)) -- Fixed bug in dynamic attributes `Illuminate\View\ComponentAttributeBag::setAttributes()` ([93f4613](https://github.com/laravel/framework/commit/93f461344051e8d44c4a50748b7bdc0eae18bcac)) -- Fixed `Illuminate\View\ComponentAttributeBag::whereDoesntStartWith()` ([#34329](https://github.com/laravel/framework/pull/34329)) -- Fixed `Illuminate\Routing\Middleware\ThrottleRequests::handleRequestUsingNamedLimiter()` ([#34325](https://github.com/laravel/framework/pull/34325)) - -### Changed -- Create Faker when a Factory is created ([#34298](https://github.com/laravel/framework/pull/34298)) - - -## [v8.1.0 (2020-09-11)](https://github.com/laravel/framework/compare/v8.0.4...v8.1.0) - -### Added -- Added `Illuminate\Database\Eloquent\Factories\Factory::raw()` ([#34278](https://github.com/laravel/framework/pull/34278)) -- Added `Illuminate\Database\Eloquent\Factories\Factory::createMany()` ([#34285](https://github.com/laravel/framework/pull/34285), [69072c7](https://github.com/laravel/framework/commit/69072c7d3efd2784d195cb95e45e4dcb8ef5907f)) -- Added the `Countable` interface to `AssertableJsonString` ([#34284](https://github.com/laravel/framework/pull/34284)) - -### Fixed -- Fixed the new maintenance mode ([#34264](https://github.com/laravel/framework/pull/34264)) - -### Changed -- Optimize command can also cache view ([#34287](https://github.com/laravel/framework/pull/34287)) - - -## [v8.0.4 (2020-09-11)](https://github.com/laravel/framework/compare/v8.0.3...v8.0.4) - -### Changed -- Allow `Illuminate\Collections\Collection::implode()` when instance of `Stringable` ([#34271](https://github.com/laravel/framework/pull/34271)) - -### Fixed -- Fixed `DatabaseUuidFailedJobProvider::find()` job record structure ([#34251](https://github.com/laravel/framework/pull/34251)) -- Cast linkCollection to array in JSON pagination responses ([#34245](https://github.com/laravel/framework/pull/34245)) -- Change the placeholder of schema dump according to symfony placeholder in `MySqlSchemaState::dump()` ([#34261](https://github.com/laravel/framework/pull/34261)) -- Fixed problems with dots in validator ([8723739](https://github.com/laravel/framework/commit/8723739746a53442a5ec5bdebe649f8a4d9dd3c2)) - - -## [v8.0.3 (2020-09-10)](https://github.com/laravel/framework/compare/v8.0.2...v8.0.3) - -### Added -- Added links property to JSON pagination responses ([13751a1](https://github.com/laravel/framework/commit/13751a187834fabe515c14fb3ac1dc008fd23f37)) - -### Fixed -- Fixed bugs with factory creation in `FactoryMakeCommand` ([c7186e0](https://github.com/laravel/framework/commit/c7186e09204cb3ed72ab24fe9f25a6450c2512bb)) - - -## [v8.0.2 (2020-09-09)](https://github.com/laravel/framework/compare/v8.0.1...v8.0.2) - -### Revert -- Revert of ["Fixed for empty fallback_locale in `Illuminate\Translation\Translator`"](https://github.com/laravel/framework/pull/34136) ([7c54eb6](https://github.com/laravel/framework/commit/7c54eb678d58fb9ee7f532a5a5842e6f0e1fe4c9)) - -### Changed -- Update `Illuminate\Database\Schema\MySqlSchemaState::executeDumpProcess()` ([#34233](https://github.com/laravel/framework/pull/34233)) - - -## [v8.0.1 (2020-09-09)](https://github.com/laravel/framework/compare/v8.0.0...v8.0.1) - -### Added -- Support array syntax in `Illuminate\Routing\Route::uses()` ([f80ba11](https://github.com/laravel/framework/commit/f80ba11b698b6130bdbc7ffdcb947519deabbdba)) - -### Fixed -- Fixed `BatchRepositoryFake` TypeError ([#34225](https://github.com/laravel/framework/pull/34225)) -- Fixed dynamic component bug ([4b1e317](https://github.com/laravel/framework/commit/4b1e317c7aec22c2767766bb8b84e059fe4e0802)) - -### Changed -- Give shadow a rounded edge to match content in `tailwind.blade.php` ([#34198](https://github.com/laravel/framework/pull/34198)) -- Pass the request to the renderable callback in `Illuminate\Foundation\Exceptions\Handler::render()` ([#34200](https://github.com/laravel/framework/pull/34200)) -- Update `Illuminate\Database\Schema\MySqlSchemaState` ([d67be130](https://github.com/laravel/framework/commit/d67be1305bef418d9bdeb8192177202f9d705699), [c87794f](https://github.com/laravel/framework/commit/c87794fc354941729d1f0c4607693c0b8d2cfda2)) -- Respect local env in `Illuminate\Foundation\Console\ServeCommand::startProcess()` ([75e792d](https://github.com/laravel/framework/commit/75e792d61871780f75ecb4eb170826b0ba2f305e)) - - -## [v8.0.0 (2020-09-08)](https://github.com/laravel/framework/compare/v7.27.0...v8.0.0) - -Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/8.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/8.x/releases). diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000000..fb052fd0a63c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Release Notes for 9.x + +## [Unreleased](https://github.com/laravel/framework/compare/v9.0.0...9.x) + + +## [v9.0.0 (2020-??-??)](https://github.com/laravel/framework/compare/v8.22.0...v9.0.0) + +Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/9.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/9.x/releases). From c377b2b607346675d8c72917ce434e1d2f936458 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Jan 2021 15:04:52 +0100 Subject: [PATCH 087/194] Remove test --- tests/Database/DatabaseMysqlBuilderTest.php | 48 --------------------- 1 file changed, 48 deletions(-) delete mode 100644 tests/Database/DatabaseMysqlBuilderTest.php diff --git a/tests/Database/DatabaseMysqlBuilderTest.php b/tests/Database/DatabaseMysqlBuilderTest.php deleted file mode 100644 index dd36209eb40e..000000000000 --- a/tests/Database/DatabaseMysqlBuilderTest.php +++ /dev/null @@ -1,48 +0,0 @@ -shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); - $connection->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8mb4_unicode_ci'); - $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('statement')->once()->with( - 'create database `my_temporary_database` default character set `utf8mb4` default collate `utf8mb4_unicode_ci`' - )->andReturn(true); - - $builder = new MySqlBuilder($connection); - $builder->createDatabase('my_temporary_database'); - } - - public function testDropDatabaseIfExists() - { - $grammar = new MySqlGrammar(); - - $connection = m::mock(Connection::class); - $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('statement')->once()->with( - 'drop database if exists `my_database_a`' - )->andReturn(true); - - $builder = new MySqlBuilder($connection); - - $builder->dropDatabaseIfExists('my_database_a'); - } -} From c17c67bc238e134de9b62c5376c8ba011b5820d0 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Jan 2021 15:05:20 +0100 Subject: [PATCH 088/194] Re-add test with renamed file --- tests/Database/DatabaseMySqlBuilderTest.php | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/Database/DatabaseMySqlBuilderTest.php diff --git a/tests/Database/DatabaseMySqlBuilderTest.php b/tests/Database/DatabaseMySqlBuilderTest.php new file mode 100644 index 000000000000..dd36209eb40e --- /dev/null +++ b/tests/Database/DatabaseMySqlBuilderTest.php @@ -0,0 +1,48 @@ +shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); + $connection->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8mb4_unicode_ci'); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database `my_temporary_database` default character set `utf8mb4` default collate `utf8mb4_unicode_ci`' + )->andReturn(true); + + $builder = new MySqlBuilder($connection); + $builder->createDatabase('my_temporary_database'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new MySqlGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists `my_database_a`' + )->andReturn(true); + + $builder = new MySqlBuilder($connection); + + $builder->dropDatabaseIfExists('my_database_a'); + } +} From 6ba34a3cc2e4a8fbd8e0b8934662d0f4ce1ccec5 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Jan 2021 20:02:40 +0100 Subject: [PATCH 089/194] Bump CronExpression minimum version (#35984) --- composer.json | 2 +- src/Illuminate/Console/Scheduling/Event.php | 2 +- src/Illuminate/Console/Scheduling/ScheduleListCommand.php | 5 ++++- src/Illuminate/Console/composer.json | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 79bea59f041d..7c66b17ea08d 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "ext-mbstring": "*", "ext-openssl": "*", "doctrine/inflector": "^1.4|^2.0", - "dragonmantank/cron-expression": "^3.0.2", + "dragonmantank/cron-expression": "^3.1", "egulias/email-validator": "^2.1.10", "league/commonmark": "^1.3", "league/flysystem": "^2.0", diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 0bfaeaf8c429..2e14fd56e4a2 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -328,7 +328,7 @@ protected function expressionPasses() $date->setTimezone($this->timezone); } - return CronExpression::factory($this->expression)->isDue($date->toDateTimeString()); + return (new CronExpression($this->expression))->isDue($date->toDateTimeString()); } /** diff --git a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php index bc8cecfe0618..abd722dbfcb8 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php @@ -3,6 +3,7 @@ namespace Illuminate\Console\Scheduling; use Cron\CronExpression; +use DateTimeZone; use Illuminate\Console\Command; use Illuminate\Support\Carbon; @@ -47,7 +48,9 @@ public function handle(Schedule $schedule) $event->description, (new CronExpression($event->expression)) ->getNextRunDate(Carbon::now()) - ->setTimezone($this->option('timezone', config('app.timezone'))), + ->setTimezone( + new DateTimeZone($this->option('timezone') ?? config('app.timezone')) + ), ]; } diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index b3fae079a42c..fe6560a9465c 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -33,7 +33,7 @@ } }, "suggest": { - "dragonmantank/cron-expression": "Required to use scheduler (^3.0.2).", + "dragonmantank/cron-expression": "Required to use scheduler (^3.1).", "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^7.2).", "illuminate/bus": "Required to use the scheduled job dispatcher (^9.0).", "illuminate/container": "Required to use the scheduler (^9.0).", From 09a233672f1d3c55736d2f0ef176b38917bb092f Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Jan 2021 20:03:49 +0100 Subject: [PATCH 090/194] Drop doctrine/inflector v1 (#35983) Co-authored-by: Taylor Otwell --- composer.json | 2 +- src/Illuminate/Support/composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 7c66b17ea08d..621cd40ac5d8 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "doctrine/inflector": "^1.4|^2.0", + "doctrine/inflector": "^2.0", "dragonmantank/cron-expression": "^3.1", "egulias/email-validator": "^2.1.10", "league/commonmark": "^1.3", diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index b59cc6907f7a..5ae3cc5da694 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -17,7 +17,7 @@ "php": "^7.3|^8.0", "ext-json": "*", "ext-mbstring": "*", - "doctrine/inflector": "^1.4|^2.0", + "doctrine/inflector": "^2.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", From eaf1ab7dbcdde25dbb95020cbf4bfff9d1f35cc3 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Jan 2021 20:07:05 +0100 Subject: [PATCH 091/194] [9.x] Bump DBAL to 2.12 (#35974) * Bump DBAL to 2.12 * Fix invalid signatures * Remove conflict * inheritdoc * DocBlocks --- composer.json | 4 ++-- src/Illuminate/Database/Connection.php | 2 +- .../Database/DBAL/TimestampType.php | 2 +- src/Illuminate/Database/MySqlConnection.php | 6 ++---- .../PDO/Concerns/ConnectsToDatabase.php | 7 +++++-- src/Illuminate/Database/PDO/MySqlDriver.php | 8 ++++++++ .../Database/PDO/PostgresDriver.php | 8 ++++++++ src/Illuminate/Database/PDO/SQLiteDriver.php | 8 ++++++++ .../Database/PDO/SqlServerDriver.php | 19 ++++++++++++++++++- .../Database/PostgresConnection.php | 6 ++---- src/Illuminate/Database/SQLiteConnection.php | 6 ++---- .../Database/SqlServerConnection.php | 6 ++---- src/Illuminate/Database/composer.json | 2 +- 13 files changed, 60 insertions(+), 24 deletions(-) diff --git a/composer.json b/composer.json index 621cd40ac5d8..13841b98a206 100644 --- a/composer.json +++ b/composer.json @@ -79,7 +79,7 @@ }, "require-dev": { "aws/aws-sdk-php": "^3.155", - "doctrine/dbal": "^2.6|^3.0", + "doctrine/dbal": "^2.12|^3.0", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^7.2", "league/flysystem-aws-s3-v3": "^2.0", @@ -132,7 +132,7 @@ "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", "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.12|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^7.2).", diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index b4fa6d4c3a0d..fee34f251808 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -920,7 +920,7 @@ public function getDoctrineConnection() $this->doctrineConnection = new DoctrineConnection(array_filter([ 'pdo' => $this->getPdo(), 'dbname' => $this->getDatabaseName(), - 'driver' => method_exists($driver, 'getName') ? $driver->getName() : null, + 'driver' => $driver->getName(), 'serverVersion' => $this->getConfig('server_version'), ]), $driver); } diff --git a/src/Illuminate/Database/DBAL/TimestampType.php b/src/Illuminate/Database/DBAL/TimestampType.php index 0ab733cfe520..8132b03ffb5d 100644 --- a/src/Illuminate/Database/DBAL/TimestampType.php +++ b/src/Illuminate/Database/DBAL/TimestampType.php @@ -2,7 +2,7 @@ namespace Illuminate\Database\DBAL; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index 9760358cf5f4..91f01a030099 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -2,8 +2,6 @@ namespace Illuminate\Database; -use Doctrine\DBAL\Driver\PDOMySql\Driver as DoctrineDriver; -use Doctrine\DBAL\Version; use Illuminate\Database\PDO\MySqlDriver; use Illuminate\Database\Query\Grammars\MySqlGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\MySqlProcessor; @@ -84,10 +82,10 @@ protected function getDefaultPostProcessor() /** * Get the Doctrine DBAL driver. * - * @return \Doctrine\DBAL\Driver\PDOMySql\Driver|\Illuminate\Database\PDO\MySqlDriver + * @return \Illuminate\Database\PDO\MySqlDriver */ protected function getDoctrineDriver() { - return class_exists(Version::class) ? new DoctrineDriver : new MySqlDriver; + return new MySqlDriver; } } diff --git a/src/Illuminate/Database/PDO/Concerns/ConnectsToDatabase.php b/src/Illuminate/Database/PDO/Concerns/ConnectsToDatabase.php index 637c62ce1f5d..0529ca8eb600 100644 --- a/src/Illuminate/Database/PDO/Concerns/ConnectsToDatabase.php +++ b/src/Illuminate/Database/PDO/Concerns/ConnectsToDatabase.php @@ -10,10 +10,13 @@ trait ConnectsToDatabase /** * Create a new database connection. * - * @param array $params + * @param mixed[] $params + * @param string|null $username + * @param string|null $password + * @param mixed[] $driverOptions * @return \Illuminate\Database\PDO\Connection */ - public function connect(array $params) + public function connect(array $params, $username = null, $password = null, array $driverOptions = []) { if (! isset($params['pdo']) || ! $params['pdo'] instanceof PDO) { throw new \InvalidArgumentException('Laravel requires the "pdo" property to be set and be a PDO instance.'); diff --git a/src/Illuminate/Database/PDO/MySqlDriver.php b/src/Illuminate/Database/PDO/MySqlDriver.php index 5f68c6fab5a4..54ac37536189 100644 --- a/src/Illuminate/Database/PDO/MySqlDriver.php +++ b/src/Illuminate/Database/PDO/MySqlDriver.php @@ -8,4 +8,12 @@ class MySqlDriver extends AbstractMySQLDriver { use ConnectsToDatabase; + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'pdo_mysql'; + } } diff --git a/src/Illuminate/Database/PDO/PostgresDriver.php b/src/Illuminate/Database/PDO/PostgresDriver.php index eb29c969de58..0d9561107cc9 100644 --- a/src/Illuminate/Database/PDO/PostgresDriver.php +++ b/src/Illuminate/Database/PDO/PostgresDriver.php @@ -8,4 +8,12 @@ class PostgresDriver extends AbstractPostgreSQLDriver { use ConnectsToDatabase; + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'pdo_pgsql'; + } } diff --git a/src/Illuminate/Database/PDO/SQLiteDriver.php b/src/Illuminate/Database/PDO/SQLiteDriver.php index 2dac06db8be0..f50da08e7d15 100644 --- a/src/Illuminate/Database/PDO/SQLiteDriver.php +++ b/src/Illuminate/Database/PDO/SQLiteDriver.php @@ -8,4 +8,12 @@ class SQLiteDriver extends AbstractSQLiteDriver { use ConnectsToDatabase; + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'pdo_sqlite'; + } } diff --git a/src/Illuminate/Database/PDO/SqlServerDriver.php b/src/Illuminate/Database/PDO/SqlServerDriver.php index bbb3bbd32397..d1f2ae5b2ab0 100644 --- a/src/Illuminate/Database/PDO/SqlServerDriver.php +++ b/src/Illuminate/Database/PDO/SqlServerDriver.php @@ -6,10 +6,27 @@ class SqlServerDriver extends AbstractSQLServerDriver { - public function connect(array $params) + /** + * Create a new database connection. + * + * @param mixed[] $params + * @param string|null $username + * @param string|null $password + * @param mixed[] $driverOptions + * @return \Illuminate\Database\PDO\Connection + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = []) { return new SqlServerConnection( new Connection($params['pdo']) ); } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'pdo_sqlsrv'; + } } diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index 009a02b37def..1fc77439b87f 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -2,8 +2,6 @@ namespace Illuminate\Database; -use Doctrine\DBAL\Driver\PDOPgSql\Driver as DoctrineDriver; -use Doctrine\DBAL\Version; use Illuminate\Database\PDO\PostgresDriver; use Illuminate\Database\Query\Grammars\PostgresGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\PostgresProcessor; @@ -99,10 +97,10 @@ protected function getDefaultPostProcessor() /** * Get the Doctrine DBAL driver. * - * @return \Doctrine\DBAL\Driver\PDOPgSql\Driver|\Illuminate\Database\PDO\PostgresDriver + * @return \Illuminate\Database\PDO\PostgresDriver */ protected function getDoctrineDriver() { - return class_exists(Version::class) ? new DoctrineDriver : new PostgresDriver; + return new PostgresDriver; } } diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 38116877c3ca..59b5edb210b2 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -2,8 +2,6 @@ namespace Illuminate\Database; -use Doctrine\DBAL\Driver\PDOSqlite\Driver as DoctrineDriver; -use Doctrine\DBAL\Version; use Illuminate\Database\PDO\SQLiteDriver; use Illuminate\Database\Query\Grammars\SQLiteGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\SQLiteProcessor; @@ -98,11 +96,11 @@ protected function getDefaultPostProcessor() /** * Get the Doctrine DBAL driver. * - * @return \Doctrine\DBAL\Driver\PDOSqlite\Driver|\Illuminate\Database\PDO\SQLiteDriver + * @return \Illuminate\Database\PDO\SQLiteDriver */ protected function getDoctrineDriver() { - return class_exists(Version::class) ? new DoctrineDriver : new SQLiteDriver; + return new SQLiteDriver; } /** diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index b0b8490d062a..f93c499cb6a7 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -3,8 +3,6 @@ namespace Illuminate\Database; use Closure; -use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as DoctrineDriver; -use Doctrine\DBAL\Version; use Illuminate\Database\PDO\SqlServerDriver; use Illuminate\Database\Query\Grammars\SqlServerGrammar as QueryGrammar; use Illuminate\Database\Query\Processors\SqlServerProcessor; @@ -116,10 +114,10 @@ protected function getDefaultPostProcessor() /** * Get the Doctrine DBAL driver. * - * @return \Doctrine\DBAL\Driver\PDOSqlsrv\Driver|\Illuminate\Database\PDO\SqlServerDriver + * @return \Illuminate\Database\PDO\SqlServerDriver */ protected function getDoctrineDriver() { - return class_exists(Version::class) ? new DoctrineDriver : new SqlServerDriver; + return new SqlServerDriver; } } diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 43c24ef2c3a4..43fd5410ef8e 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -35,7 +35,7 @@ } }, "suggest": { - "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.12|^3.0).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", "illuminate/console": "Required to use the database commands (^9.0).", "illuminate/events": "Required to use the observers with Eloquent (^9.0).", From 2bef36cfadaa61ec5e28f2ab326e3662c6d6d07e Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 21 Jan 2021 22:16:29 +0000 Subject: [PATCH 092/194] Fixes ParallelTesting::token() return type in docs (#35985) --- src/Illuminate/Support/Facades/ParallelTesting.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/ParallelTesting.php b/src/Illuminate/Support/Facades/ParallelTesting.php index deed8a1b6aba..641f9fe90eae 100644 --- a/src/Illuminate/Support/Facades/ParallelTesting.php +++ b/src/Illuminate/Support/Facades/ParallelTesting.php @@ -7,7 +7,7 @@ * @method static void setUpTestCase(callable $callback) * @method static void tearDownProcess(callable $callback) * @method static void tearDownTestCase(callable $callback) - * @method static string token() + * @method static int|false token() * * @see \Illuminate\Testing\ParallelTesting */ From f6640f80613f57002aa26c632dd2d5f896d33719 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Sun, 24 Jan 2021 19:56:21 -0500 Subject: [PATCH 093/194] Default uuid column name (#36005) --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- tests/Database/DatabaseMySqlSchemaGrammarTest.php | 10 ++++++++++ tests/Database/DatabasePostgresSchemaGrammarTest.php | 10 ++++++++++ tests/Database/DatabaseSQLiteSchemaGrammarTest.php | 10 ++++++++++ tests/Database/DatabaseSqlServerSchemaGrammarTest.php | 10 ++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index f8c273fbcbc6..e90157e4911b 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1176,7 +1176,7 @@ public function binary($column) * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function uuid($column) + public function uuid($column = 'uuid') { return $this->addColumn('uuid', $column); } diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index ebb190ccb46b..84a8090e1a29 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -978,6 +978,16 @@ public function testAddingUuid() $this->assertSame('alter table `users` add `foo` char(36) not null', $statements[0]); } + public function testAddingUuidDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->uuid(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table `users` add `uuid` char(36) not null', $statements[0]); + } + public function testAddingForeignUuid() { $blueprint = new Blueprint('users'); diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 7e10fae23d55..ac2758f37690 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -778,6 +778,16 @@ public function testAddingUuid() $this->assertSame('alter table "users" add column "foo" uuid not null', $statements[0]); } + public function testAddingUuidDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->uuid(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "uuid" uuid not null', $statements[0]); + } + public function testAddingForeignUuid() { $blueprint = new Blueprint('users'); diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index cc6663e7463e..e77e21578cbe 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -710,6 +710,16 @@ public function testAddingUuid() $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); } + public function testAddingUuidDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->uuid(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "uuid" varchar not null', $statements[0]); + } + public function testAddingForeignUuid() { $blueprint = new Blueprint('users'); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 4513a93001a3..c80c8c484f4b 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -740,6 +740,16 @@ public function testAddingUuid() $this->assertSame('alter table "users" add "foo" uniqueidentifier not null', $statements[0]); } + public function testAddingUuidDefaultsColumnName() + { + $blueprint = new Blueprint('users'); + $blueprint->uuid(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add "uuid" uniqueidentifier not null', $statements[0]); + } + public function testAddingForeignUuid() { $blueprint = new Blueprint('users'); From be9e960592c497ced062992ed929974cecc359cb Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 25 Jan 2021 16:20:42 +0000 Subject: [PATCH 094/194] [9.x] Drop PHP 7.3 (#36038) * Drop PHP 7.3 * Update tests.yml --- .github/workflows/tests.yml | 4 ++-- composer.json | 2 +- src/Illuminate/Auth/composer.json | 2 +- src/Illuminate/Broadcasting/composer.json | 2 +- src/Illuminate/Bus/composer.json | 2 +- src/Illuminate/Cache/composer.json | 2 +- src/Illuminate/Collections/composer.json | 2 +- src/Illuminate/Config/composer.json | 2 +- src/Illuminate/Console/composer.json | 2 +- src/Illuminate/Container/composer.json | 2 +- src/Illuminate/Contracts/composer.json | 2 +- src/Illuminate/Cookie/composer.json | 2 +- src/Illuminate/Database/composer.json | 2 +- src/Illuminate/Encryption/composer.json | 2 +- src/Illuminate/Events/composer.json | 2 +- src/Illuminate/Filesystem/composer.json | 2 +- src/Illuminate/Hashing/composer.json | 2 +- src/Illuminate/Http/composer.json | 2 +- src/Illuminate/Log/composer.json | 2 +- src/Illuminate/Macroable/composer.json | 2 +- src/Illuminate/Mail/composer.json | 2 +- src/Illuminate/Notifications/composer.json | 2 +- src/Illuminate/Pagination/composer.json | 2 +- src/Illuminate/Pipeline/composer.json | 2 +- src/Illuminate/Queue/composer.json | 2 +- src/Illuminate/Redis/composer.json | 2 +- src/Illuminate/Routing/composer.json | 2 +- src/Illuminate/Session/composer.json | 2 +- src/Illuminate/Support/composer.json | 2 +- src/Illuminate/Testing/composer.json | 2 +- src/Illuminate/Translation/composer.json | 2 +- src/Illuminate/Validation/composer.json | 2 +- src/Illuminate/View/composer.json | 2 +- 33 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0c350be13ef8..e69137d62315 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: true matrix: - php: [7.3, 7.4, 8.0] + php: [7.4, 8.0] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} @@ -70,7 +70,7 @@ jobs: strategy: fail-fast: true matrix: - php: [7.3, 7.4, 8.0] + php: [7.4, 8.0] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - Windows diff --git a/composer.json b/composer.json index 13841b98a206..5f33553c4fee 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", diff --git a/src/Illuminate/Auth/composer.json b/src/Illuminate/Auth/composer.json index cb6324fdeda8..4c25696b8495 100644 --- a/src/Illuminate/Auth/composer.json +++ b/src/Illuminate/Auth/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/http": "^9.0", diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index 26eec56f3179..edcfdceed74c 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "psr/log": "^1.0", "illuminate/bus": "^9.0", diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index a4a6ffd4491a..612a66bad68f 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/pipeline": "^9.0", diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index e815077edd40..a0da4140dbed 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index ad5fa838dfba..c41776dbdec8 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0" }, diff --git a/src/Illuminate/Config/composer.json b/src/Illuminate/Config/composer.json index cc99f0bf6ef9..112bed557786 100755 --- a/src/Illuminate/Config/composer.json +++ b/src/Illuminate/Config/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0" }, diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index fe6560a9465c..23312f86c46e 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index ea2ff77624ac..48b14c5136ad 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/contracts": "^9.0", "psr/container": "^1.0" }, diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index 4297db965d20..efd4563da3a1 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "psr/container": "^1.0", "psr/simple-cache": "^1.0" }, diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 1fffb524f859..b56b430ceefe 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 43fd5410ef8e..39280b59a456 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", diff --git a/src/Illuminate/Encryption/composer.json b/src/Illuminate/Encryption/composer.json index d5e54f85159f..c279db0aa233 100644 --- a/src/Illuminate/Encryption/composer.json +++ b/src/Illuminate/Encryption/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", diff --git a/src/Illuminate/Events/composer.json b/src/Illuminate/Events/composer.json index 0d021f39b060..ddff05d3039b 100755 --- a/src/Illuminate/Events/composer.json +++ b/src/Illuminate/Events/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/bus": "^9.0", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 7d10b4aeb439..a75c23daf287 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Hashing/composer.json b/src/Illuminate/Hashing/composer.json index ab2a11e403e8..f3fcc65e1a3c 100755 --- a/src/Illuminate/Hashing/composer.json +++ b/src/Illuminate/Hashing/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0" }, diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 24092e35692d..9aab579afa4f 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index 09f91ada54bc..8374723510f2 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0", "monolog/monolog": "^2.0" diff --git a/src/Illuminate/Macroable/composer.json b/src/Illuminate/Macroable/composer.json index f21750ccd7f4..43f1528be714 100644 --- a/src/Illuminate/Macroable/composer.json +++ b/src/Illuminate/Macroable/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0" + "php": "^7.4|^8.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 5f782e13dc5c..28882e965432 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index 863fbf667cb4..40af814f99e7 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/broadcasting": "^9.0", "illuminate/bus": "^9.0", "illuminate/collections": "^9.0", diff --git a/src/Illuminate/Pagination/composer.json b/src/Illuminate/Pagination/composer.json index 79c4e5971de3..d1f78330da93 100755 --- a/src/Illuminate/Pagination/composer.json +++ b/src/Illuminate/Pagination/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", diff --git a/src/Illuminate/Pipeline/composer.json b/src/Illuminate/Pipeline/composer.json index 76ac294856ce..38edca3ab3a9 100644 --- a/src/Illuminate/Pipeline/composer.json +++ b/src/Illuminate/Pipeline/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0" }, diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 0fee98723ecf..104fc02e24a0 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/console": "^9.0", diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index d6fb28cae3c5..d542af696cb1 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 178d3264b10e..30ffcd8ebcf1 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index e76ef3e68bd0..298a4caca293 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 5ae3cc5da694..32c19d9d966b 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "ext-mbstring": "*", "doctrine/inflector": "^2.0", diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index c7bd6b00304f..e38ab9755e69 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Translation/composer.json b/src/Illuminate/Translation/composer.json index 1f9bb438f5a5..0a58f23c47f3 100755 --- a/src/Illuminate/Translation/composer.json +++ b/src/Illuminate/Translation/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index dfb8c26a9f6e..54926da15ed7 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "egulias/email-validator": "^2.1.10", "illuminate/collections": "^9.0", diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index 8a6660e82ede..9c4c1c1acfda 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", From 9846e8847bdc850d3f9146fe8836086ecd2269a5 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 25 Jan 2021 16:45:40 +0000 Subject: [PATCH 095/194] Fixed bad merge --- .../DatabaseMySqlSchemaGrammarTest.php | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index a208aefde7d1..84a8090e1a29 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1227,48 +1227,6 @@ public function testGrammarsAreMacroable() $this->assertTrue($c); } - public function testCreateDatabase() - { - $connection = $this->getConnection(); - $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8mb4_foo'); - $connection->shouldReceive('getConfig')->once()->once()->with('collation')->andReturn('utf8mb4_unicode_ci_foo'); - - $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); - - $this->assertSame( - 'create database `my_database_a` default character set `utf8mb4_foo` default collate `utf8mb4_unicode_ci_foo`', - $statement - ); - - $connection = $this->getConnection(); - $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8mb4_bar'); - $connection->shouldReceive('getConfig')->once()->once()->with('collation')->andReturn('utf8mb4_unicode_ci_bar'); - - $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); - - $this->assertSame( - 'create database `my_database_b` default character set `utf8mb4_bar` default collate `utf8mb4_unicode_ci_bar`', - $statement - ); - } - - public function testDropDatabaseIfExists() - { - $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); - - $this->assertSame( - 'drop database if exists `my_database_a`', - $statement - ); - - $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); - - $this->assertSame( - 'drop database if exists `my_database_b`', - $statement - ); - } - protected function getConnection() { return m::mock(Connection::class); From c848d93c3158d5e642c2b1a60e267813de029f77 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 28 Jan 2021 14:13:31 +0100 Subject: [PATCH 096/194] Fix test --- tests/View/Blade/BladeComponentTagCompilerTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index a8190615d02d..6dc97bb4fcaa 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -93,6 +93,9 @@ public function testEscapedColonAttribute() $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => 1]) +getConstructor()): ?> +except(collect(\$constructor->getParameters())->map->getName()->all()); ?> + withAttributes([':title' => 'user.name']); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } From e095ac0e928b5620f33c9b60816fde5ece867d32 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 8 Feb 2021 15:52:47 +0100 Subject: [PATCH 097/194] [9.x] Accept attribute to touch (#36157) * wip * Update HasTimestamps.php --- .../Database/Eloquent/Concerns/HasTimestamps.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php index 13ebd31744cd..add911ae8619 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php @@ -16,10 +16,17 @@ trait HasTimestamps /** * Update the model's update timestamp. * + * @param string|null $attribute * @return bool */ - public function touch() + public function touch($attribute = null) { + if ($attribute) { + $this->$attribute = $this->freshTimestamp(); + + return $this->save(); + } + if (! $this->usesTimestamps()) { return false; } From 8a106ef039c01ac208639e395d74c0c5474bb75f Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 10 Feb 2021 16:27:00 -0500 Subject: [PATCH 098/194] [9.x] Pass collection instance into `tap` directly, not a clone (#36220) * Pass instance into `tap` directly * Use `tap` instead of `pipe` in test --- src/Illuminate/Collections/Traits/EnumeratesValues.php | 2 +- tests/Support/SupportCollectionTest.php | 5 ++++- tests/Support/SupportLazyCollectionTest.php | 4 +--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index aee05f114c0d..85720ebbedf7 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -764,7 +764,7 @@ public function reject($callback = true) */ public function tap(callable $callback) { - $callback(clone $this); + $callback($this); return $this; } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index c5584d5ebbc9..506b85df8981 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -4126,10 +4126,13 @@ public function testTap($collection) $data = new $collection([1, 2, 3]); $fromTap = []; - $data = $data->tap(function ($data) use (&$fromTap) { + $tappedInstance = null; + $data = $data->tap(function ($data) use (&$fromTap, &$tappedInstance) { $fromTap = $data->slice(0, 1)->toArray(); + $tappedInstance = $data; }); + $this->assertSame($data, $tappedInstance); $this->assertSame([1], $fromTap); $this->assertSame([1, 2, 3], $data->toArray()); } diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index c671830029e1..bb85818b7d8f 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -164,7 +164,7 @@ public function testTakeUntilTimeout() $results = $mock ->times(10) - ->pipe(function ($collection) use ($mock, $timeout) { + ->tap(function ($collection) use ($mock, $timeout) { tap($collection) ->mockery_init($mock->mockery_getContainer()) ->shouldAllowMockingProtectedMethods() @@ -175,8 +175,6 @@ public function testTakeUntilTimeout() (clone $timeout)->sub(1, 'minute')->getTimestamp(), $timeout->getTimestamp() ); - - return $collection; }) ->takeUntilTimeout($timeout) ->all(); From 347dc5bd5a3ca3c441bfb5496f27eef2164fdcb6 Mon Sep 17 00:00:00 2001 From: ARCANEDEV Date: Mon, 1 Mar 2021 19:55:39 +0000 Subject: [PATCH 099/194] [9.x] Fixing the Error : Class "League\Flysystem\Adapter\Local" not found (#36407) * [9.x] Fixing the Error : Class "League\Flysystem\Adapter\Local" not found This is related to the new Flysystem v2 (Check the PR #33612) * Update VendorPublishCommand.php --- src/Illuminate/Foundation/Console/VendorPublishCommand.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Console/VendorPublishCommand.php b/src/Illuminate/Foundation/Console/VendorPublishCommand.php index 842c3759da8a..45efdf65e611 100644 --- a/src/Illuminate/Foundation/Console/VendorPublishCommand.php +++ b/src/Illuminate/Foundation/Console/VendorPublishCommand.php @@ -6,8 +6,8 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Arr; use Illuminate\Support\ServiceProvider; -use League\Flysystem\Adapter\Local as LocalAdapter; use League\Flysystem\Filesystem as Flysystem; +use League\Flysystem\Local\LocalFilesystemAdapter as LocalAdapter; use League\Flysystem\MountManager; class VendorPublishCommand extends Command @@ -254,8 +254,8 @@ protected function publishDirectory($from, $to) protected function moveManagedFiles($manager) { foreach ($manager->listContents('from://', true) as $file) { - if ($file['type'] === 'file' && (! $manager->has('to://'.$file['path']) || $this->option('force'))) { - $manager->put('to://'.$file['path'], $manager->read('from://'.$file['path'])); + if ($file['type'] === 'file' && (! $manager->fileExists('to://'.$file['path']) || $this->option('force'))) { + $manager->write('to://'.$file['path'], $manager->read('from://'.$file['path'])); } } } From 7b5c5218125cc3d0c9fbf211029e9a2de02d061e Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 4 Mar 2021 14:09:40 +0100 Subject: [PATCH 100/194] Date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb052fd0a63c..f44399c5f5e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,6 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v9.0.0...9.x) -## [v9.0.0 (2020-??-??)](https://github.com/laravel/framework/compare/v8.22.0...v9.0.0) +## [v9.0.0 (2021-??-??)](https://github.com/laravel/framework/compare/v8.22.0...v9.0.0) Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/9.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/9.x/releases). From f6a42172c386e37e859c7093bfb1375815913e73 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 9 Mar 2021 15:50:09 +0100 Subject: [PATCH 101/194] [9.x] Update to EmailValidator v3 (#36525) * Update to EmailValidator v3 * Return null --- composer.json | 4 ++-- src/Illuminate/Mail/composer.json | 2 +- .../Validation/Concerns/FilterEmailValidation.php | 11 ++++++----- src/Illuminate/Validation/composer.json | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index a6bfc72af0ce..011f9c47d68f 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "ext-openssl": "*", "doctrine/inflector": "^2.0", "dragonmantank/cron-expression": "^3.1", - "egulias/email-validator": "^2.1.10", + "egulias/email-validator": "^3.1", "league/commonmark": "^1.3", "league/flysystem": "^2.0", "monolog/monolog": "^2.0", @@ -30,7 +30,7 @@ "psr/container": "^1.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", - "swiftmailer/swiftmailer": "^6.0", + "swiftmailer/swiftmailer": "^6.2.7", "symfony/console": "^5.2", "symfony/error-handler": "^5.2", "symfony/finder": "^5.2", diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 28882e965432..75cecef57ff4 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -23,7 +23,7 @@ "illuminate/support": "^9.0", "league/commonmark": "^1.3", "psr/log": "^1.0", - "swiftmailer/swiftmailer": "^6.0", + "swiftmailer/swiftmailer": "^6.2.7", "tijsverkoyen/css-to-inline-styles": "^2.2.2" }, "autoload": { diff --git a/src/Illuminate/Validation/Concerns/FilterEmailValidation.php b/src/Illuminate/Validation/Concerns/FilterEmailValidation.php index 2d21b6c5b27d..84ed212f2755 100644 --- a/src/Illuminate/Validation/Concerns/FilterEmailValidation.php +++ b/src/Illuminate/Validation/Concerns/FilterEmailValidation.php @@ -3,6 +3,7 @@ namespace Illuminate\Validation\Concerns; use Egulias\EmailValidator\EmailLexer; +use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Validation\EmailValidation; class FilterEmailValidation implements EmailValidation @@ -42,7 +43,7 @@ public static function unicode() * @param \Egulias\EmailValidator\EmailLexer $emailLexer * @return bool */ - public function isValid($email, EmailLexer $emailLexer) + public function isValid(string $email, EmailLexer $emailLexer): bool { return is_null($this->flags) ? filter_var($email, FILTER_VALIDATE_EMAIL) !== false @@ -52,11 +53,11 @@ public function isValid($email, EmailLexer $emailLexer) /** * Returns the validation error. * - * @return \Egulias\EmailValidator\Exception\InvalidEmail|null + * @return \Egulias\EmailValidator\Result\InvalidEmail|null */ - public function getError() + public function getError(): ?InvalidEmail { - // + return null; } /** @@ -64,7 +65,7 @@ public function getError() * * @return \Egulias\EmailValidator\Warning\Warning[] */ - public function getWarnings() + public function getWarnings(): array { return []; } diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 54926da15ed7..af707b3f0c28 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -16,7 +16,7 @@ "require": { "php": "^7.4|^8.0", "ext-json": "*", - "egulias/email-validator": "^2.1.10", + "egulias/email-validator": "^3.1", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", "illuminate/contracts": "^9.0", From ac0e13306739edf162bef5b36f65e6b6d45e9012 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 9 Mar 2021 17:44:22 +0000 Subject: [PATCH 102/194] Delete CHANGELOG-6.x.md --- CHANGELOG-6.x.md | 1061 ---------------------------------------------- 1 file changed, 1061 deletions(-) delete mode 100644 CHANGELOG-6.x.md diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md deleted file mode 100644 index 860012f0bd0a..000000000000 --- a/CHANGELOG-6.x.md +++ /dev/null @@ -1,1061 +0,0 @@ -# Release Notes for 6.x - -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.17...6.x) - - -## [v6.20.17 (2021-03-02)](https://github.com/laravel/framework/compare/v6.20.16...v6.20.17) - -### Added -- Added new line to `DetectsLostConnections` ([#36373](https://github.com/laravel/framework/pull/36373)) - - -## [v6.20.16 (2021-02-02)](https://github.com/laravel/framework/compare/v6.20.15...v6.20.16) - -### Fixed -- Fixed `Illuminate\View\ViewException::report()` ([#36110](https://github.com/laravel/framework/pull/36110)) -- Fixed `Illuminate\Redis\Connections\PhpRedisConnection::spop()` ([#36106](https://github.com/laravel/framework/pull/36106)) - -### Changed -- Typecast page number as integer in `Illuminate\Pagination\AbstractPaginator::resolveCurrentPage()` ([#36055](https://github.com/laravel/framework/pull/36055)) - - -## [v6.20.15 (2021-01-26)](https://github.com/laravel/framework/compare/v6.20.14...v6.20.15) - -### Changed -- Pipe new through render and report exception methods ([#36037](https://github.com/laravel/framework/pull/36037)) - - -## [v6.20.14 (2021-01-21)](https://github.com/laravel/framework/compare/v6.20.13...v6.20.14) - -### Fixed -- Fixed type error in `Illuminate\Http\Concerns\InteractsWithContentTypes::isJson()` ([#35956](https://github.com/laravel/framework/pull/35956)) -- Limit expected bindings ([#35972](https://github.com/laravel/framework/pull/35972), [006873d](https://github.com/laravel/framework/commit/006873df411d28bfd03fea5e7f91a2afe3918498)) - - -## [v6.20.13 (2021-01-19)](https://github.com/laravel/framework/compare/v6.20.12...v6.20.13) - -### Fixed -- Fixed empty html mail ([#35941](https://github.com/laravel/framework/pull/35941)) - - -## [v6.20.12 (2021-01-13)](https://github.com/laravel/framework/compare/v6.20.11...v6.20.12) - - -## [v6.20.11 (2021-01-13)](https://github.com/laravel/framework/compare/v6.20.10...v6.20.11) - -### Fixed -- Limit expected bindings ([#35865](https://github.com/laravel/framework/pull/35865)) - - -## [v6.20.10 (2021-01-12)](https://github.com/laravel/framework/compare/v6.20.9...v6.20.10) - -### Added -- Added new line to `DetectsLostConnections` ([#35790](https://github.com/laravel/framework/pull/35790)) - -### Fixed -- Fixed error from missing null check on PHP 8 in `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` ([#35797](https://github.com/laravel/framework/pull/35797)) - - -## [v6.20.9 (2021-01-05)](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) - -### Added -- [Updated Illuminate\Database\DetectsLostConnections with new strings](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) - - -## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) - -### Fixed -- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) -- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) - - -## [v6.20.7 (2020-12-08)](https://github.com/laravel/framework/compare/v6.20.6...v6.20.7) - -### Fixed -- Backport for fix issue with polymorphic morphMaps with literal 0 ([#35487](https://github.com/laravel/framework/pull/35487)) -- Fixed mime validation for jpeg files ([#35518](https://github.com/laravel/framework/pull/35518)) - - -## [v6.20.6 (2020-12-01)](https://github.com/laravel/framework/compare/v6.20.5...v6.20.6) - -### Fixed -- Backport Redis context option ([#35370](https://github.com/laravel/framework/pull/35370)) -- Fixed validating image/jpeg images after Symfony/Mime update ([#35419](https://github.com/laravel/framework/pull/35419)) - - -## [v6.20.5 (2020-11-24)](https://github.com/laravel/framework/compare/v6.20.4...v6.20.5) - -### Fixed -- Fixing BroadcastException message in PusherBroadcaster@broadcast ([#35290](https://github.com/laravel/framework/pull/35290)) -- Fixed generic DetectsLostConnection string ([#35323](https://github.com/laravel/framework/pull/35323)) - -### Changed -- Updated `aws/aws-sdk-php` suggest to `^3.155` ([#35267](https://github.com/laravel/framework/pull/35267)) - - -## [v6.20.4 (2020-11-17)](https://github.com/laravel/framework/compare/v6.20.3...v6.20.4) - -### Fixed -- Fixed pivot restoration ([#35218](https://github.com/laravel/framework/pull/35218)) - - -## [v6.20.3 (2020-11-10)](https://github.com/laravel/framework/compare/v6.20.2...v6.20.3) - -### Fixed -- Turn the eloquent collection into a base collection if mapWithKeys loses models ([#35129](https://github.com/laravel/framework/pull/35129)) - - -## [v6.20.2 (2020-10-29)](https://github.com/laravel/framework/compare/v6.20.1...v6.20.2) - -### Fixed -- [Add some fixes](https://github.com/laravel/framework/compare/v6.20.1...v6.20.2) - - -## [v6.20.1 (2020-10-29)](https://github.com/laravel/framework/compare/v6.20.0...v6.20.1) - -### Fixed -- Fixed alias usage in `Eloquent` ([6091048](https://github.com/laravel/framework/commit/609104806b8b639710268c75c22f43034c2b72db)) -- Fixed `Illuminate\Support\Reflector::isCallable()` ([a90f344](https://github.com/laravel/framework/commit/a90f344c66f0a5bb1d718f8bbd20c257d4de9e02)) - - -## [v6.20.0 (2020-10-28)](https://github.com/laravel/framework/compare/v6.19.1...v6.20.0) - -### Added -- Full PHP 8.0 Support ([#33388](https://github.com/laravel/framework/pull/33388)) -- Added `Illuminate\Support\Reflector::isCallable()` ([#34994](https://github.com/laravel/framework/pull/34994), [8c16891](https://github.com/laravel/framework/commit/8c16891c6e7a4738d63788f4447614056ab5136e), [31917ab](https://github.com/laravel/framework/commit/31917abcfa0db6ec6221bb07fc91b6e768ff5ec8), [11cfa4d](https://github.com/laravel/framework/commit/11cfa4d4c92bf2f023544d58d51b35c5d31dece0), [#34999](https://github.com/laravel/framework/pull/34999)) - -### Changed -- Bump minimum PHP version to v7.2.5 ([#34928](https://github.com/laravel/framework/pull/34928)) - -### Fixed -- Fixed ambigious column on many to many with select load ([5007986](https://github.com/laravel/framework/commit/500798623d100a9746b2931ae6191cb756521f05)) - - -## [v6.19.1 (2020-10-20)](https://github.com/laravel/framework/compare/v6.19.0...v6.19.1) - -### Fixed -- Fixed `bound()` method ([a7759d7](https://github.com/laravel/framework/commit/a7759d70e15b0be946569b8299ac694c08a35d7e)) - - -## [v6.19.0 (2020-10-20)](https://github.com/laravel/framework/compare/v6.18.43...v6.19.0) - -### Added -- Provisional support for PHP 8.0 ([#34884](https://github.com/laravel/framework/pull/34884), [28bb76e](https://github.com/laravel/framework/commit/28bb76efbcfc5fee57307ffa062b67ff709240dc)) - - -## [v6.18.43 (2020-10-13)](https://github.com/laravel/framework/compare/v6.18.42...v6.18.43) - -### Fixed -- Matched `symfony/debug` version with other symfony reqs ([6ce02a2](https://github.com/laravel/framework/commit/6ce02a21cf736f28beda2529d1e28849e86b0944)) - - -## [v6.18.42 (2020-10-06)](https://github.com/laravel/framework/compare/v6.18.41...v6.18.42) - -### Fixed -- Added missed RESET_THROTTLED constant to Password Facade ([#34641](https://github.com/laravel/framework/pull/34641)) - - -## [v6.18.41 (2020-09-29)](https://github.com/laravel/framework/compare/v6.18.40...v6.18.41) - -### Fixed -- Added support for stream reads in FileManager for S3 driver ([#34480](https://github.com/laravel/framework/pull/34480)) - - -## [v6.18.40 (2020-09-09)](https://github.com/laravel/framework/compare/v6.18.39...v6.18.40) - -### Revert -- Revert of ["Fixed for empty fallback_locale in `Illuminate\Translation\Translator`"](https://github.com/laravel/framework/pull/34136) ([7c54eb6](https://github.com/laravel/framework/commit/7c54eb678d58fb9ee7f532a5a5842e6f0e1fe4c9)) - - -## [v6.18.39 (2020-09-08)](https://github.com/laravel/framework/compare/v6.18.38...v6.18.39) - -### Fixed -- Fixed for empty fallback_locale in `Illuminate\Translation\Translator` ([#34136](https://github.com/laravel/framework/pull/34136)) - - -## [v6.18.38 (2020-09-01)](https://github.com/laravel/framework/compare/v6.18.37...v6.18.38) - -### Changed -- Changed postgres processor ([#34055](https://github.com/laravel/framework/pull/34055)) - - -## [v6.18.37 (2020-08-27)](https://github.com/laravel/framework/compare/v6.18.36...v6.18.37) - -### Fixed -- Fixed offset error on invalid remember token ([#34020](https://github.com/laravel/framework/pull/34020)) -- Only prepend scheme to PhpRedis host when necessary ([#34017](https://github.com/laravel/framework/pull/34017)) -- Fixed `whereKey` and `whereKeyNot` in `Illuminate\Database\Eloquent\Builder` ([#34031](https://github.com/laravel/framework/pull/34031)) - - -## [v6.18.36 (2020-08-25)](https://github.com/laravel/framework/compare/v6.18.35...v6.18.36) - -### Fixed -- Fix dimension ratio calculation in `Illuminate\Validation\Concerns\ValidatesAttributes::failsRatioCheck()` ([#34003](https://github.com/laravel/framework/pull/34003)) - -### Changed -- Normalize scheme in Redis connections ([#33892](https://github.com/laravel/framework/pull/33892)) -- Check no-interaction flag exists and is true for Artisan commands ([#33950](https://github.com/laravel/framework/pull/33950)) - - -## [v6.18.35 (2020-08-07)](https://github.com/laravel/framework/compare/v6.18.34...v6.18.35) - -### Changed -- Verify column names are actual columns when using guarded ([#33777](https://github.com/laravel/framework/pull/33777)) - - -## [v6.18.34 (2020-08-06)](https://github.com/laravel/framework/compare/v6.18.33...v6.18.34) - -### Fixed -- Fixed `Illuminate\Support\Arr::query()` ([c6f9ae2](https://github.com/laravel/framework/commit/c6f9ae2b6fdc3c1716938223de731b97f6a5a255)) -- Don't allow mass filling with table names ([9240404](https://github.com/laravel/framework/commit/9240404b22ef6f9e827577b3753e4713ddce7471), [f5fa6e3](https://github.com/laravel/framework/commit/f5fa6e3a0fbf9a93eab45b9ae73265b4dbfc3ad7)) - - -## [v6.18.33 (2020-08-06)](https://github.com/laravel/framework/compare/v6.18.32...v6.18.33) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Concerns\GuardsAttributes::isGuarded()` ([1b70bef](https://github.com/laravel/framework/commit/1b70bef5fd7cc5da74abcdf79e283f830fa3b0a4), [624d873](https://github.com/laravel/framework/commit/624d873733388aa2246553a3b465e38554953180), [b70876a](https://github.com/laravel/framework/commit/b70876ac80759fbf168c91cdffd7a2b2305e27cb)) -- Fixed escaping quotes ([687df01](https://github.com/laravel/framework/commit/687df01fa19c99546c1ae1dd53c2a465459b50dc)) - - -## [v6.18.32 (2020-08-04)](https://github.com/laravel/framework/compare/v6.18.31...v6.18.32) - -### Changed -- Ignore numeric field names in validators ([#33712](https://github.com/laravel/framework/pull/33712)) -- Fixed validation rule 'required_unless' when other field value is boolean. ([#33715](https://github.com/laravel/framework/pull/33715)) - - -## [v6.18.31 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.30...v6.18.31) - -### Update -- Update cookies encryption ([release](https://github.com/laravel/framework/compare/v6.18.30...v6.18.31)) - - -## [v6.18.30 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.29...v6.18.30) - -### Update -- Update cookies encryption ([release](https://github.com/laravel/framework/compare/v6.18.29...v6.18.30)) - - -## [v6.18.29 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.28...v6.18.29) - -### Fixed -- Fixed cookie issues encryption ([c9ce261](https://github.com/laravel/framework/commit/c9ce261a9f7b8e07c9ebc8a7d45651ee1cf86215), [5786aa4](https://github.com/laravel/framework/commit/5786aa4a388adfcc62862573275bd37d49aa07d7)) - - -## [v6.18.28 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.27...v6.18.28) - -### Fixed -- Fixed cookie issues ([bb9db21](https://github.com/laravel/framework/commit/bb9db21af137344feffa192fcabe4e439c8b0f60)) - - -## [v6.18.27 (2020-07-27)](https://github.com/laravel/framework/compare/v6.18.26...v6.18.27) - -### Fixed -- Don't decrement transaction below 0 in `Illuminate\Database\Concerns\ManagesTransactions::handleCommitTransactionException()` ([7681795](https://github.com/laravel/framework/commit/768179578e5492b5f80c391bd43b233938e16e27)) -- Fixed transaction problems on closure transaction ([c4cdfc7](https://github.com/laravel/framework/commit/c4cdfc7c54127b772ef10f37cfc9ef8e9d6b3227)) -- Prevent to serialize uninitialized properties ([#33644](https://github.com/laravel/framework/pull/33644)) -- Fixed missing statement preventing deletion in `Illuminate\Database\Eloquent\Relations\MorphPivot::delete()` ([#33648](https://github.com/laravel/framework/pull/33648)) - -### Changed -- Improve cookie encryption ([#33662](https://github.com/laravel/framework/pull/33662)) - -This change will invalidate all existing cookies. Please see [this security bulletin](https://blog.laravel.com/laravel-cookie-security-releases) for more information. - - -## [v6.18.26 (2020-07-21)](https://github.com/laravel/framework/compare/v6.18.25...v6.18.26) - -### Fixed -- Align (fix) nested arrays support for `assertViewHas` & `assertViewMissing` in `Illuminate\Testing\TestResponse` ([#33566](https://github.com/laravel/framework/pull/33566)) - - -## [v6.18.25 (2020-07-10)](https://github.com/laravel/framework/compare/v6.18.24...v6.18.25) - -### Fixed -- Fixed `Illuminate\Cache\FileStore::flush()` ([#33458](https://github.com/laravel/framework/pull/33458)) -- Fixed auto creating model by class name ([#33481](https://github.com/laravel/framework/pull/33481)) -- Don't return nested data from validator when failing an exclude rule ([#33435](https://github.com/laravel/framework/pull/33435)) -- Fixed validation nested error messages ([6615371](https://github.com/laravel/framework/commit/6615371d7c0a7431372244d21eae54696b3c19f2)) -- Fixed `Illuminate\Support\Reflector` to handle parent ([#33502](https://github.com/laravel/framework/pull/33502)) - -### Revert -- Revert [Improve SQL Server last insert id retrieval](https://github.com/laravel/framework/pull/33453) ([#33496](https://github.com/laravel/framework/pull/33496)) - - -## [v6.18.24 (2020-07-07)](https://github.com/laravel/framework/compare/v6.18.23...v6.18.24) - -### Fixed -- Fixed notifications database channel for anonymous notifiables ([#33409](https://github.com/laravel/framework/pull/33409)) -- Added float comparison null checks ([#33421](https://github.com/laravel/framework/pull/33421)) -- Improve SQL Server last insert id retrieval ([#33453](https://github.com/laravel/framework/pull/33453)) - - -## [v6.18.23 (2020-06-30)](https://github.com/laravel/framework/compare/v6.18.22...v6.18.23) - -### Fixed -- Fixed `ConfigurationUrlParser` query decoding ([#33340](https://github.com/laravel/framework/pull/33340)) -- Correct implementation of float casting comparison ([#33322](https://github.com/laravel/framework/pull/33322)) - - -## [v6.18.22 (2020-06-24)](https://github.com/laravel/framework/compare/v6.18.21...v6.18.22) - -### Revert -- Revert "Fixed `Model::originalIsEquivalent()` with floats ([#33259](https://github.com/laravel/framework/pull/33259), [d68d915](https://github.com/laravel/framework/commit/d68d91516db6d1b9cba8a72f99b2c7e8223e988f))" [bf3cb6f](https://github.com/laravel/framework/commit/bf3cb6f6979df2d6965d2e0aa731724d0e2b15e5) - - -## [v6.18.21 (2020-06-23)](https://github.com/laravel/framework/compare/v6.18.20...v6.18.21) - -### Fixed -- Fixed `Model::originalIsEquivalent()` with floats ([#33259](https://github.com/laravel/framework/pull/33259), [d68d915](https://github.com/laravel/framework/commit/d68d91516db6d1b9cba8a72f99b2c7e8223e988f)) - - -## [v6.18.20 (2020-06-16)](https://github.com/laravel/framework/compare/v6.18.19...v6.18.20) - -### Changed -- Improved the reflector ([#33184](https://github.com/laravel/framework/pull/33184)) - - -## [v6.18.19 (2020-06-09)](https://github.com/laravel/framework/compare/v6.18.18...v6.18.19) - -### Fixed -- Fixed `Model::withoutEvents()` not registering listeners inside boot() ([#33149](https://github.com/laravel/framework/pull/33149), [4bb32ae](https://github.com/laravel/framework/commit/4bb32aea50eec4c3cc8b77f463e4a96213a0af09)) - - -## [v6.18.18 (2020-06-03)](https://github.com/laravel/framework/compare/v6.18.17...v6.18.18) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Relations\MorphToMany::getCurrentlyAttachedPivots()` ([110b129](https://github.com/laravel/framework/commit/110b129531df172f03bf163f561c71123fac6296)) - - -## [v6.18.17 (2020-06-02)](https://github.com/laravel/framework/compare/v6.18.16...v6.18.17) - -### Added -- Support PHP 8's reflection API ([#33039](https://github.com/laravel/framework/pull/33039)) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Collection::getQueueableRelations()` ([00e9ed7](https://github.com/laravel/framework/commit/00e9ed76483ea6ad1264676e7b1095b23e16a433)) -- Fixed bug with update existing pivot and polymorphic many to many ([684208b](https://github.com/laravel/framework/commit/684208b10460b49fa34354cc42f33b9b7135814f)) - - -## [v6.18.15 (2020-05-19)](https://github.com/laravel/framework/compare/v6.18.14...v6.18.15) - -### Added -- Added `Illuminate\Http\Middleware\TrustHosts` ([9229264](https://github.com/laravel/framework/commit/92292649621f2aadc84ab94376244650a9f55696)) - -### Fixed -- Revert of ["Remove `strval` from `Illuminate/Validation/ValidationRuleParser::explodeWildcardRules()`"](https://github.com/laravel/framework/commit/1c76a6f3a80fa8f756740566dffd9fa1be65c123) ([52940cf](https://github.com/laravel/framework/commit/52940cf3275cfebd47ec008fd8ae5bc6d6a42dfd)) -- Fixed Queued Mail MessageSent Listener With Attachments ([#32795](https://github.com/laravel/framework/pull/32795)) -- Added error clearing before sending in `Illuminate\Mail\Mailer::sendSwiftMessage()` ([#32799](https://github.com/laravel/framework/pull/32799)) -- Avoid foundation function call in the auth component ([#32805](https://github.com/laravel/framework/pull/32805)) - -### Changed -- Added explicit `symfony/polyfill-php73` dependency ([5796b1e](https://github.com/laravel/framework/commit/5796b1e43dfe14914050a7e5dd24ddf803ec99b8)) -- Set `Cache\FileStore` file permissions only once ([#32845](https://github.com/laravel/framework/pull/32845), [11c533b](https://github.com/laravel/framework/commit/11c533b9aa062f4cba1dd0fe3673bf33d275480f)) - - -## [v6.18.14 (2020-05-12)](https://github.com/laravel/framework/compare/v6.18.13...v6.18.14) - -### Added -- Added SSL SYSCALL EOF as a lost connection message ([#32697](https://github.com/laravel/framework/pull/32697)) - -### Fixed -- Fixed `FakerGenerator` Unique caching issue ([#32703](https://github.com/laravel/framework/pull/32703)) -- Added boolean to types that don't need character options ([#32716](https://github.com/laravel/framework/pull/32716)) -- Fixed `Illuminate\Foundation\Testing\PendingCommand` that do not resolve 'OutputStyle::class' from the container ([#32687](https://github.com/laravel/framework/pull/32687)) -- Clear resolved event facade on `Illuminate\Foundation\Testing\Concerns\MocksApplicationServices::withoutEvents()` ([d1e7f85](https://github.com/laravel/framework/commit/d1e7f85dfd79abbe4f5e01818f620f6ecc67de4d)) -- Fixed deprecated "Doctrine/Common/Inflector/Inflector" class ([#32734](https://github.com/laravel/framework/pull/32734)) - -### Changed -- Remove the undocumented dot keys support in validators ([#32764](https://github.com/laravel/framework/pull/32764)) -- Remove `strval` from `Illuminate/Validation/ValidationRuleParser::explodeWildcardRules()` [1c76a6f](https://github.com/laravel/framework/commit/1c76a6f3a80fa8f756740566dffd9fa1be65c123) - - -## [v6.18.13 (2020-05-05)](https://github.com/laravel/framework/compare/v6.18.12...v6.18.13) - -### Fixed -- Fixed `Illuminate\Database\Eloquent\Collection::getQueueableRelations()` ([7b32460](https://github.com/laravel/framework/commit/7b32469420258e9e52b24b2ffa7f491e79a3a870)) - - -## [v6.18.12 (2020-05-05)](https://github.com/laravel/framework/compare/v6.18.11...v6.18.12) - -### Added -- Add pdo try again as lost connection message ([#32605](https://github.com/laravel/framework/pull/32605)) - -### Fixed -- Fixed `Illuminate\Foundation\Testing\TestResponse::assertSessionHasInput()` ([f0639fd](https://github.com/laravel/framework/commit/f0639fda45fc2874986fe409d944dde21d42c6f3)) -- Set relation connection on eager loaded MorphTo ([#32602](https://github.com/laravel/framework/pull/32602)) -- Fixed `Illuminate\Database\Schema\Grammars\SqlServerGrammar::compileDropDefaultConstraint()` was ignoring Table prefixes ([#32606](https://github.com/laravel/framework/pull/32606)) -- Filtering null's in `hasMorph()` ([#32614](https://github.com/laravel/framework/pull/32614)) -- Fixed `Illuminate\Console\Scheduling\Schedule::compileParameters()` ([cfc3ac9](https://github.com/laravel/framework/commit/cfc3ac9c8b0a593d264ae722ab90601fa4882d0e), [36e215d](https://github.com/laravel/framework/commit/36e215dd39cd757a8ffc6b17794de60476b2289d)) -- Fixed bug with model name in `Illuminate\Database\Eloquent\RelationNotFoundException::make()` ([f72a166](https://github.com/laravel/framework/commit/f72a1662ab64cc543c532941b1ab1279001af8e9)) -- Fixed `Illuminate\Foundation\Testing\TestResponse::assertJsonCount()` not accepting falsey keys ([#32655](https://github.com/laravel/framework/pull/32655)) - -### Changed -- Changed `Illuminate/Database/Eloquent/Relations/Concerns/AsPivot::fromRawAttributes()` ([6c502c1](https://github.com/laravel/framework/commit/6c502c1135082e8b25f2720931b19d36eeec8f41)) -- Restore оnly common relations ([#32613](https://github.com/laravel/framework/pull/32613), [d82f78b](https://github.com/laravel/framework/commit/d82f78b13631c4a04b9595099da0022ca3d8b94e), [48e4d60](https://github.com/laravel/framework/commit/48e4d602d4f8fe9304e8998c5893206f67504dbf)) -- Use single space if plain email is empty in `Illuminate\Mail\Mailer::addContent()` ([0557622](https://github.com/laravel/framework/commit/055762286132d545cbc064dce645562c0d51532f)) -- Remove wasted file read when loading package manifest in `Illuminate\Foundation\PackageManifest::getManifest()` ([#32646](https://github.com/laravel/framework/pull/32646)) -- Cache `FakerGenerator` instances ([#32585](https://github.com/laravel/framework/pull/32585)) -- Do not change `character` and `collation` for some columns on change ([fccdf7c](https://github.com/laravel/framework/commit/fccdf7c42d5ceb50985b3e8243d7ba650de996d6)) - - -## [v6.18.11 (2020-04-28)](https://github.com/laravel/framework/compare/v6.18.10...v6.18.11) - -### Fixed -- Auth with each master on flushdb ([d0afa58](https://github.com/laravel/framework/commit/d0afa5846ca1d85ca07cdb580d3b9e9768ebdf41)) -- Clear resolved facades earlier ([f2ea1a2](https://github.com/laravel/framework/commit/f2ea1a23fdac94d3f0818e7ff514fbaed3f45643)) -- Register opis key so it is not tied to a deferred service provider ([a4574ea](https://github.com/laravel/framework/commit/a4574ea973bab9bd6a2ba34d36dfb8f9b55d5a4a)) -- Pass status code to schedule finish ([b815dc6](https://github.com/laravel/framework/commit/b815dc6c1b1c595f3241c493255f0fbfd67a6131)) -- Fix firstWhere behavior for relations ([#32525](https://github.com/laravel/framework/pull/32525)) -- Fixed boolean value in `Illuminate\Foundation\Testing\TestResponse::assertSessionHasErrors()` ([#32555](https://github.com/laravel/framework/pull/32555)) - - -## [v6.18.10 (2020-04-21)](https://github.com/laravel/framework/compare/v6.18.9...v6.18.10) - -### Fixed -- Check if object ([1b0bdb4](https://github.com/laravel/framework/commit/1b0bdb43062a2792befe6fd754140124a8e4dc35)) - - -## [v6.18.9 (2020-04-21)](https://github.com/laravel/framework/compare/v6.18.8...v6.18.9) - -### Fixed -- Fix `refresh()` to support `AsPivot` trait ([#32420](https://github.com/laravel/framework/pull/32420)) -- Fix orderBy with callable ([#32471](https://github.com/laravel/framework/pull/32471)) - - -## [v6.18.8 (2020-04-15)](https://github.com/laravel/framework/compare/v6.18.7...v6.18.8) - -### Fixed -- Removed dots ([e78d24f](https://github.com/laravel/framework/commit/e78d24f31b84cd81c30b5d8837731d77ec089761)) -- Duplicated mailable in-memory data attachments with different names ([#32392](https://github.com/laravel/framework/pull/32392)) -- Fix a regression caused by #32315 ([#32388](https://github.com/laravel/framework/pull/32388)) -- Duplicated mailable storage attachments with different names ([#32394](https://github.com/laravel/framework/pull/32394)) - - -## [v6.18.7 (2020-04-14)](https://github.com/laravel/framework/compare/v6.18.6...v6.18.7) - -### Fixed -- Call setlocale ([1c6a504](https://github.com/laravel/framework/commit/1c6a50424c5558782a55769a226ab834484282e1)) -- Use a map to prevent unnecessary array access ([#32296](https://github.com/laravel/framework/pull/32296)) -- Prevent timestamp update when pivot is not dirty ([#32311](https://github.com/laravel/framework/pull/32311)) -- Add support for the new composer installed.json format ([#32310](https://github.com/laravel/framework/pull/32310)) -- ValidatesAttributes::validateUrl use Symfony/Validator 5.0.7 regex ([#32315](https://github.com/laravel/framework/pull/32315)) -- Fix *scan methods for phpredis ([#32336](https://github.com/laravel/framework/pull/32336)) -- Use the router for absolute urls ([#32345](https://github.com/laravel/framework/pull/32345)) - - -## [v6.18.6 (2020-04-08)](https://github.com/laravel/framework/compare/v6.18.5...v6.18.6) - -### Security -- Prevent insecure characters in locale ([c248521](https://github.com/laravel/framework/commit/c248521f502c74c6cea7b0d221639d4aa752d5db)) - - -## [v6.18.5 (2020-04-07)](https://github.com/laravel/framework/compare/v6.18.4...v6.18.5) - -### Fixed -- Revert "Fix setting mail header" ([#32278](https://github.com/laravel/framework/pull/32278)) - - -## [v6.18.4 (2020-04-07)](https://github.com/laravel/framework/compare/v6.18.3...v6.18.4) - -### Fixed -- Added missing return in the sendNow pending mail fake ([#32095](https://github.com/laravel/framework/pull/32095)) -- Prevent long URLs from breaking email layouts ([#32189](https://github.com/laravel/framework/pull/32189)) -- Fix setting mail header ([#32272](https://github.com/laravel/framework/pull/32272)) - - -## [v6.18.3 (2020-03-24)](https://github.com/laravel/framework/compare/v6.18.2...v6.18.3) - -### Fixed -- Corrected suggested dependencies ([#32072](https://github.com/laravel/framework/pull/32072), [c01a70e](https://github.com/laravel/framework/commit/c01a70e33198e81d06d4b581e36e25a80acf8a68)) -- Avoid deadlock in test when sharing process group ([#32067](https://github.com/laravel/framework/pull/32067)) - - -## [v6.18.2 (2020-03-17)](https://github.com/laravel/framework/compare/v6.18.1...v6.18.2) - -### Fixed -- Fixed scheduler dependency assumptions ([#31894](https://github.com/laravel/framework/pull/31894)) -- Corrected suggested dependencies ([bb0ec42](https://github.com/laravel/framework/commit/bb0ec42b5a55b3ebf3a5a35cc6df01eec290dfa9)) -- Unset `pivotParent` on `Pivot::unsetRelations()` ([#31956](https://github.com/laravel/framework/pull/31956)) -- Fixed `cookie` helper signature , matching match `CookieFactory` ([#31974](https://github.com/laravel/framework/pull/31974)) - - -## [v6.18.1 (2020-03-10)](https://github.com/laravel/framework/compare/v6.18.0...v6.18.1) - -### Fixed -- Fixed array lock release behavior ([#31795](https://github.com/laravel/framework/pull/31795)) -- Fixed model restoring right after being soft deleting ([#31719](https://github.com/laravel/framework/pull/31719)) -- Fixed phpredis "zadd" and "exists" on cluster ([#31838](https://github.com/laravel/framework/pull/31838)) -- Fixed "srid" mysql schema ([#31852](https://github.com/laravel/framework/pull/31852)) -- Fixed Microsoft ODBC lost connection handling ([#31879](https://github.com/laravel/framework/pull/31879)) - - -## [v6.18.0 (2020-03-03)](https://github.com/laravel/framework/compare/v6.17.1...v6.18.0) - -### Added -- Added `Arr::hasAny()` method ([#31636](https://github.com/laravel/framework/pull/31636)) - -### Fixed -- Use correct locale when resolving Faker from the container ([#31615](https://github.com/laravel/framework/pull/31615)) -- Fixed loading deferred providers for binding interfaces and implementations ([#31629](https://github.com/laravel/framework/pull/31629), [1764ff7](https://github.com/laravel/framework/commit/1764ff762966083a12dd2c9b522cec5f1bbda967)) - -### Changed -- Make `newPivotQuery()` method public ([#31677](https://github.com/laravel/framework/pull/31677)) -- Allowed easier customization of the queued mailable job ([#31684](https://github.com/laravel/framework/pull/31684)) -- Expose Notification Id within Message Data in `Illuminate\Notifications\Channels\MailChannel` ([#31632](https://github.com/laravel/framework/pull/31632)) - - -## [v6.17.1 (2020-02-26)](https://github.com/laravel/framework/compare/v6.17.0...v6.17.1) - -### Changed -- Don`t do chmod in File cache in case if permission not set ([#31593](https://github.com/laravel/framework/pull/31593)) - - -## [v6.17.0 (2020-02-25)](https://github.com/laravel/framework/compare/v6.16.0...v6.17.0) - -### Added -- Allowed private-encrypted pusher channels ([#31559](https://github.com/laravel/framework/pull/31559), [ceabaef](https://github.com/laravel/framework/commit/ceabaef88741c0c6a891166cf14eb967fdf4e8ee), [8215e0d](https://github.com/laravel/framework/commit/8215e0dc66bf71a7ff4e9bf260380cf4a26f28a6)) -- Added file `permission` config option for the File cache store ([#31579](https://github.com/laravel/framework/pull/31579)) -- Added `Connection refused` and `running with the --read-only option so it cannot execute this statement` to `DetectsLostConnections` ([#31539](https://github.com/laravel/framework/pull/31539)) - -### Reverted -- Reverted ["Fixed memory usage on downloading large files"](https://github.com/laravel/framework/pull/31163) ([#31587](https://github.com/laravel/framework/pull/31587)) - -### Fixed -- Fixed issue `Content Type not specified` ([#31533](https://github.com/laravel/framework/pull/31533)) - -### Changed -- Allowed `cache` helper to have an optional `expiration` parameter ([#31554](https://github.com/laravel/framework/pull/31554)) -- Allowed passing of strings to `TestResponse::dumpSession()` method ([#31583](https://github.com/laravel/framework/pull/31583)) -- Consider mailto: and tel: links in the subcopy actionUrl label in emails ([#31523](https://github.com/laravel/framework/pull/31523), [641a7cd](https://github.com/laravel/framework/commit/641a7cda8280ecd3035616d4ce6434434b116624)) -- Exclude mariaDB from database queue support for new SKIP LOCKED ([fff96e7](https://github.com/laravel/framework/commit/fff96e7df7de470e162a6b7f6dd528e6fe17aadc)) - - -## [v6.16.0 (2020-02-18)](https://github.com/laravel/framework/compare/v6.15.1...v6.16.0) - -### Added -- Added Guzzle 7 support ([#31484](https://github.com/laravel/framework/pull/31484)) -- Added `Illuminate\Database\Query\Builder::groupByRaw()` ([#31498](https://github.com/laravel/framework/pull/31498)) -- Added SQLite JSON update support with json_patch ([#31492](https://github.com/laravel/framework/pull/31492)) - -### Fixed -- Fixed `appendRow` on console table ([#31469](https://github.com/laravel/framework/pull/31469)) -- Fixed password check in `EloquentUserProvider::retrieveByCredentials()` ([4436662](https://github.com/laravel/framework/commit/4436662a1ee19fc5e9eb76a0651d0de1aedb3ee2)) - -### Revert -- Revert table feature in the console output ([4094d78](https://github.com/laravel/framework/commit/4094d785269ce7849557b792f650fb278d48978e)) - -### Changed -- Change MySql nullable modifier to allow generated columns to be not null ([#31452](https://github.com/laravel/framework/pull/31452)) -- Throw exception on empty collection in `assertSentTo()` \ `assertNotSentTo()` methods in `NotificationFake` class ([#31471](https://github.com/laravel/framework/pull/31471)) - - -## [v6.15.1 (2020-02-12)](https://github.com/laravel/framework/compare/v6.15.0...v6.15.1) - -### Added -- Added `whereNull` and `whereNotNull` to `Collection` ([#31425](https://github.com/laravel/framework/pull/31425)) -- Added `Illuminate\Foundation\Testing\MockStream` class ([#31447](https://github.com/laravel/framework/pull/31447)) - -### Fixed -- Fixed `event:list` command for shows non-registered events ([#31444](https://github.com/laravel/framework/pull/31444)) -- Fixed postgres grammar for nested json arrays with ([#31448](https://github.com/laravel/framework/pull/31448), [b3d0da1](https://github.com/laravel/framework/commit/b3d0da164bdf3d5d829384025476ca1b2065c97e)) - - -## [v6.15.0 (2020-02-11)](https://github.com/laravel/framework/compare/v6.14.0...v6.15.0) - -### Added -- Added `Illuminate\Auth\Events\Validated` event ([#31357](https://github.com/laravel/framework/pull/31357), [7ddac28](https://github.com/laravel/framework/commit/7ddac28bc08b99ee248b1e4aa559efc3a8bfec8c)) -- Make `Blueprint` support Grammar's `macro` ([#31365](https://github.com/laravel/framework/pull/31365)) -- Added `Macroable` trait to `Illuminate\Console\Scheduling\Schedule` class ([#31354](https://github.com/laravel/framework/pull/31354)) -- Added support `dispatchAfterResponse` in `BusFake` ([#31418](https://github.com/laravel/framework/pull/31418), [e59597f](https://github.com/laravel/framework/commit/e59597f13af3ee6e6467bdb8593844f9db6bb789)) -- Added `Illuminate\Foundation\Exceptions\Handler::getHttpExceptionView()` ([#31420](https://github.com/laravel/framework/pull/31420)) -- Allowed appending of rows to Artisan tables ([#31426](https://github.com/laravel/framework/pull/31426)) - -### Fixed -- Fixed `locks` for `sqlsrv` queue ([5868066](https://github.com/laravel/framework/commit/58680668102282fcc4215a48e8947c2c1b051201)) -- Fixed `Illuminate\Events\Dispatcher::hasListeners()` ([#31403](https://github.com/laravel/framework/pull/31403), [c80302e](https://github.com/laravel/framework/commit/c80302e6e9403f9fad71f114d94e758ee0fcbff7)) -- Fixed testing with unencrypted cookies ([#31390](https://github.com/laravel/framework/pull/31390)) - -### Changed -- Allowed multiple paths to be passed to migrate fresh and migrate refresh commands ([#31381](https://github.com/laravel/framework/pull/31381)) -- Split Console InteractsWithIO to external trait ([#31376](https://github.com/laravel/framework/pull/31376)) -- Added sms link as valid URL in `UrlGenerator::isValid()` method ([#31382](https://github.com/laravel/framework/pull/31382)) -- Upgrade CommonMark and use the bundled table extension ([#31411](https://github.com/laravel/framework/pull/31411)) -- Ensure `Application::$terminatingCallbacks` are reset on `Application::flush()` ([#31413](https://github.com/laravel/framework/pull/31413)) -- Remove serializer option in `PhpRedisConnector::createClient()` ([#31417](https://github.com/laravel/framework/pull/31417)) - - -## [v6.14.0 (2020-02-04)](https://github.com/laravel/framework/compare/v6.13.1...v6.14.0) - -### Added -- Added `Illuminate\Bus\Dispatcher::dispatchAfterResponse()` method ([#31300](https://github.com/laravel/framework/pull/31300), [8a3cdb0](https://github.com/laravel/framework/commit/8a3cdb0622047b1d94b4a754bfe98fb7dc1c174a)) -- Added `Illuminate\Support\Testing\Fakes\QueueFake::assertPushedWithoutChain()` method ([#31332](https://github.com/laravel/framework/pull/31332), [7fcc6b5](https://github.com/laravel/framework/commit/7fcc6b5feb004f57aa61a0fa93c340694ae6a980)) -- Added `Macroable` trait to the `Illuminate\Events\Dispatcher` ([#31317](https://github.com/laravel/framework/pull/31317)) -- Added `NoPendingMigrations` event ([#31289](https://github.com/laravel/framework/pull/31289), [739fcea](https://github.com/laravel/framework/commit/739fcea5cfcc9079d3ca8e5aa9673f706741418e)) - -### Fixed -- Used current DB to create Doctrine Connections ([#31278](https://github.com/laravel/framework/pull/31278)) -- Removed duplicate output when publishing tags in `vendor:publish` command ([#31333](https://github.com/laravel/framework/pull/31333)) -- Fixed plucking column name containing a space ([#31299](https://github.com/laravel/framework/pull/31299)) -- Fixed bug with wildcard caching in event dispatcher ([#31313](https://github.com/laravel/framework/pull/31313)) -- Fixed infinite value for RedisStore ([#31348](https://github.com/laravel/framework/pull/31348)) -- Fixed dropping columns in SQLServer with default value ([#31341](https://github.com/laravel/framework/pull/31341)) - -### Changed -- Use SKIP LOCKED for mysql 8.1 and pgsql 9.5 queue workers ([#31287](https://github.com/laravel/framework/pull/31287)) -- Don't merge middleware from method and property in `Illuminate\Bus\Queueable::middleware()` ([#31301](https://github.com/laravel/framework/pull/31301)) -- Split `specifyParameter()` from `Illuminate\Console\Command` to `HasParameters` trait ([#31254](https://github.com/laravel/framework/pull/31254)) -- Make sure changing a database field to json does not include charset ([#31343](https://github.com/laravel/framework/pull/31343)) - - -## [v6.13.1 (2020-01-28)](https://github.com/laravel/framework/compare/v6.13.0...v6.13.1) - -### Fixed -- Fixed error on `queue:work` database on Windows ([#31277](https://github.com/laravel/framework/pull/31277)) - - -## [v6.13.0 (2020-01-28)](https://github.com/laravel/framework/compare/v6.12.0...v6.13.0) - -### Added -- Added `--api` option to the `make:model` command ([#31197](https://github.com/laravel/framework/pull/31197), [#31222](https://github.com/laravel/framework/pull/31222)) -- Added `PendingResourceRegistration::shallow()` method ([#31208](https://github.com/laravel/framework/pull/31208), [104c539](https://github.com/laravel/framework/commit/104c539c342d395e2f3c4ba7339df095f83f6352)) -- Allowed formatting an implicit attribute using a closure ([#31246](https://github.com/laravel/framework/pull/31246)) -- Added `Filesystem::ensureDirectoryExists()` method ([8a8eed4](https://github.com/laravel/framework/commit/8a8eed4d157102ef77527891ac1d8f8e85e7afee)) -- Added support to `Storage::url()` for the Ftp driver ([#31258](https://github.com/laravel/framework/pull/31258), [b8790e5](https://github.com/laravel/framework/commit/b8790e56bb7333943db799e6ff6e21a7b01218e0)) - -### Fixed -- Fixed laravel migrations when migrating to sql server (dropColumn with default value) ([#31229](https://github.com/laravel/framework/pull/31229)) -- Fixed `handleBeginTransactionException()` method calling pdo property instead of getPdo() method ([#31233](https://github.com/laravel/framework/pull/31233)) -- Fixed channel names when broadcasting via redis ([#31261](https://github.com/laravel/framework/pull/31261)) -- Replace asterisks before validation ([#31257](https://github.com/laravel/framework/pull/31257)) - -### Changed -- Reset timeout handler after worker loop ([#31198](https://github.com/laravel/framework/pull/31198)) - - -## [v6.12.0 (2020-01-21)](https://github.com/laravel/framework/compare/v6.11.0...v6.12.0) - -### Added -- Added `ServiceProvider::loadFactoriesFrom()` method ([#31133](https://github.com/laravel/framework/pull/31133)) -- Added `TestResponse::dumpSession()` method ([#31131](https://github.com/laravel/framework/pull/31131)) -- Added `Str::isUuid()` method ([#31148](https://github.com/laravel/framework/pull/31148)) -- Restored phpunit 7 support ([#31113](https://github.com/laravel/framework/pull/31113)) -- Added `Request::boolean()` method ([#31160](https://github.com/laravel/framework/pull/31160)) -- Added `Database\Eloquent\FactoryBuilder::createMany()` ([#31171](https://github.com/laravel/framework/pull/31171), [6553d59](https://github.com/laravel/framework/commit/6553d5923959bd947b49eb089053cd430d8968d4)) -- Added missing options for PhpRedis ([#31182](https://github.com/laravel/framework/pull/31182)) - -### Fixed -- Fixed `Cache\RedisLock::acquire()` ([#31168](https://github.com/laravel/framework/pull/31168), [8683a3d](https://github.com/laravel/framework/commit/8683a3d721f92e512a83a3e5feb3d0a9bb682560)) -- Fixed database url parsing for connections with no database specified ([#31185](https://github.com/laravel/framework/pull/31185)) -- Prevent ambiguous column with table name prefix ([#31174](https://github.com/laravel/framework/pull/31174)) - -### Optimization -- Fixed memory usage on downloading large files ([#31163](https://github.com/laravel/framework/pull/31163)) - -### Changed -- Replace Event Dispatcher in resolved cache repositories when `Event::fake()` is used ([#31119](https://github.com/laravel/framework/pull/31119), [0a70beb](https://github.com/laravel/framework/commit/0a70bebd5ecfd51185a312bbfb60ee7f8ff7eb09)) - - -## [v6.11.0 (2020-01-14)](https://github.com/laravel/framework/compare/v6.10.1...v6.11.0) - -### Added -- Added `Illuminate\Database\Eloquent\Builder::firstWhere()` method ([#31089](https://github.com/laravel/framework/pull/31089)) -- Redis Broadcaster: Broadcast to multiple channels at once ([#31108](https://github.com/laravel/framework/pull/31108)) - -### Fixed -- Fixed undefined property in `WithFaker::makeFaker()` ([#31083](https://github.com/laravel/framework/pull/31083)) -- Fixed `Str::afterLast()` method ([#31095](https://github.com/laravel/framework/pull/31095)) -- Fixed insert float into MySQL with PHP 7.3 ([#31100](https://github.com/laravel/framework/pull/31100)) -- Fixed refresh on Model with customized pivot attribute name ([#31125](https://github.com/laravel/framework/pull/31125), [678b26b](https://github.com/laravel/framework/commit/678b26b1a9cd0d8a6bef85932420e67a1b20e677)) - -### Changed -- Remove all indentation in blade templates ([917ee51](https://github.com/laravel/framework/commit/917ee514d4bbd4162b6ddb385c643df97dcfa7d3)) -- Added mailable names to assertion messages in `MailFake::assertNothingSent()` and `MailFake::assertNothingQueued()` ([#31106](https://github.com/laravel/framework/pull/31106)) -- Search for similar results in `assertDatabaseHas()` ([#31042](https://github.com/laravel/framework/pull/31042), [2103eb7](https://github.com/laravel/framework/commit/2103eb7ccfbb6798e9078d82e0ebffcf87d95b14)) - - -## [v6.10.1 (2020-01-08)](https://github.com/laravel/framework/compare/v6.10.0...v6.10.1) - -### Changed -- Updated some blade templates ([f17e347](https://github.com/laravel/framework/commit/f17e347b15e8d27b4e775a8f961bda083326ee8f)) - - -## [v6.10.0 (2020-01-07)](https://github.com/laravel/framework/compare/v6.9.0...v6.10.0) - -### Added -- Added `withoutMix()` and `withMix()` test helpers ([#30900](https://github.com/laravel/framework/pull/30900)) -- Added `validateWithBag()` macro to `Request` ([#30896](https://github.com/laravel/framework/pull/30896)) -- Added PHPUnit 9 support ([#30947](https://github.com/laravel/framework/pull/30947), [#30989](https://github.com/laravel/framework/pull/30989)) -- Added `exclude_if` and `exclude_unless` validation rules ([#30835](https://github.com/laravel/framework/pull/30835), [c0fdb56](https://github.com/laravel/framework/commit/c0fdb566831b7ebf34a15bbdfec81dd0039c76f0)) -- Added generated columns (virtual/stored) support for PostgreSQL ([#30971](https://github.com/laravel/framework/pull/30971)) -- Added `mixin` support to Eloquent builder ([#30978](https://github.com/laravel/framework/pull/30978), [28fa74e](https://github.com/laravel/framework/commit/28fa74e8222a57118ae1b590101a35f63b964f81)) -- Make the Redis Connection `Macroable` ([#31020](https://github.com/laravel/framework/pull/31020)) -- Added `PackageManifest::config()` method ([#31039](https://github.com/laravel/framework/pull/31039), [9b73540](https://github.com/laravel/framework/commit/9b73540cbe7ebb67b0a0a127743791511e5ae8fe)) -- Added `redis.connection` aliases in container ([#31034](https://github.com/laravel/framework/pull/31034)) -- Extracted `CallsCommands` feature from `Illuminate\Console\Command` ([#31026](https://github.com/laravel/framework/pull/31026), [ef72716](https://github.com/laravel/framework/commit/ef72716db85f36e003fb92d2625adabbf94d5afe)) -- Allowed absolute file path for `Storage::putFile()` ([#31040](https://github.com/laravel/framework/pull/31040)) - -### Changed -- Handled passing too many arguments to `@slot` ([#30893](https://github.com/laravel/framework/pull/30893), [878f159](https://github.com/laravel/framework/commit/878f15922523e748bfbfdf50f40269f8ffe20d9d)) -- Make `ThrottleRequestsException` extend `TooManyRequestsHttpException` ([#30943](https://github.com/laravel/framework/pull/30943)) -- Used `league/commonmark` instead of `erusev/parsedown` for mail markdown ([#30982](https://github.com/laravel/framework/pull/30982)) -- Regenerate token on logout ([b2af428](https://github.com/laravel/framework/commit/b2af428e60188ea55fb06f3a1e0b0b0c690bbe86)) -- Make `RedisQueue::getConnection()` public ([#31016](https://github.com/laravel/framework/pull/31016)) -- Resolve `Faker\Generator` out of the container if it is bound ([#30992](https://github.com/laravel/framework/pull/30992)) - -### Fixed -- Fixed `float` database types in `Blueprint` ([#30891](https://github.com/laravel/framework/pull/30891)) -- Fixed code that depended on `getenv()` ([#30924](https://github.com/laravel/framework/pull/30924)) -- Prevented making actual pdo connections while reconnecting ([#30998](https://github.com/laravel/framework/pull/30998)) -- Fixed `exclude_if` \ `exclude_unless` validation rules for nested data ([#31006](https://github.com/laravel/framework/pull/31006)) -- Update `dev-master` branch aliases from `6.0-dev` to `6.x-dev` ([d06cc79](https://github.com/laravel/framework/commit/d06cc79d92c18b0ff423466554eeed0aea09ae51)) -- Utilize Symfony’s PSR Factory. Fixed [#31017](https://github.com/laravel/framework/issues/31017) ([#31018](https://github.com/laravel/framework/pull/31018), [#31027](https://github.com/laravel/framework/pull/31027)) -- Used model connection by default in the database validators ([#31037](https://github.com/laravel/framework/pull/31037)) - -### Optimization -- Optimize Service Provider registration ([#30960](https://github.com/laravel/framework/pull/30960)) -- Optimize `runningInConsole` method ([#30922](https://github.com/laravel/framework/pull/30922)) -- Delay instantiation of translator and view factory ([#31009](https://github.com/laravel/framework/pull/31009)) - -### Deprecated -- Deprecate `PendingMail::sendNow()` and remove unneeded check ([#30999](https://github.com/laravel/framework/pull/30999)) - -### Reverted -- Reverted [TransactionCommitted event doesn’t contain transaction level I’d expect it to](https://github.com/laravel/framework/pull/30883) ([#31051](https://github.com/laravel/framework/pull/31051)) - -### Refactoring -- Refactoring of `BladeCompiler::compileString()` method ([08887f9](https://github.com/laravel/framework/commit/08887f99d05bb85affd3cbc6f7fdbc32a9297eea)) - - -## [v6.9.0 (2019-12-19)](https://github.com/laravel/framework/compare/v6.8.0...v6.9.0) - -### Added -- Added `MIME` type argument to `Testing/FileFactory::create()` ([#30870](https://github.com/laravel/framework/pull/30870)) -- Added `seed` to `all` option when creating the model (`make:model` command) ([#30874](https://github.com/laravel/framework/pull/30874)) -- Allowed configurable emergency logger ([#30873](https://github.com/laravel/framework/pull/30873)) -- Added `prependMiddlewareToGroup()` / `appendMiddlewareToGroup()` / `prependToMiddlewarePriority()` / `appendToMiddlewarePriority()` to `Kernal` for manipulating middleware ([6f33feb](https://github.com/laravel/framework/commit/6f33feba124d4a7ff2af4f3ed18583d67fb68f7c)) - -### Reverted -- Reverted [Added `Model::setRawAttribute()`](https://github.com/laravel/framework/pull/30853) ([#30885](https://github.com/laravel/framework/pull/30885)) - -### Fixed -- Fixed `Builder::withCount()` binding error when a scope is added into related model with binding in a sub-select ([#30869](https://github.com/laravel/framework/pull/30869)) - -### Changed -- Don't throw exception when session is not set in `AuthenticateSession` middleware ([4de1d24](https://github.com/laravel/framework/commit/4de1d24cf390f07d4f503973e5556f73060fbb31)) - - -## [v6.8.0 (2019-12-17)](https://github.com/laravel/framework/compare/v6.7.0...v6.8.0) - -### Added -- Allowed packages to use custom markdown mail themes ([#30814](https://github.com/laravel/framework/pull/30814), [2206d52](https://github.com/laravel/framework/commit/2206d5223606f5a24e7e3bf0ba1f25b343dfcc6b)) -- Added more quotes to `Inspiring` ([4a7d566](https://github.com/laravel/framework/commit/4a7d566ff4a330970cfaa03df4c988c580804a7f), [9693ced](https://github.com/laravel/framework/commit/9693cedbfc1fb0e38a8e688375e5b2ce5273b75f)) -- Added support for nested arrays in `TestResponse::assertViewHas()` ([#30837](https://github.com/laravel/framework/pull/30837)) -- Added `Model::setRawAttribute()` ([#30853](https://github.com/laravel/framework/pull/30853)) -- Added `--force` option to the `make:controller` resource ([#30856](https://github.com/laravel/framework/pull/30856)) -- Allowed passing an array to `Resource::collection()` ([#30800](https://github.com/laravel/framework/pull/30800)) -- Implemented ArrayAccess on `JsonResponse` and `TestResponse` ([#30817](https://github.com/laravel/framework/pull/30817)) -- Added `--seed` option to the `make::model` resource ([#30828](https://github.com/laravel/framework/pull/30828), [2cd9417](https://github.com/laravel/framework/commit/2cd9417064123fd6c9114788d331659ede568dbf)) - -### Fixed -- Fixed two index creation instead of one when using `change()` ([#30843](https://github.com/laravel/framework/pull/30843)) -- Prevent duplicate attachments in the `Mailable` ([3c8ccc2](https://github.com/laravel/framework/commit/3c8ccc2fb4ec03572076e6df71608f6bbb7d71e1)) -- Fixed `ServiceProvider` for PHP 7.4 in `Lumen` ([#30819](https://github.com/laravel/framework/pull/30819)) -- Fixed non-eloquent model validation in database validation rules ([#30840](https://github.com/laravel/framework/pull/30840)) - -### Changed -- Changed `rescue()` helper ([#30838](https://github.com/laravel/framework/pull/30838)) -- Added previous exception to `EntryNotFoundException` thrown in `Container.php` ([#30862](https://github.com/laravel/framework/pull/30862)) -- Changed `DatabaseNotification::$keyType` to match `uuid` ([#30823](https://github.com/laravel/framework/pull/30823)) - - -## [v6.7.0 (2019-12-10)](https://github.com/laravel/framework/compare/v6.6.2...v6.7.0) - -### Added -- Added `getQualifiedCreatedAtColumn()` and `getQualifiedUpdatedAtColumn()` methods to `HasTimestamps` concern ([#30792](https://github.com/laravel/framework/pull/30792)) -- Added `exceptionContext()` method to the `Exceptions\Handler` ([#30780](https://github.com/laravel/framework/pull/30780)) -- Added ability for postmark transport to throw errors ([#30799](https://github.com/laravel/framework/pull/30799), [4320b82](https://github.com/laravel/framework/commit/4320b82f848d63d41df95860ed3bf595202873a9)) -- Added `withoutRelations()` and `unsetRelations()` methods to `HasRelationships` ([#30802](https://github.com/laravel/framework/pull/30802)) -- Added `ResourceCollection::preserveQueryParameters()` for preserve query parameters on paginated api resources ([#30745](https://github.com/laravel/framework/pull/30745), [e92a708](https://github.com/laravel/framework/commit/e92a70800671187cc30a39e965144101d5db169a)) - -### Fixed -- Fixed explicit models in string-based database validation rules ([#30790](https://github.com/laravel/framework/pull/30790)) -- Fixed `Routing\RedirectController()` ([#30783](https://github.com/laravel/framework/pull/30783)) - -### Changed -- Reconnect `PhpRedisConnection` on connection missing ([#30778](https://github.com/laravel/framework/pull/30778)) -- Improved ShouldBroadcastNow performance ([#30797](https://github.com/laravel/framework/pull/30797), [5b3cc97](https://github.com/laravel/framework/commit/5b3cc9752d873be96ac34d9062cc35aa9c95bd59)) - - -## [v6.6.2 (2019-12-05)](https://github.com/laravel/framework/compare/v6.6.1...v6.6.2) - -### Added -- Added `Illuminate\Support\Facades\Facade::partialMock()` method ([#30754](https://github.com/laravel/framework/pull/30754)) -- Added of support `retryAfter` option on queued listeners ([#30743](https://github.com/laravel/framework/pull/30743)) - -### Fixed -- Fixed zero parameter for routes ([#30768](https://github.com/laravel/framework/pull/30768)) - -### Changed -- Changed `getAllViews()` method visibility from `protected` to `public` in all schema builders ([#30757](https://github.com/laravel/framework/pull/30757)) - - -## [v6.6.1 (2019-12-03)](https://github.com/laravel/framework/compare/v6.6.0...v6.6.1) - -### Added -- Added `setInput()` and `setOutput()` methods to `Illuminate\Console\Command` ([#30706](https://github.com/laravel/framework/pull/30706)) - -### Fixed -- Fixed RouteUrlGenerator with empty string for required parameter ([#30714](https://github.com/laravel/framework/pull/30714)) - -### Changed -- Force usage getting timestamps columns in model ([#30697](https://github.com/laravel/framework/pull/30697)) - -### Reverted -- Revert [Added `Illuminate\Routing\Router::head()`](https://github.com/laravel/framework/pull/30646) ([#30710](https://github.com/laravel/framework/pull/30710)) - - -## [v6.6.0 (2019-11-26)](https://github.com/laravel/framework/compare/v6.5.2...v6.6.0) - -### Added -- Allowed explicit Model definitions in database rules ([#30653](https://github.com/laravel/framework/pull/30653), [9beceac](https://github.com/laravel/framework/commit/9beceacb1a1b8ba37cd0f775cb2fb81e21ba4c31)) -- Allowed `ResponseFactory::view()` to return first view ([#30651](https://github.com/laravel/framework/pull/30651)) -- Added `Foundation\Testing\Concerns\InteractsWithDatabase::assertDeleted()` method ([#30648](https://github.com/laravel/framework/pull/30648)) -- Added `Illuminate\Routing\Router::head()` ([#30646](https://github.com/laravel/framework/pull/30646)) -- Added `wherePivotNotIn()` and `orWherePivotNotIn()` methods to `BelongsToMany` ([#30671](https://github.com/laravel/framework/pull/30671)) -- Added options in `SqlServerConnector` to encrypt data with Azure Key vault ([#30636](https://github.com/laravel/framework/pull/30636)) - -### Fixed -- Fixed errors in `Illuminate\Http\Testing\FileFactory::create()` ([#30632](https://github.com/laravel/framework/pull/30632)) -- Fixed routing bug that causes missing parameters to be ignored ([#30659](https://github.com/laravel/framework/pull/30659)) - -### Changed -- Updated error message in `PhpRedisConnector::createClient()` if redis extension is not loaded ([#30673](https://github.com/laravel/framework/pull/30673), [184a0f4](https://github.com/laravel/framework/commit/184a0f45bc9959ebadf36a7dd6966c2bfcb96191)) -- Updated `windows_os()` helper to use PHP_OS_FAMILY ([#30660](https://github.com/laravel/framework/pull/30660)) - - -## [v6.5.2 (2019-11-19)](https://github.com/laravel/framework/compare/v6.5.1...v6.5.2) - -### Added -- Allowed model serialization on jobs for typed properties ([#30604](https://github.com/laravel/framework/pull/30604), [#30605](https://github.com/laravel/framework/pull/30605), [920c364](https://github.com/laravel/framework/commit/920c3640269b7c1dd0f26e5b6f765ca9b7f99366)) -- Allowed fallback when facade root accessor has previously been resolved ([#30616](https://github.com/laravel/framework/pull/30616)) -- Added support for separation between `geometry` and `geography` types for `Postgres` ([#30545](https://github.com/laravel/framework/pull/30545)) -- Added `createWithContent()` method to `Illuminate\Http\Testing\File` and `Illuminate\Http\Testing\FileFactory` ([2cc6fa3](https://github.com/laravel/framework/commit/2cc6fa33732118cc71c74209b02382b989689b63), [181db51](https://github.com/laravel/framework/commit/181db51595d546cbd24b3fac0cb276255e147286)) - -### Refactoring -- Improved `PostgresGrammar::formatPostGisType()` method readability ([#30593](https://github.com/laravel/framework/pull/30593)) - -### Changed -- Added `symfony/debug` dependency to `illuminate/pipeline` ([#30611](https://github.com/laravel/framework/pull/30611)) -- Override `BelongsToMany::cursor()` to hydrate pivot relations ([#30580](https://github.com/laravel/framework/pull/30580)) -- Ignore Redis prefix when verifying channel access in RedisBroadcaster ([#30597](https://github.com/laravel/framework/pull/30597), [d77ce36](https://github.com/laravel/framework/commit/d77ce36917510d5a6800dd4116a4e18b7bf720b3)) - - -## [v6.5.1 (2019-11-12)](https://github.com/laravel/framework/compare/v6.5.0...v6.5.1) - -### Added -- Added `includeUnless` Blade directive ([#30538](https://github.com/laravel/framework/pull/30538)) - -### Fixed -- Fixed default value for $count in `PhpRedisConnection::spop()` method ([#30546](https://github.com/laravel/framework/pull/30546)) -- Fixed breaking compatibility with multi-schema postgres ([#30562](https://github.com/laravel/framework/pull/30562), [6460d2b](https://github.com/laravel/framework/commit/6460d2b1bd89f470a76f5c2c3bddd390fe430e0f)) -- Fixed `Model::isDirty()` with `collection` / `object` casts ([#30565](https://github.com/laravel/framework/pull/30565)) -- Fixed `bcc` in `MailgunTransport::send()` ([#30569](https://github.com/laravel/framework/pull/30569)) - -### Changed -- Remove `illuminate/support` dependency from `Container` package ([#30518](https://github.com/laravel/framework/pull/30518), [#30528](https://github.com/laravel/framework/pull/30528)) - - -## [v6.5.0 (2019-11-05)](https://github.com/laravel/framework/compare/v6.4.1...v6.5.0) - -### Added -- Added `LazyCollection::remember()` method ([#30443](https://github.com/laravel/framework/pull/30443)) -- Added `Str::afterLast()` and `Str::beforeLast()` methods ([#30507](https://github.com/laravel/framework/pull/30507)) -- Added `existsOr()` and `doesntExistOr()` methods to the query builder ([#30495](https://github.com/laravel/framework/pull/30495)) -- Added `unless` condition to Blade custom `if` directives ([#30492](https://github.com/laravel/framework/pull/30492)) - -### Changed -- Added reconnect if missing connection when beginning transaction ([#30474](https://github.com/laravel/framework/pull/30474)) -- Set Redis cluster prefix with PhpRedis ([#30461](https://github.com/laravel/framework/pull/30461)) - - -## [v6.4.1 (2019-10-29)](https://github.com/laravel/framework/compare/v6.4.0...v6.4.1) - -### Added -- Added `ScheduledTaskSkipped` event when a scheduled command was filtered from running ([#30407](https://github.com/laravel/framework/pull/30407)) -- Added `Login timeout expired` to `DetectsLostConnections` ([#30362](https://github.com/laravel/framework/pull/30362)) -- Added `missing` method to `Illuminate\Filesystem\Filesystem` and `Illuminate\Filesystem\FilesystemAdapter` classes ([#30441](https://github.com/laravel/framework/pull/30441)) - -### Changed -- Make `vendor:publish` command more informative ([#30408](https://github.com/laravel/framework/pull/30408), [65d040d](https://github.com/laravel/framework/commit/65d040d44f1cef3830748ec59c0056bc2418dca6)) -- Accepted underscores URL in the `URL` validator ([#30417](https://github.com/laravel/framework/pull/30417)) -- Updated `artisan down` output to be consistent with `artisan up` ([#30422](https://github.com/laravel/framework/pull/30422)) -- Changed `!empty` to `isset` for changing redis database ([#30420](https://github.com/laravel/framework/pull/30420)) -- Throw an exception when signing route got in parameter keys `signature` ([#30444](https://github.com/laravel/framework/pull/30444), [71af732](https://github.com/laravel/framework/commit/71af732b6b00ab148cd23b95aca4e05bcb86c242)) - -### Fixed -- Fixed of retrieving view config in `ServiceProvider::loadViewsFrom()` for Lumen ([#30404](https://github.com/laravel/framework/pull/30404)) - - -## [v6.4.0 (2019-10-23)](https://github.com/laravel/framework/compare/v6.3.0...v6.4.0) - -### Added -- Added `missing()` method to `Request` class ([#30320](https://github.com/laravel/framework/pull/30320)) -- Added `Pipeline::pipes()` method ([#30346](https://github.com/laravel/framework/pull/30346)) -- Added `TestResponse::assertCreated()` method ([#30368](https://github.com/laravel/framework/pull/30368)) - -### Changed -- Added `connection is no longer usable` to `DetectsLostConnections` ([#30362](https://github.com/laravel/framework/pull/30362)) -- Implemented parse ID on find method for many to many relation ([#30359](https://github.com/laravel/framework/pull/30359)) -- Improvements on subqueries ([#30307](https://github.com/laravel/framework/pull/30307), [3f3b621](https://github.com/laravel/framework/commit/3f3b6214cc3353156a490d88fc8f0c148da400d5)) -- Pass mail data to theme css in `Markdown::render()` method ([#30376](https://github.com/laravel/framework/pull/30376)) -- Handle ajax requests in RequirePassword middleware ([#30390](https://github.com/laravel/framework/pull/30390), [331c354](https://github.com/laravel/framework/commit/331c354e586a5a27a9edc9b9a49d23aa872e4b32)) - -### Fixed -- Fixed `retry()` with `$times` value less then 1 ([#30356](https://github.com/laravel/framework/pull/30356)) -- Fixed `last_modified` option in `SetCacheHeader` ([#30335](https://github.com/laravel/framework/pull/30335)) -- Fixed the Filesystem manager's exception on unsupported driver ([#30331](https://github.com/laravel/framework/pull/30331), [#30369](https://github.com/laravel/framework/pull/30369)) -- Fixed `shouldQueue()` check for bound event listeners ([#30378](https://github.com/laravel/framework/pull/30378)) -- Used exit code `1` when migration table not found ([#30321](https://github.com/laravel/framework/pull/30321)) -- Alleviate breaking change introduced by password confirm feature ([#30389](https://github.com/laravel/framework/pull/30389)) - -### Security: -- Password Reset Security fix ([23041e9](https://github.com/laravel/framework/commit/23041e99833630d93cc7672bd7087eaa350c3a59), [a934160](https://github.com/laravel/framework/commit/a9341609705e2f8febcd356cdfa33391ec6538c7)) - - -## [v6.3.0 (2019-10-15)](https://github.com/laravel/framework/compare/v6.2.0...v6.3.0) - -### Added -- Added ability to override `setUserPassword` on password reset ([#30218](https://github.com/laravel/framework/pull/30218)) -- Added firing `deleting` / `deleted` events in `MorphPivot` ([#30229](https://github.com/laravel/framework/pull/30229)) -- Added locking mechanism for the array cache driver ([#30253](https://github.com/laravel/framework/pull/30253)) -- Added `dropAllViews` functionality to the SQL Server builder ([#30222](https://github.com/laravel/framework/pull/30222)) - -### Optimization -- Optimize eager loading memory handling ([#30248](https://github.com/laravel/framework/pull/30248)) - -### Fixed -- Fixed extra `?` for empty query string in `RouteUrlGenerator::getRouteQueryString()` ([#30280](https://github.com/laravel/framework/pull/30280)) - -### Changed -- Updated list of URI schemes for `Url` validator ([#30220](https://github.com/laravel/framework/pull/30220)) -- Added schema name when dropping all FKs in SQL Server ([#30221](https://github.com/laravel/framework/pull/30221)) -- Used contracts in `RequirePassword` middleware ([#30215](https://github.com/laravel/framework/pull/30215)) -- Added ability to return array in `receivesBroadcastNotificationsOn` if `channelName` is array ([#30242](https://github.com/laravel/framework/pull/30242), [2faadcd](https://github.com/laravel/framework/commit/2faadcd288cdc86cf7a1a3644e68e5e0ce641a8b)) - - -## [v6.2.0 (2019-10-08)](https://github.com/laravel/framework/compare/v6.1.0...v6.2.0) - -### Added -- Added support for callable objects in `Container::call()` ([#30156](https://github.com/laravel/framework/pull/30156)) -- Add multipolygonz type for postgreSQL ([#30173](https://github.com/laravel/framework/pull/30173)) -- Add "unauthenticated" method in auth middleware ([#30177](https://github.com/laravel/framework/pull/30177)) -- Add partialMock shorthand ([#30202](https://github.com/laravel/framework/pull/30202)) -- Allow Storage::put to accept a Psr StreamInterface ([#30179](https://github.com/laravel/framework/pull/30179)) -- Implement new password rule and password confirmation ([#30214](https://github.com/laravel/framework/pull/30214)) - -### Changed -- Remove unnecessary param passed to updatePackageArray method ([#30155](https://github.com/laravel/framework/pull/30155)) -- Add optional connection name to DatabaseUserProvider ([#30154](https://github.com/laravel/framework/pull/30154)) -- Remove brackets arround URL php artisan serve ([#30168](https://github.com/laravel/framework/pull/30168)) -- Apply limit to database rather than collection ([#30148](https://github.com/laravel/framework/pull/30148)) -- Allow to use scoped macro in nested queries ([#30127](https://github.com/laravel/framework/pull/30127)) -- Added array to json conversion for sqlite ([#30133](https://github.com/laravel/framework/pull/30133)) -- Use the `policies()` method instead of the property policies ([#30189](https://github.com/laravel/framework/pull/30189)) -- Split hasValidSignature method ([#30208](https://github.com/laravel/framework/pull/30208)) - -### Fixed -- `validateDimensions()` handle `image/svg` MIME ([#30204](https://github.com/laravel/framework/pull/30204)) - - -## [v6.1.0 (2019-10-01)](https://github.com/laravel/framework/compare/v6.0.4...v6.1.0) - -### Added -- Added `Illuminate\Support\LazyCollection::eager()` method ([#29832](https://github.com/laravel/framework/pull/29832)) -- Added `forgetChannel()` and `getChannels()` methods to `Illuminate\Log\LogManager` ([#30132](https://github.com/laravel/framework/pull/30132), [a52a0dd](https://github.com/laravel/framework/commit/a52a0dd239262f31edfaefe9a99213cccefc2f36)) -- Added `Illuminate\Foundation\Testing\TestResponse::assertNoContent()` method ([#30125](https://github.com/laravel/framework/pull/30125)) -- Added `InteractsWithQueue` to `SendQueueNotifications` ([#30140](https://github.com/laravel/framework/pull/30140)) -- Added `SendQueueNotifications::retryUntil()` method ([#30141](https://github.com/laravel/framework/pull/30141)) -- Added methods for sending cookies with test requests ([#30101](https://github.com/laravel/framework/pull/30101)) -- Added support of job middleware for queued notifications ([#30070](https://github.com/laravel/framework/pull/30070)) - -### Fixed -- Fixed migration class duplicate check in `make:migration` command ([#30095](https://github.com/laravel/framework/pull/30095)) -- Fixed monolog v2 handler preparation ([#30123](https://github.com/laravel/framework/pull/30123)) -- Fixed return of callback value for DurationLimiter ([#30143](https://github.com/laravel/framework/pull/30143)) - -### Changed -- Added runtime information output for seeders ([#30086](https://github.com/laravel/framework/pull/30086)) -- Added strict parameter to `Illuminate\Foundation\Testing\TestResponse::assertJsonPath()` ([#30142](https://github.com/laravel/framework/pull/30142)) -- Added `deletedAtColumn` optional parameter to `Foundation\Testing\Concerns\InteractsWithDatabase::assertSoftDeleted()` ([#30111](https://github.com/laravel/framework/pull/30111)) - -### Improved -- Improved `AuthServiceProvider::registerEventRebindHandler()` in case if guard is not initialized ([#30105](https://github.com/laravel/framework/pull/30105)) - - -## [v6.0.4 (2019-09-24)](https://github.com/laravel/framework/compare/v6.0.3...v6.0.4) - -### Added -- Added `TestResponse::assertJsonPath()` method ([#29957](https://github.com/laravel/framework/pull/29957)) -- Added `hasMacro` / `getGlobalMacro` / `hasGlobalMacro` methods to `Eloquent Builder` ([#30008](https://github.com/laravel/framework/pull/30008)) -- Added `Illuminate\Database\Eloquent\Relations\BelongsToMany::getPivotColumns()` method ([#30049](https://github.com/laravel/framework/pull/30049)) -- Added `ScheduledTaskFinished` / `ScheduledTaskStarting` events to signal when scheduled task runs ([#29888](https://github.com/laravel/framework/pull/29888)) -- Allowing adding command arguments and options with `InputArgument` / `InputOption` objects ([#29987](https://github.com/laravel/framework/pull/29987)) - -### Fixed -- Fixed `__()` with `null` parameter ([#29967](https://github.com/laravel/framework/pull/29967)) -- Fixed modifying `updated_at` column on custom pivot model ([#29970](https://github.com/laravel/framework/pull/29970)) -- Fixed `Illuminate\Redis\Limiters\ConcurrencyLimiter` ([#30005](https://github.com/laravel/framework/pull/30005)) -- Fixed `VerifyCsrfToken` middleware when response object instance of `Responsable` interface ([#29972](https://github.com/laravel/framework/pull/29972)) -- Fixed Postgresql column creation without optional precision ([#29873](https://github.com/laravel/framework/pull/29873)) -- Fixed migrations orders with multiple path with certain filenames ([#29996](https://github.com/laravel/framework/pull/29996)) -- Fixed adding `NotFoundHttpException` to "allowed" exceptions in tests ([#29975](https://github.com/laravel/framework/pull/29975)) - -### Changed -- Make it possible to disable encryption via `0` / `false` ([#29985](https://github.com/laravel/framework/pull/29985)) -- Allowed a symfony file instance in validate dimensions ([#30009](https://github.com/laravel/framework/pull/30009)) -- Create storage fakes with custom configuration ([#29999](https://github.com/laravel/framework/pull/29999)) -- Set locale in `PendingMail` only if locale present conditionally ([dd1e0a6](https://github.com/laravel/framework/commit/dd1e0a604713ddae21e6a893e4f605a6777300e8)) -- Improved sorting of imports alphabetically on class generation from stub ([#29951](https://github.com/laravel/framework/pull/29951)) - -### Refactoring -- Changed imports to Alpha ordering in stubs ([#29954](https://github.com/laravel/framework/pull/29954), [#29958](https://github.com/laravel/framework/pull/29958)) -- Used value helper where possible ([#29959](https://github.com/laravel/framework/pull/29959)) -- Improved readability in `auth.throttle` translation ([#30011](https://github.com/laravel/framework/pull/30011), [#30017](https://github.com/laravel/framework/pull/30017)) - - -## [v6.0.3 (2019-09-10)](https://github.com/laravel/framework/compare/v6.0.2...v6.0.3) - -### Reverted -- Reverted [Wrapped `MySQL` default values in parentheses](https://github.com/laravel/framework/pull/29878) ([#29943](https://github.com/laravel/framework/pull/29943)) - -### Refactoring -- Converted `call_user_func` where appropriate to native calls ([#29932](https://github.com/laravel/framework/pull/29932)) -- Changed imports to Alpha ordering ([#29933](https://github.com/laravel/framework/pull/29933)) - - -## [v6.0.2 (2019-09-10)](https://github.com/laravel/framework/compare/v6.0.1...v6.0.2) - -### Changed -- Used `Application::normalizeCachePath()` method to define cache path`s ([#29890](https://github.com/laravel/framework/pull/29890), [ac9dbf6](https://github.com/laravel/framework/commit/ac9dbf6beaded2ad86f5595958c75e3c4b1147ae)) -- Wrapped `MySQL` default values in parentheses ([#29878](https://github.com/laravel/framework/pull/29878)) - -### Fixed -- Prevent `event auto discovery` from crashing when trying to instantiate files without php classes ([#29895](https://github.com/laravel/framework/pull/29895)) -- Fix resolving class command via container ([#29869](https://github.com/laravel/framework/pull/29869)) - - -## [v6.0.1 (2019-09-06)](https://github.com/laravel/framework/compare/v6.0.0...v6.0.1) - -### Fixed -- Fixed `Schedule::runInBackground()` not fired on Windows ([#29826](https://github.com/laravel/framework/pull/29826)) - -### Changed -- Throw `Symfony\Component\Routing\Exception\RouteNotFoundException` instead of `InvalidArgumentException` in `UrlGenerator::route()` ([#29861](https://github.com/laravel/framework/pull/29861)) - -### Reverted -- Reverted: [`Extract registered event and login to registered method`](https://github.com/laravel/framework/pull/27807) ([#29875](https://github.com/laravel/framework/pull/29875)) - - -## [v6.0.0 (2019-09-03)](https://github.com/laravel/framework/compare/5.8...v6.0.0) - -Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/6.0/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/6.x/releases). From 1762bd92ffdf53f934f8b6422a1b4c599b3fca30 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 10 Mar 2021 14:15:45 +0000 Subject: [PATCH 103/194] Bumped symfony version to ^5.3 (#36529) --- composer.json | 26 ++++++++++++------------ src/Illuminate/Cache/composer.json | 2 +- src/Illuminate/Collections/composer.json | 2 +- src/Illuminate/Console/composer.json | 4 ++-- src/Illuminate/Cookie/composer.json | 4 ++-- src/Illuminate/Database/composer.json | 4 ++-- src/Illuminate/Filesystem/composer.json | 6 +++--- src/Illuminate/Http/composer.json | 6 +++--- src/Illuminate/Queue/composer.json | 2 +- src/Illuminate/Routing/composer.json | 6 +++--- src/Illuminate/Session/composer.json | 4 ++-- src/Illuminate/Support/composer.json | 6 +++--- src/Illuminate/Validation/composer.json | 4 ++-- 13 files changed, 38 insertions(+), 38 deletions(-) diff --git a/composer.json b/composer.json index 011f9c47d68f..72d7ac06c630 100644 --- a/composer.json +++ b/composer.json @@ -31,17 +31,17 @@ "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", "swiftmailer/swiftmailer": "^6.2.7", - "symfony/console": "^5.2", - "symfony/error-handler": "^5.2", - "symfony/finder": "^5.2", - "symfony/http-foundation": "^5.2", - "symfony/http-kernel": "^5.2", - "symfony/mime": "^5.2", - "symfony/process": "^5.2", - "symfony/routing": "^5.2", - "symfony/var-dumper": "^5.2", + "symfony/console": "^5.3", + "symfony/error-handler": "^5.3", + "symfony/finder": "^5.3", + "symfony/http-foundation": "^5.3", + "symfony/http-kernel": "^5.3", + "symfony/mime": "^5.3", + "symfony/process": "^5.3", + "symfony/routing": "^5.3", + "symfony/var-dumper": "^5.3", "tijsverkoyen/css-to-inline-styles": "^2.2.2", - "vlucas/phpdotenv": "^5.2", + "vlucas/phpdotenv": "^5.3", "voku/portable-ascii": "^1.4.8" }, "replace": { @@ -90,7 +90,7 @@ "pda/pheanstalk": "^4.0", "phpunit/phpunit": "^9.4", "predis/predis": "^1.1.1", - "symfony/cache": "^5.2" + "symfony/cache": "^5.3" }, "provide": { "psr/container-implementation": "1.0" @@ -147,8 +147,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).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.2).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.2).", + "symfony/cache": "Required to PSR-6 cache bridge (^5.3).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^5.3).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index a0da4140dbed..a41a791f5039 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -35,7 +35,7 @@ "illuminate/database": "Required to use the database cache driver (^9.0).", "illuminate/filesystem": "Required to use the file cache driver (^9.0).", "illuminate/redis": "Required to use the redis cache driver (^9.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.2)." + "symfony/cache": "Required to PSR-6 cache bridge (^5.3)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index c41776dbdec8..1ec6a1b6827a 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -32,7 +32,7 @@ } }, "suggest": { - "symfony/var-dumper": "Required to use the dump method (^5.2)." + "symfony/var-dumper": "Required to use the dump method (^5.3)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 23312f86c46e..5115717e15c6 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -19,8 +19,8 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/console": "^5.2", - "symfony/process": "^5.2" + "symfony/console": "^5.3", + "symfony/process": "^5.3" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index b56b430ceefe..0a0519c1fcef 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -19,8 +19,8 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.2", - "symfony/http-kernel": "^5.2" + "symfony/http-foundation": "^5.3", + "symfony/http-kernel": "^5.3" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 39280b59a456..1baa558ba277 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -22,7 +22,7 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/console": "^5.2" + "symfony/console": "^5.3" }, "autoload": { "psr-4": { @@ -41,7 +41,7 @@ "illuminate/events": "Required to use the observers with Eloquent (^9.0).", "illuminate/filesystem": "Required to use the migrations (^9.0).", "illuminate/pagination": "Required to paginate the result set (^9.0).", - "symfony/finder": "Required to use Eloquent model factories (^5.2)." + "symfony/finder": "Required to use Eloquent model factories (^5.3)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index a75c23daf287..b0113cb9d294 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -19,7 +19,7 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/finder": "^5.2" + "symfony/finder": "^5.3" }, "autoload": { "psr-4": { @@ -39,8 +39,8 @@ "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^2.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^2.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.2).", - "symfony/mime": "Required to enable support for guessing extensions (^5.2)." + "symfony/filesystem": "Required to enable support for relative symbolic links (^5.3).", + "symfony/mime": "Required to enable support for guessing extensions (^5.3)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 9aab579afa4f..eb5ee847e2c0 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -20,9 +20,9 @@ "illuminate/macroable": "^9.0", "illuminate/session": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.2", - "symfony/http-kernel": "^5.2", - "symfony/mime": "^5.2" + "symfony/http-foundation": "^5.3", + "symfony/http-kernel": "^5.3", + "symfony/mime": "^5.3" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 104fc02e24a0..250e007f1930 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -26,7 +26,7 @@ "illuminate/support": "^9.0", "opis/closure": "^3.6", "ramsey/uuid": "^4.0", - "symfony/process": "^5.2" + "symfony/process": "^5.3" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 30ffcd8ebcf1..3eb2a654bf9d 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -24,9 +24,9 @@ "illuminate/pipeline": "^9.0", "illuminate/session": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.2", - "symfony/http-kernel": "^5.2", - "symfony/routing": "^5.2" + "symfony/http-foundation": "^5.3", + "symfony/http-kernel": "^5.3", + "symfony/routing": "^5.3" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 298a4caca293..13c56ea87fd4 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -20,8 +20,8 @@ "illuminate/contracts": "^9.0", "illuminate/filesystem": "^9.0", "illuminate/support": "^9.0", - "symfony/finder": "^5.2", - "symfony/http-foundation": "^5.2" + "symfony/finder": "^5.3", + "symfony/http-foundation": "^5.3" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index cc1564d433a7..8b3b5907379a 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -44,9 +44,9 @@ "illuminate/filesystem": "Required to use the composer class (^9.0).", "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^1.3).", "ramsey/uuid": "Required to use Str::uuid() (^4.0).", - "symfony/process": "Required to use the composer class (^5.2).", - "symfony/var-dumper": "Required to use the dd function (^5.2).", - "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.2)." + "symfony/process": "Required to use the composer class (^5.3).", + "symfony/var-dumper": "Required to use the dd function (^5.3).", + "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.3)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index af707b3f0c28..47257824d4be 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -23,8 +23,8 @@ "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", "illuminate/translation": "^9.0", - "symfony/http-foundation": "^5.2", - "symfony/mime": "^5.2" + "symfony/http-foundation": "^5.3", + "symfony/mime": "^5.3" }, "autoload": { "psr-4": { From e16f4b680c653640b8408ad648e5be8f8e638787 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 10 Mar 2021 14:16:55 +0000 Subject: [PATCH 104/194] Drop pusher/pusher-php-server 4.x (#36528) Co-authored-by: Taylor Otwell --- composer.json | 2 +- .../Broadcasters/PusherBroadcaster.php | 41 ++++--------------- src/Illuminate/Broadcasting/composer.json | 2 +- 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index 72d7ac06c630..3013fb636555 100644 --- a/composer.json +++ b/composer.json @@ -146,7 +146,7 @@ "phpunit/phpunit": "Required to use assertions and run tests (^9.4).", "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).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^5.0).", "symfony/cache": "Required to PSR-6 cache bridge (^5.3).", "symfony/filesystem": "Required to enable support for relative symbolic links (^5.3).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 15695e114e6f..fde951e9dbca 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -111,46 +111,19 @@ public function broadcast(array $channels, $event, array $payload = []) { $socket = Arr::pull($payload, 'socket'); - if ($this->pusherServerIsVersionFiveOrGreater()) { - $parameters = $socket !== null ? ['socket_id' => $socket] : []; - - try { - $this->pusher->trigger( - $this->formatChannels($channels), $event, $payload, $parameters - ); - } catch (ApiErrorException $e) { - throw new BroadcastException( - sprintf('Pusher error: %s.', $e->getMessage()) - ); - } - } else { - $response = $this->pusher->trigger( - $this->formatChannels($channels), $event, $payload, $socket, true - ); - - if ((is_array($response) && $response['status'] >= 200 && $response['status'] <= 299) - || $response === true) { - return; - } + $parameters = $socket !== null ? ['socket_id' => $socket] : []; + try { + $this->pusher->trigger( + $this->formatChannels($channels), $event, $payload, $parameters + ); + } catch (ApiErrorException $e) { throw new BroadcastException( - ! empty($response['body']) - ? sprintf('Pusher error: %s.', $response['body']) - : 'Failed to connect to Pusher.' + sprintf('Pusher error: %s.', $e->getMessage()) ); } } - /** - * Determine if the Pusher PHP server is version 5.0 or greater. - * - * @return bool - */ - protected function pusherServerIsVersionFiveOrGreater() - { - return class_exists(ApiErrorException::class); - } - /** * Get the Pusher SDK instance. * diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index 347b74164c1b..5224a0edaea4 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -34,7 +34,7 @@ } }, "suggest": { - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0)." + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^5.0)." }, "config": { "sort-packages": true From 84c78b9f5f3dad58f92161069e6482f7267ffdb6 Mon Sep 17 00:00:00 2001 From: Sibghatullah Mujaddid Date: Thu, 11 Mar 2021 21:39:49 +0800 Subject: [PATCH 105/194] Change exception's handler ignore method to public (#36550) --- src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 38c29a3996c7..7c8b29c3baf8 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -191,7 +191,7 @@ public function map($from, $to = null) * @param string $class * @return $this */ - protected function ignore(string $class) + public function ignore(string $class) { $this->dontReport[] = $class; From 3aabbb7bae55e66a5316d1b3d5f70c06d79250b0 Mon Sep 17 00:00:00 2001 From: Reid Barden Date: Fri, 12 Mar 2021 08:52:31 -0500 Subject: [PATCH 106/194] fixes restrictive type declaration in InteractsWithViews (#36575) --- .../Foundation/Testing/Concerns/InteractsWithViews.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php index 574009a68f95..bbc65c7a10c2 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php @@ -18,7 +18,7 @@ trait InteractsWithViews * @param \Illuminate\Contracts\Support\Arrayable|array $data * @return \Illuminate\Testing\TestView */ - protected function view(string $view, array $data = []) + protected function view(string $view, $data = []) { return new TestView(view($view, $data)); } @@ -30,7 +30,7 @@ protected function view(string $view, array $data = []) * @param \Illuminate\Contracts\Support\Arrayable|array $data * @return \Illuminate\Testing\TestView */ - protected function blade(string $template, array $data = []) + protected function blade(string $template, $data = []) { $tempDirectory = sys_get_temp_dir(); @@ -52,7 +52,7 @@ protected function blade(string $template, array $data = []) * @param \Illuminate\Contracts\Support\Arrayable|array $data * @return \Illuminate\Testing\TestView */ - protected function component(string $componentClass, array $data = []) + protected function component(string $componentClass, $data = []) { $component = $this->app->make($componentClass, $data); From e9e91b0d88115c7a968beadd8a12af5114216f51 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 12 Mar 2021 17:48:17 +0100 Subject: [PATCH 107/194] Add Faker as dev dependency (#36586) --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 3013fb636555..da30eb089210 100644 --- a/composer.json +++ b/composer.json @@ -80,6 +80,7 @@ "require-dev": { "aws/aws-sdk-php": "^3.155", "doctrine/dbal": "^2.12|^3.0", + "fakerphp/faker": "^1.9.2", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^7.2", "league/flysystem-aws-s3-v3": "^2.0", From f8b0c0934d6b14ea863f1d16823731d3377cbd72 Mon Sep 17 00:00:00 2001 From: "iAm[i]nE" Date: Tue, 23 Mar 2021 15:51:49 +0100 Subject: [PATCH 108/194] Rename $conn to meaningful name $connection (#36713) --- src/Illuminate/Auth/DatabaseUserProvider.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Auth/DatabaseUserProvider.php b/src/Illuminate/Auth/DatabaseUserProvider.php index 8aa563d82023..7bd8edc55550 100755 --- a/src/Illuminate/Auth/DatabaseUserProvider.php +++ b/src/Illuminate/Auth/DatabaseUserProvider.php @@ -16,7 +16,7 @@ class DatabaseUserProvider implements UserProvider * * @var \Illuminate\Database\ConnectionInterface */ - protected $conn; + protected $connection; /** * The hasher implementation. @@ -40,9 +40,9 @@ class DatabaseUserProvider implements UserProvider * @param string $table * @return void */ - public function __construct(ConnectionInterface $conn, HasherContract $hasher, $table) + public function __construct(ConnectionInterface $connection, HasherContract $hasher, $table) { - $this->conn = $conn; + $this->connection = $connection; $this->table = $table; $this->hasher = $hasher; } @@ -55,7 +55,7 @@ public function __construct(ConnectionInterface $conn, HasherContract $hasher, $ */ public function retrieveById($identifier) { - $user = $this->conn->table($this->table)->find($identifier); + $user = $this->connection->table($this->table)->find($identifier); return $this->getGenericUser($user); } @@ -70,7 +70,7 @@ public function retrieveById($identifier) public function retrieveByToken($identifier, $token) { $user = $this->getGenericUser( - $this->conn->table($this->table)->find($identifier) + $this->connection->table($this->table)->find($identifier) ); return $user && $user->getRememberToken() && hash_equals($user->getRememberToken(), $token) @@ -86,7 +86,7 @@ public function retrieveByToken($identifier, $token) */ public function updateRememberToken(UserContract $user, $token) { - $this->conn->table($this->table) + $this->connection->table($this->table) ->where($user->getAuthIdentifierName(), $user->getAuthIdentifier()) ->update([$user->getRememberTokenName() => $token]); } @@ -108,7 +108,7 @@ public function retrieveByCredentials(array $credentials) // First we will add each credential element to the query as a where clause. // Then we can execute the query and, if we found a user, return it in a // generic "user" object that will be utilized by the Guard instances. - $query = $this->conn->table($this->table); + $query = $this->connection->table($this->table); foreach ($credentials as $key => $value) { if (Str::contains($key, 'password')) { From b132b09f4ca669428dc09473b9cb92448867d47a Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 24 Mar 2021 22:55:16 +0000 Subject: [PATCH 109/194] Fixed merge --- src/Illuminate/Foundation/Application.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 614079a8015b..ca35ce2429e0 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,11 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ -<<<<<<< HEAD const VERSION = '9.x-dev'; -======= - const VERSION = '8.34.0'; ->>>>>>> 8.x /** * The base path for the Laravel installation. From 76762f90e510c4cb74ed3907b8c26350e1c26ece Mon Sep 17 00:00:00 2001 From: Wouter Rutgers Date: Fri, 26 Mar 2021 13:03:07 +0100 Subject: [PATCH 110/194] add age option to flush failed jobs command --- .../Queue/Console/FlushFailedCommand.php | 10 ++++- .../Failed/DatabaseFailedJobProvider.php | 7 +++- .../Failed/DatabaseUuidFailedJobProvider.php | 7 +++- .../Failed/DynamoDbFailedJobProvider.php | 3 +- .../Failed/FailedJobProviderInterface.php | 3 +- .../Queue/Failed/NullFailedJobProvider.php | 3 +- tests/Queue/DatabaseFailedJobProviderTest.php | 42 +++++++++++++++++++ 7 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 tests/Queue/DatabaseFailedJobProviderTest.php diff --git a/src/Illuminate/Queue/Console/FlushFailedCommand.php b/src/Illuminate/Queue/Console/FlushFailedCommand.php index 302278af9bed..5372ff2cb869 100644 --- a/src/Illuminate/Queue/Console/FlushFailedCommand.php +++ b/src/Illuminate/Queue/Console/FlushFailedCommand.php @@ -11,7 +11,7 @@ class FlushFailedCommand extends Command * * @var string */ - protected $name = 'queue:flush'; + protected $signature = 'queue:flush {--age= : Only clear failed jobs older than the given age in days}'; /** * The name of the console command. @@ -36,7 +36,13 @@ class FlushFailedCommand extends Command */ public function handle() { - $this->laravel['queue.failer']->flush(); + $this->laravel['queue.failer']->flush($this->option('age')); + + if ($this->option('age')) { + $this->info("Failed jobs older than {$this->option('age')} days deleted successfully!"); + + return; + } $this->info('All failed jobs deleted successfully!'); } diff --git a/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php b/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php index 1a634f760d89..aece6f8c5bad 100644 --- a/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php @@ -98,11 +98,14 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * + * @param int|null $age * @return void */ - public function flush() + public function flush($age = null) { - $this->getTable()->delete(); + $this->getTable()->when($age, function ($query, $age) { + $query->where('failed_at', '<=', Date::now()->subDays($age)); + })->delete(); } /** diff --git a/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php b/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php index f452bf4ba22a..03356bcf1d1b 100644 --- a/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php @@ -111,11 +111,14 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * + * @param int|null $age * @return void */ - public function flush() + public function flush($age = null) { - $this->getTable()->delete(); + $this->getTable()->when($age, function ($query, $age) { + $query->where('failed_at', '<=', Date::now()->subDays($age)); + })->delete(); } /** diff --git a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php index 7b88b2394ee5..e97ba81772bb 100644 --- a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php @@ -165,11 +165,12 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * + * @param int|null $age * @return void * * @throws \Exception */ - public function flush() + public function flush($age = null) { throw new Exception("DynamoDb failed job storage may not be flushed. Please use DynamoDb's TTL features on your expires_at attribute."); } diff --git a/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php b/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php index 1a11fc0b5806..df4ae99c6672 100644 --- a/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php +++ b/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php @@ -41,7 +41,8 @@ public function forget($id); /** * Flush all of the failed jobs from storage. * + * @param int|null $age * @return void */ - public function flush(); + public function flush($age = null); } diff --git a/src/Illuminate/Queue/Failed/NullFailedJobProvider.php b/src/Illuminate/Queue/Failed/NullFailedJobProvider.php index 06f3e078603d..114406720a6c 100644 --- a/src/Illuminate/Queue/Failed/NullFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/NullFailedJobProvider.php @@ -53,9 +53,10 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * + * @param int|null $age * @return void */ - public function flush() + public function flush($age = null) { // } diff --git a/tests/Queue/DatabaseFailedJobProviderTest.php b/tests/Queue/DatabaseFailedJobProviderTest.php new file mode 100644 index 000000000000..88b9f59dd7d5 --- /dev/null +++ b/tests/Queue/DatabaseFailedJobProviderTest.php @@ -0,0 +1,42 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->timestamp('failed_at')->useCurrent(); + }); + + $provider = new DatabaseFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs'); + + $db->getConnection()->table('failed_jobs')->insert(['failed_at' => Date::now()->subDays(10)]); + $provider->flush(); + $this->assertSame(0, $db->getConnection()->table('failed_jobs')->count()); + + $db->getConnection()->table('failed_jobs')->insert(['failed_at' => Date::now()->subDays(10)]); + $provider->flush(15); + $this->assertSame(1, $db->getConnection()->table('failed_jobs')->count()); + + $db->getConnection()->table('failed_jobs')->insert(['failed_at' => Date::now()->subDays(10)]); + $provider->flush(10); + $this->assertSame(0, $db->getConnection()->table('failed_jobs')->count()); + } +} From 6daecf43dd931dc503e410645ff4a7d611e3371f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 26 Mar 2021 08:09:30 -0700 Subject: [PATCH 111/194] use hours --- src/Illuminate/Queue/Console/FlushFailedCommand.php | 8 ++++---- src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php | 8 ++++---- .../Queue/Failed/DatabaseUuidFailedJobProvider.php | 8 ++++---- src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php | 4 ++-- .../Queue/Failed/FailedJobProviderInterface.php | 4 ++-- src/Illuminate/Queue/Failed/NullFailedJobProvider.php | 4 ++-- tests/Queue/DatabaseFailedJobProviderTest.php | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Queue/Console/FlushFailedCommand.php b/src/Illuminate/Queue/Console/FlushFailedCommand.php index 5372ff2cb869..628b2b9995f0 100644 --- a/src/Illuminate/Queue/Console/FlushFailedCommand.php +++ b/src/Illuminate/Queue/Console/FlushFailedCommand.php @@ -11,7 +11,7 @@ class FlushFailedCommand extends Command * * @var string */ - protected $signature = 'queue:flush {--age= : Only clear failed jobs older than the given age in days}'; + protected $signature = 'queue:flush {--hours= : The number of hours to retain failed job data}'; /** * The name of the console command. @@ -36,10 +36,10 @@ class FlushFailedCommand extends Command */ public function handle() { - $this->laravel['queue.failer']->flush($this->option('age')); + $this->laravel['queue.failer']->flush($this->option('hours')); - if ($this->option('age')) { - $this->info("Failed jobs older than {$this->option('age')} days deleted successfully!"); + if ($this->option('hours')) { + $this->info("All jobs that failed more than {$this->option('hours')} hours ago have been deleted successfully!"); return; } diff --git a/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php b/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php index aece6f8c5bad..b6d847393441 100644 --- a/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php @@ -98,13 +98,13 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * - * @param int|null $age + * @param int|null $hours * @return void */ - public function flush($age = null) + public function flush($hours = null) { - $this->getTable()->when($age, function ($query, $age) { - $query->where('failed_at', '<=', Date::now()->subDays($age)); + $this->getTable()->when($hours, function ($query, $hours) { + $query->where('failed_at', '<=', Date::now()->subHours($hours)); })->delete(); } diff --git a/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php b/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php index 03356bcf1d1b..f4a1df26384c 100644 --- a/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php @@ -111,13 +111,13 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * - * @param int|null $age + * @param int|null $hours * @return void */ - public function flush($age = null) + public function flush($hours = null) { - $this->getTable()->when($age, function ($query, $age) { - $query->where('failed_at', '<=', Date::now()->subDays($age)); + $this->getTable()->when($hours, function ($query, $hours) { + $query->where('failed_at', '<=', Date::now()->subHours($hours)); })->delete(); } diff --git a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php index e97ba81772bb..2feeaa98a29f 100644 --- a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php @@ -165,12 +165,12 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * - * @param int|null $age + * @param int|null $hours * @return void * * @throws \Exception */ - public function flush($age = null) + public function flush($hours = null) { throw new Exception("DynamoDb failed job storage may not be flushed. Please use DynamoDb's TTL features on your expires_at attribute."); } diff --git a/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php b/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php index df4ae99c6672..26dd583b9496 100644 --- a/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php +++ b/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php @@ -41,8 +41,8 @@ public function forget($id); /** * Flush all of the failed jobs from storage. * - * @param int|null $age + * @param int|null $hours * @return void */ - public function flush($age = null); + public function flush($hours = null); } diff --git a/src/Illuminate/Queue/Failed/NullFailedJobProvider.php b/src/Illuminate/Queue/Failed/NullFailedJobProvider.php index 114406720a6c..22adb977ae11 100644 --- a/src/Illuminate/Queue/Failed/NullFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/NullFailedJobProvider.php @@ -53,10 +53,10 @@ public function forget($id) /** * Flush all of the failed jobs from storage. * - * @param int|null $age + * @param int|null $hours * @return void */ - public function flush($age = null) + public function flush($hours = null) { // } diff --git a/tests/Queue/DatabaseFailedJobProviderTest.php b/tests/Queue/DatabaseFailedJobProviderTest.php index 88b9f59dd7d5..67c491ce6655 100644 --- a/tests/Queue/DatabaseFailedJobProviderTest.php +++ b/tests/Queue/DatabaseFailedJobProviderTest.php @@ -32,11 +32,11 @@ public function testCanFlushFailedJobs() $this->assertSame(0, $db->getConnection()->table('failed_jobs')->count()); $db->getConnection()->table('failed_jobs')->insert(['failed_at' => Date::now()->subDays(10)]); - $provider->flush(15); + $provider->flush(15 * 24); $this->assertSame(1, $db->getConnection()->table('failed_jobs')->count()); $db->getConnection()->table('failed_jobs')->insert(['failed_at' => Date::now()->subDays(10)]); - $provider->flush(10); + $provider->flush(10 * 24); $this->assertSame(0, $db->getConnection()->table('failed_jobs')->count()); } } From 8b40e8b7cba2fbf8337dfc05e3c6a62ae457e889 Mon Sep 17 00:00:00 2001 From: Ben Holmen Date: Tue, 30 Mar 2021 08:54:00 -0500 Subject: [PATCH 112/194] [9.x] Add key support to FormRequest validated method (#36807) * Add key option to $request->validated() Co-authored-by: mattstauffer * Make FoundationFormRequestTest method names consistent Co-authored-by: mattstauffer --- .../Foundation/Http/FormRequest.php | 12 ++++++++-- .../Foundation/FoundationFormRequestTest.php | 22 ++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 8c2da9699600..e82bf967bb2b 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -188,10 +188,18 @@ protected function failedAuthorization() /** * Get the validated data from the request. * - * @return array + * @param string|null $key + * @param string|array|null $default + * @return mixed */ - public function validated() + public function validated($key = null, $default = null) { + if (! is_null($key)) { + return data_get( + $this->validator->validated(), $key, $default + ); + } + return $this->validator->validated(); } diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index d394566ce6cb..1d68e487235e 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -106,7 +106,7 @@ public function testPrepareForValidationRunsBeforeValidation() $this->createRequest([], FoundationTestFormRequestHooks::class)->validateResolved(); } - public function test_after_validation_runs_after_validation() + public function testAfterValidationRunsAfterValidation() { $request = $this->createRequest([], FoundationTestFormRequestHooks::class); @@ -115,6 +115,26 @@ public function test_after_validation_runs_after_validation() $this->assertEquals(['name' => 'Adam'], $request->all()); } + public function testValidatedMethodReturnsOnlyRequestedValidatedData() + { + $request = $this->createRequest(['name' => 'specified', 'with' => 'extras']); + + $request->validateResolved(); + + $this->assertEquals('specified', $request->validated('name')); + } + + public function testValidatedMethodReturnsOnlyRequestedNestedValidatedData() + { + $payload = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; + + $request = $this->createRequest($payload, FoundationTestFormRequestNestedStub::class); + + $request->validateResolved(); + + $this->assertEquals('bar', $request->validated('nested.foo')); + } + /** * Catch the given exception thrown from the executor, and return it. * From 6f41768363c193ed40c1e01773e05a594ee3956d Mon Sep 17 00:00:00 2001 From: Lars Grevelink Date: Thu, 1 Apr 2021 21:29:11 +0200 Subject: [PATCH 113/194] - Merge wrap differences into base grammar (#36510) - Move JSON related functions from query grammar to base grammar - Add JSON wrap functions to schema grammar - Add JSON support for MySQL and SQLite for virtualAs and storedAs columns --- src/Illuminate/Database/Grammar.php | 33 +++++++ .../Database/Query/Grammars/Grammar.php | 55 ------------ .../Database/Schema/Grammars/Grammar.php | 31 +++++++ .../Database/Schema/Grammars/MySqlGrammar.php | 29 +++++- .../Schema/Grammars/SQLiteGrammar.php | 29 +++++- .../DatabaseMySqlSchemaGrammarTest.php | 88 +++++++++++++++++++ .../DatabaseSQLiteSchemaGrammarTest.php | 66 ++++++++++++++ 7 files changed, 268 insertions(+), 63 deletions(-) diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index cc1e0b946940..ccea0916be2e 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -3,7 +3,9 @@ namespace Illuminate\Database; use Illuminate\Database\Query\Expression; +use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; +use RuntimeException; abstract class Grammar { @@ -62,6 +64,13 @@ public function wrap($value, $prefixAlias = false) return $this->wrapAliasedValue($value, $prefixAlias); } + // If the given value is a JSON selector we will wrap it differently than a + // traditional value. We will need to split this path and wrap each part + // wrapped, etc. Otherwise, we will simply wrap the value as a string. + if ($this->isJsonSelector($value)) { + return $this->wrapJsonSelector($value); + } + return $this->wrapSegments(explode('.', $value)); } @@ -116,6 +125,30 @@ protected function wrapValue($value) return $value; } + /** + * Wrap the given JSON selector. + * + * @param string $value + * @return string + * + * @throws \RuntimeException + */ + protected function wrapJsonSelector($value) + { + throw new RuntimeException('This database engine does not support JSON operations.'); + } + + /** + * Determine if the given string is a JSON selector. + * + * @param string $value + * @return bool + */ + protected function isJsonSelector($value) + { + return Str::contains($value, '->'); + } + /** * Convert an array of column names into a delimited string. * diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index b7305e8ea382..1e5c1b0b611d 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -6,7 +6,6 @@ use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Arr; -use Illuminate\Support\Str; use RuntimeException; class Grammar extends BaseGrammar @@ -1144,49 +1143,6 @@ public function compileSavepointRollBack($name) return 'ROLLBACK TO SAVEPOINT '.$name; } - /** - * Wrap a value in keyword identifiers. - * - * @param \Illuminate\Database\Query\Expression|string $value - * @param bool $prefixAlias - * @return string - */ - public function wrap($value, $prefixAlias = false) - { - if ($this->isExpression($value)) { - return $this->getValue($value); - } - - // If the value being wrapped has a column alias we will need to separate out - // the pieces so we can wrap each of the segments of the expression on its - // own, and then join these both back together using the "as" connector. - if (stripos($value, ' as ') !== false) { - return $this->wrapAliasedValue($value, $prefixAlias); - } - - // If the given value is a JSON selector we will wrap it differently than a - // traditional value. We will need to split this path and wrap each part - // wrapped, etc. Otherwise, we will simply wrap the value as a string. - if ($this->isJsonSelector($value)) { - return $this->wrapJsonSelector($value); - } - - return $this->wrapSegments(explode('.', $value)); - } - - /** - * Wrap the given JSON selector. - * - * @param string $value - * @return string - * - * @throws \RuntimeException - */ - protected function wrapJsonSelector($value) - { - throw new RuntimeException('This database engine does not support JSON operations.'); - } - /** * Wrap the given JSON selector for boolean values. * @@ -1240,17 +1196,6 @@ protected function wrapJsonPath($value, $delimiter = '->') return '\'$."'.str_replace($delimiter, '"."', $value).'"\''; } - /** - * Determine if the given string is a JSON selector. - * - * @param string $value - * @return bool - */ - protected function isJsonSelector($value) - { - return Str::contains($value, '->'); - } - /** * Concatenate an array of segments, removing empties. * diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index 18071b2fbb12..3d0111da726b 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -241,6 +241,37 @@ public function wrapTable($table) ); } + /** + * Split the given JSON selector into the field and the optional path and wrap them separately. + * + * @param string $column + * @return array + */ + protected function wrapJsonFieldAndPath($column) + { + $parts = explode('->', $column, 2); + + $field = $this->wrap($parts[0]); + + $path = count($parts) > 1 ? ', '.$this->wrapJsonPath($parts[1], '->') : ''; + + return [$field, $path]; + } + + /** + * Wrap the given JSON path. + * + * @param string $value + * @param string $delimiter + * @return string + */ + protected function wrapJsonPath($value, $delimiter = '->') + { + $value = preg_replace("/([\\\\]+)?\\'/", "''", $value); + + return '\'$."'.str_replace($delimiter, '"."', $value).'"\''; + } + /** * Wrap a value in keyword identifiers. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index c1a2c5586b54..09f363064150 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -920,8 +920,12 @@ protected function typeComputed(Fluent $column) */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($column->virtualAs)) { - return " as ({$column->virtualAs})"; + if (! is_null($virtualAs = $column->virtualAs)) { + if ($this->isJsonSelector($virtualAs)) { + $virtualAs = $this->wrapJsonSelector($virtualAs); + } + + return " as ({$virtualAs})"; } } @@ -934,8 +938,12 @@ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($column->storedAs)) { - return " as ({$column->storedAs}) stored"; + if (! is_null($storedAs = $column->storedAs)) { + if ($this->isJsonSelector($storedAs)) { + $storedAs = $this->wrapJsonSelector($storedAs); + } + + return " as ({$storedAs}) stored"; } } @@ -1097,4 +1105,17 @@ protected function wrapValue($value) return $value; } + + /** + * Wrap the given JSON selector. + * + * @param string $value + * @return string + */ + protected function wrapJsonSelector($value) + { + [$field, $path] = $this->wrapJsonFieldAndPath($value); + + return 'json_unquote(json_extract('.$field.$path.'))'; + } } diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 556d749e23b2..d0dc3dd45efa 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -846,8 +846,12 @@ protected function typeComputed(Fluent $column) */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($column->virtualAs)) { - return " as ({$column->virtualAs})"; + if (! is_null($virtualAs = $column->virtualAs)) { + if ($this->isJsonSelector($virtualAs)) { + $virtualAs = $this->wrapJsonSelector($virtualAs); + } + + return " as ({$virtualAs})"; } } @@ -860,8 +864,12 @@ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($column->storedAs)) { - return " as ({$column->storedAs}) stored"; + if (! is_null($storedAs = $column->storedAs)) { + if ($this->isJsonSelector($storedAs)) { + $storedAs = $this->wrapJsonSelector($storedAs); + } + + return " as ({$storedAs}) stored"; } } @@ -910,4 +918,17 @@ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) return ' primary key autoincrement'; } } + + /** + * Wrap the given JSON selector. + * + * @param string $value + * @return string + */ + protected function wrapJsonSelector($value) + { + [$field, $path] = $this->wrapJsonFieldAndPath($value); + + return 'json_extract('.$field.$path.')'; + } } diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 1ea53f991d16..4b1188faf415 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1197,6 +1197,94 @@ public function testCreateDatabase() ); } + public function testCreateTableWithVirtualAsColumn() + { + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); + $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); + $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_column'); + $blueprint->string('my_other_column')->virtualAs('my_column'); + + $statements = $blueprint->toSql($conn, $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame("create table `users` (`my_column` varchar(255) not null, `my_other_column` varchar(255) as (my_column)) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute'); + + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $statements = $blueprint->toSql($conn, $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame("create table `users` (`my_json_column` varchar(255) not null, `my_other_column` varchar(255) as (json_unquote(json_extract(`my_json_column`, '$.\"some_attribute\"'))))", $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute->nested'); + + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $statements = $blueprint->toSql($conn, $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame("create table `users` (`my_json_column` varchar(255) not null, `my_other_column` varchar(255) as (json_unquote(json_extract(`my_json_column`, '$.\"some_attribute\".\"nested\"'))))", $statements[0]); + } + + public function testCreateTableWithStoredAsColumn() + { + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); + $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); + $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_column'); + $blueprint->string('my_other_column')->storedAs('my_column'); + + $statements = $blueprint->toSql($conn, $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame("create table `users` (`my_column` varchar(255) not null, `my_other_column` varchar(255) as (my_column) stored) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute'); + + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $statements = $blueprint->toSql($conn, $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame("create table `users` (`my_json_column` varchar(255) not null, `my_other_column` varchar(255) as (json_unquote(json_extract(`my_json_column`, '$.\"some_attribute\"'))) stored)", $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute->nested'); + + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $statements = $blueprint->toSql($conn, $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame("create table `users` (`my_json_column` varchar(255) not null, `my_other_column` varchar(255) as (json_unquote(json_extract(`my_json_column`, '$.\"some_attribute\".\"nested\"'))) stored)", $statements[0]); + } + public function testDropDatabaseIfExists() { $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index e77e21578cbe..4b143d9f8891 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -899,6 +899,72 @@ public function testGrammarsAreMacroable() $this->assertTrue($c); } + public function testCreateTableWithVirtualAsColumn() + { + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_column'); + $blueprint->string('my_other_column')->virtualAs('my_column'); + + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('create table "users" ("my_column" varchar not null, "my_other_column" varchar as (my_column))', $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute'); + + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('create table "users" ("my_json_column" varchar not null, "my_other_column" varchar as (json_extract("my_json_column", \'$."some_attribute"\')))', $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute->nested'); + + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('create table "users" ("my_json_column" varchar not null, "my_other_column" varchar as (json_extract("my_json_column", \'$."some_attribute"."nested"\')))', $statements[0]); + } + + public function testCreateTableWithStoredAsColumn() + { + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_column'); + $blueprint->string('my_other_column')->storedAs('my_column'); + + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('create table "users" ("my_column" varchar not null, "my_other_column" varchar as (my_column) stored)', $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute'); + + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('create table "users" ("my_json_column" varchar not null, "my_other_column" varchar as (json_extract("my_json_column", \'$."some_attribute"\')) stored)', $statements[0]); + + $blueprint = new Blueprint('users'); + $blueprint->create(); + $blueprint->string('my_json_column'); + $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute->nested'); + + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertSame('create table "users" ("my_json_column" varchar not null, "my_other_column" varchar as (json_extract("my_json_column", \'$."some_attribute"."nested"\')) stored)', $statements[0]); + } + protected function getConnection() { return m::mock(Connection::class); From c61c8624b988595e24beafd418ef84447893709e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 1 Apr 2021 14:39:34 -0500 Subject: [PATCH 114/194] formatting --- .../Database/Schema/Grammars/MySqlGrammar.php | 17 ++++++++++++++--- .../Schema/Grammars/SQLiteGrammar.php | 19 +++++++++++++++---- .../DatabaseMySqlSchemaGrammarTest.php | 8 ++++---- .../DatabaseSQLiteSchemaGrammarTest.php | 8 ++++---- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 09f363064150..299fc0e35eba 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -920,13 +920,17 @@ protected function typeComputed(Fluent $column) */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($virtualAs = $column->virtualAs)) { + if (! is_null($virtualAs = $column->virtualAsJson)) { if ($this->isJsonSelector($virtualAs)) { $virtualAs = $this->wrapJsonSelector($virtualAs); } return " as ({$virtualAs})"; } + + if (! is_null($virtualAs = $column->virtualAs)) { + return " as ({$virtualAs})"; + } } /** @@ -938,13 +942,17 @@ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($storedAs = $column->storedAs)) { + if (! is_null($storedAs = $column->storedAsJson)) { if ($this->isJsonSelector($storedAs)) { $storedAs = $this->wrapJsonSelector($storedAs); } return " as ({$storedAs}) stored"; } + + if (! is_null($storedAs = $column->storedAs)) { + return " as ({$storedAs}) stored"; + } } /** @@ -998,7 +1006,10 @@ protected function modifyCollate(Blueprint $blueprint, Fluent $column) */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { - if (is_null($column->virtualAs) && is_null($column->storedAs)) { + if (is_null($column->virtualAs) && + is_null($column->virtualAsJson) && + is_null($column->storedAs) && + is_null($column->storedAsJson)) { return $column->nullable ? ' null' : ' not null'; } diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index d0dc3dd45efa..865d53d8e4c8 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -846,13 +846,17 @@ protected function typeComputed(Fluent $column) */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($virtualAs = $column->virtualAs)) { + if (! is_null($virtualAs = $column->virtualAsJson)) { if ($this->isJsonSelector($virtualAs)) { $virtualAs = $this->wrapJsonSelector($virtualAs); } return " as ({$virtualAs})"; } + + if (! is_null($virtualAs = $column->virtualAs)) { + return " as ({$virtualAs})"; + } } /** @@ -864,13 +868,17 @@ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { - if (! is_null($storedAs = $column->storedAs)) { + if (! is_null($storedAs = $column->storedAsJson)) { if ($this->isJsonSelector($storedAs)) { $storedAs = $this->wrapJsonSelector($storedAs); } return " as ({$storedAs}) stored"; } + + if (! is_null($storedAs = $column->storedAs)) { + return " as ({$column->storedAs}) stored"; + } } /** @@ -882,7 +890,10 @@ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { - if (is_null($column->virtualAs) && is_null($column->storedAs)) { + if (is_null($column->virtualAs) && + is_null($column->virtualAsJson) && + is_null($column->storedAs) && + is_null($column->storedAsJson)) { return $column->nullable ? '' : ' not null'; } @@ -900,7 +911,7 @@ protected function modifyNullable(Blueprint $blueprint, Fluent $column) */ protected function modifyDefault(Blueprint $blueprint, Fluent $column) { - if (! is_null($column->default) && is_null($column->virtualAs) && is_null($column->storedAs)) { + if (! is_null($column->default) && is_null($column->virtualAs) && is_null($column->virtualAsJson) && is_null($column->storedAs)) { return ' default '.$this->getDefaultValue($column->default); } } diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 4b1188faf415..51d955bba577 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1217,7 +1217,7 @@ public function testCreateTableWithVirtualAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute'); + $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute'); $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); @@ -1230,7 +1230,7 @@ public function testCreateTableWithVirtualAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute->nested'); + $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute->nested'); $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); @@ -1261,7 +1261,7 @@ public function testCreateTableWithStoredAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute'); + $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute'); $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); @@ -1274,7 +1274,7 @@ public function testCreateTableWithStoredAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute->nested'); + $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute->nested'); $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index 4b143d9f8891..1b9ca140101a 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -914,7 +914,7 @@ public function testCreateTableWithVirtualAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute'); + $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); @@ -924,7 +924,7 @@ public function testCreateTableWithVirtualAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->virtualAs('my_json_column->some_attribute->nested'); + $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute->nested'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); @@ -947,7 +947,7 @@ public function testCreateTableWithStoredAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute'); + $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); @@ -957,7 +957,7 @@ public function testCreateTableWithStoredAsColumn() $blueprint = new Blueprint('users'); $blueprint->create(); $blueprint->string('my_json_column'); - $blueprint->string('my_other_column')->storedAs('my_json_column->some_attribute->nested'); + $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute->nested'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); From f7cd47a6f3f57f5c19a1a6be9c6c3a17591d8c19 Mon Sep 17 00:00:00 2001 From: Markus Hebenstreit Date: Sun, 11 Apr 2021 18:14:45 +0200 Subject: [PATCH 115/194] [9.x] Iterable value type for whereBetween (#36933) * Added CarbonPeriod value type to Query\Builder->whereBetween * Removed CarbonPeriod typehint and replaced it with native iterable type --- src/Illuminate/Database/Query/Builder.php | 16 ++++++++-------- tests/Database/DatabaseQueryBuilderTest.php | 11 +++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 710d0a3a568c..5cacbbd6a021 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1110,12 +1110,12 @@ public function whereNotNull($columns, $boolean = 'and') * Add a where between statement to the query. * * @param string|\Illuminate\Database\Query\Expression $column - * @param array $values + * @param iterable $values * @param string $boolean * @param bool $not * @return $this */ - public function whereBetween($column, array $values, $boolean = 'and', $not = false) + public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) { $type = 'between'; @@ -1148,10 +1148,10 @@ public function whereBetweenColumns($column, array $values, $boolean = 'and', $n * Add an or where between statement to the query. * * @param string $column - * @param array $values + * @param iterable $values * @return $this */ - public function orWhereBetween($column, array $values) + public function orWhereBetween($column, iterable $values) { return $this->whereBetween($column, $values, 'or'); } @@ -1172,11 +1172,11 @@ public function orWhereBetweenColumns($column, array $values) * Add a where not between statement to the query. * * @param string $column - * @param array $values + * @param iterable $values * @param string $boolean * @return $this */ - public function whereNotBetween($column, array $values, $boolean = 'and') + public function whereNotBetween($column, iterable $values, $boolean = 'and') { return $this->whereBetween($column, $values, $boolean, true); } @@ -1198,10 +1198,10 @@ public function whereNotBetweenColumns($column, array $values, $boolean = 'and') * Add an or where not between statement to the query. * * @param string $column - * @param array $values + * @param iterable $values * @return $this */ - public function orWhereNotBetween($column, array $values) + public function orWhereNotBetween($column, iterable $values) { return $this->whereNotBetween($column, $values, 'or'); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 0fed6c3a1ba9..8da545ccdbf3 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -673,6 +673,17 @@ public function testWhereBetweens() $builder->select('*')->from('users')->whereBetween('id', [new Raw(1), new Raw(2)]); $this->assertSame('select * from "users" where "id" between 1 and 2', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); + + $builder = $this->getBuilder(); + $period = now()->toPeriod(now()->addDay()); + $builder->select('*')->from('users')->whereBetween('created_at', $period); + $this->assertSame('select * from "users" where "created_at" between ? and ?', $builder->toSql()); + $this->assertEquals($period->toArray(), $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereBetween('id', collect([1, 2])); + $this->assertSame('select * from "users" where "id" between ? and ?', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); } public function testWhereBetweenColumns() From 8bdd75bc8241422ab616a848bd2d6f8ed01440e4 Mon Sep 17 00:00:00 2001 From: Oliver Matla Date: Mon, 12 Apr 2021 17:49:25 +0200 Subject: [PATCH 116/194] [9.x] allow for named global class scopes (#36934) --- .../Database/Eloquent/Concerns/HasGlobalScopes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasGlobalScopes.php b/src/Illuminate/Database/Eloquent/Concerns/HasGlobalScopes.php index 1742679c5a30..72afb178897b 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasGlobalScopes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasGlobalScopes.php @@ -13,14 +13,14 @@ trait HasGlobalScopes * Register a new global scope on the model. * * @param \Illuminate\Database\Eloquent\Scope|\Closure|string $scope - * @param \Closure|null $implementation + * @param \Illuminate\Database\Eloquent\Scope|\Closure|null $implementation * @return mixed * * @throws \InvalidArgumentException */ - public static function addGlobalScope($scope, Closure $implementation = null) + public static function addGlobalScope($scope, $implementation = null) { - if (is_string($scope) && ! is_null($implementation)) { + if (is_string($scope) && ($implementation instanceof Closure || $implementation instanceof Scope)) { return static::$globalScopes[static::class][$scope] = $implementation; } elseif ($scope instanceof Closure) { return static::$globalScopes[static::class][spl_object_hash($scope)] = $scope; From eb17d56582b2e8c4dfe24e6f447632242dc3f4de Mon Sep 17 00:00:00 2001 From: Harish Toshniwal Date: Tue, 13 Apr 2021 20:32:15 +0530 Subject: [PATCH 117/194] allow passing an array of params to ignore in original while validating route signature --- src/Illuminate/Routing/UrlGenerator.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index e8e09bd5686c..5af86d6d46e3 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -358,11 +358,12 @@ public function temporarySignedRoute($name, $expiration, $parameters = [], $abso * * @param \Illuminate\Http\Request $request * @param bool $absolute + * @param array $paramsToIgnoreInOriginal * @return bool */ - public function hasValidSignature(Request $request, $absolute = true) + public function hasValidSignature(Request $request, $absolute = true, array $paramsToIgnoreInOriginal = ['signature']) { - return $this->hasCorrectSignature($request, $absolute) + return $this->hasCorrectSignature($request, $absolute, $paramsToIgnoreInOriginal) && $this->signatureHasNotExpired($request); } @@ -370,11 +371,12 @@ public function hasValidSignature(Request $request, $absolute = true) * Determine if the given request has a valid signature for a relative URL. * * @param \Illuminate\Http\Request $request + * @param array $paramsToIgnoreInOriginal * @return bool */ - public function hasValidRelativeSignature(Request $request) + public function hasValidRelativeSignature(Request $request, array $paramsToIgnoreInOriginal = ['signature']) { - return $this->hasValidSignature($request, false); + return $this->hasValidSignature($request, false, $paramsToIgnoreInOriginal); } /** @@ -382,14 +384,15 @@ public function hasValidRelativeSignature(Request $request) * * @param \Illuminate\Http\Request $request * @param bool $absolute + * @param array $paramsToIgnoreInOriginal * @return bool */ - public function hasCorrectSignature(Request $request, $absolute = true) + public function hasCorrectSignature(Request $request, $absolute = true, array $paramsToIgnoreInOriginal) { - $url = $absolute ? $request->url() : '/'.$request->path(); + $url = $absolute ? $request->url() : '/' . $request->path(); - $original = rtrim($url.'?'.Arr::query( - Arr::except($request->query(), 'signature') + $original = rtrim($url . '?' . Arr::query( + Arr::except($request->query(), $paramsToIgnoreInOriginal) ), '?'); $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver)); From 7994795a89001505fa29199d0371d668b9fb9da7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 14 Apr 2021 06:57:34 -0500 Subject: [PATCH 118/194] formatting --- src/Illuminate/Routing/UrlGenerator.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 5af86d6d46e3..c9db79b5ee75 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -358,12 +358,12 @@ public function temporarySignedRoute($name, $expiration, $parameters = [], $abso * * @param \Illuminate\Http\Request $request * @param bool $absolute - * @param array $paramsToIgnoreInOriginal + * @param array $ignoreQuery * @return bool */ - public function hasValidSignature(Request $request, $absolute = true, array $paramsToIgnoreInOriginal = ['signature']) + public function hasValidSignature(Request $request, $absolute = true, array $ignoreQuery = []) { - return $this->hasCorrectSignature($request, $absolute, $paramsToIgnoreInOriginal) + return $this->hasCorrectSignature($request, $absolute, $ignoreQuery) && $this->signatureHasNotExpired($request); } @@ -371,12 +371,12 @@ public function hasValidSignature(Request $request, $absolute = true, array $par * Determine if the given request has a valid signature for a relative URL. * * @param \Illuminate\Http\Request $request - * @param array $paramsToIgnoreInOriginal + * @param array $ignoreQuery * @return bool */ - public function hasValidRelativeSignature(Request $request, array $paramsToIgnoreInOriginal = ['signature']) + public function hasValidRelativeSignature(Request $request, array $ignoreQuery = []) { - return $this->hasValidSignature($request, false, $paramsToIgnoreInOriginal); + return $this->hasValidSignature($request, false, $ignoreQuery); } /** @@ -384,15 +384,17 @@ public function hasValidRelativeSignature(Request $request, array $paramsToIgnor * * @param \Illuminate\Http\Request $request * @param bool $absolute - * @param array $paramsToIgnoreInOriginal + * @param array $ignoreQuery * @return bool */ - public function hasCorrectSignature(Request $request, $absolute = true, array $paramsToIgnoreInOriginal) + public function hasCorrectSignature(Request $request, $absolute = true, array $ignoreQuery = []) { + $ignoreQuery[] = 'signature'; + $url = $absolute ? $request->url() : '/' . $request->path(); - $original = rtrim($url . '?' . Arr::query( - Arr::except($request->query(), $paramsToIgnoreInOriginal) + $original = rtrim($url.'?'.Arr::query( + Arr::except($request->query(), $ignoreQuery) ), '?'); $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver)); From 8f31b6407b5b4bf4082984a8f88db4da19451c7e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 14 Apr 2021 06:58:10 -0500 Subject: [PATCH 119/194] Apply fixes from StyleCI (#36983) --- src/Illuminate/Routing/UrlGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index c9db79b5ee75..9a2522ddbb1e 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -391,7 +391,7 @@ public function hasCorrectSignature(Request $request, $absolute = true, array $i { $ignoreQuery[] = 'signature'; - $url = $absolute ? $request->url() : '/' . $request->path(); + $url = $absolute ? $request->url() : '/'.$request->path(); $original = rtrim($url.'?'.Arr::query( Arr::except($request->query(), $ignoreQuery) From 6e134212e8b327eb76b00f644a233f328d039838 Mon Sep 17 00:00:00 2001 From: netpok Date: Thu, 15 Apr 2021 13:57:29 +0200 Subject: [PATCH 120/194] [9.x] Update Container\Util::unwrapIfClosure to match value helper (#36995) * Match Util::unwrapIfClosure to value helper * Use helper when applicable --- src/Illuminate/Container/Container.php | 2 +- src/Illuminate/Container/Util.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 642d1e082e6d..b64c27a2b8ec 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -961,7 +961,7 @@ protected function getLastParameterOverride() protected function resolvePrimitive(ReflectionParameter $parameter) { if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->getName()))) { - return $concrete instanceof Closure ? $concrete($this) : $concrete; + return Util::unwrapIfClosure($concrete, $this); } if ($parameter->isDefaultValueAvailable()) { diff --git a/src/Illuminate/Container/Util.php b/src/Illuminate/Container/Util.php index 8180a45a5798..fa09f538d00c 100644 --- a/src/Illuminate/Container/Util.php +++ b/src/Illuminate/Container/Util.php @@ -33,11 +33,12 @@ public static function arrayWrap($value) * From global value() helper in Illuminate\Support. * * @param mixed $value + * @param mixed ...$args * @return mixed */ - public static function unwrapIfClosure($value) + public static function unwrapIfClosure($value, ...$args) { - return $value instanceof Closure ? $value() : $value; + return $value instanceof Closure ? $value(...$args) : $value; } /** From e769e3d2d37f2cd3e812441da4744e60fdd6b5bd Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Wed, 21 Apr 2021 14:12:57 +0100 Subject: [PATCH 121/194] [9.x] Add sole() to Enumerable contract. (#37066) * Added sole() to Enumerable contract. * Update Enumerable.php Co-authored-by: Taylor Otwell --- src/Illuminate/Collections/Enumerable.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 4bda35476905..29b123d53525 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -808,6 +808,19 @@ public function slice($offset, $length = null); */ public function split($numberOfGroups); + /** + * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. + * + * @param mixed $key + * @param mixed $operator + * @param mixed $value + * @return mixed + * + * @throws \Illuminate\Collections\ItemNotFoundException + * @throws \Illuminate\Collections\MultipleItemsFoundException + */ + public function sole($key = null, $operator = null, $value = null); + /** * Chunk the collection into chunks of the given size. * From accf9db3830a979c3c0e3dfdd0a5834f08c1d97e Mon Sep 17 00:00:00 2001 From: amir Date: Mon, 3 May 2021 17:02:15 +0400 Subject: [PATCH 122/194] Implement having null (#37228) --- src/Illuminate/Database/Query/Builder.php | 53 ++++++++++++++ .../Database/Query/Grammars/Grammar.php | 30 ++++++++ tests/Database/DatabaseQueryBuilderTest.php | 70 +++++++++++++++++++ 3 files changed, 153 insertions(+) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 43c59bdf717d..7167766026aa 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1898,6 +1898,59 @@ public function orHaving($column, $operator = null, $value = null) return $this->having($column, $operator, $value, 'or'); } + /** + * Add a "having null" clause to the query. + * + * @param string|array $columns + * @param string $boolean + * @param bool $not + * @return $this + */ + public function havingNull($columns, $boolean = 'and', $not = false) + { + $type = $not ? 'NotNull' : 'Null'; + + foreach (Arr::wrap($columns) as $column) { + $this->havings[] = compact('type', 'column', 'boolean'); + } + + return $this; + } + + /** + * Add an "or having null" clause to the query. + * + * @param string $column + * @return $this + */ + public function orHavingNull($column) + { + return $this->havingNull($column, 'or'); + } + + /** + * Add a "having not null" clause to the query. + * + * @param string|array $columns + * @param string $boolean + * @return $this + */ + public function havingNotNull($columns, $boolean = 'and') + { + return $this->havingNull($columns, $boolean, true); + } + + /** + * Add an "or having not null" clause to the query. + * + * @param string $column + * @return $this + */ + public function orHavingNotNull($column) + { + return $this->havingNotNull($column, 'or'); + } + /** * Add a "having between " clause to the query. * diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 1e5c1b0b611d..4fa5dac03c17 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -669,6 +669,10 @@ protected function compileHaving(array $having) return $having['boolean'].' '.$having['sql']; } elseif ($having['type'] === 'between') { return $this->compileHavingBetween($having); + } elseif ($having['type'] === 'Null') { + return $this->compileHavingNull($having); + } elseif ($having['type'] === 'NotNull') { + return $this->compileHavingNotNull($having); } return $this->compileBasicHaving($having); @@ -708,6 +712,32 @@ protected function compileHavingBetween($having) return $having['boolean'].' '.$column.' '.$between.' '.$min.' and '.$max; } + /** + * Compile a having null clause. + * + * @param array $having + * @return string + */ + protected function compileHavingNull($having) + { + $column = $this->wrap($having['column']); + + return $having['boolean'].' '.$column.' is null'; + } + + /** + * Compile a having not null clause. + * + * @param array $having + * @return string + */ + protected function compileHavingNotNull($having) + { + $column = $this->wrap($having['column']); + + return $having['boolean'].' '.$column.' is not null'; + } + /** * Compile the "order by" portions of the query. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index ebedd88e951b..131b4ba15bcc 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -1285,6 +1285,76 @@ public function testHavingBetweens() $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); } + public function testHavingNull() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->havingNull('email'); + $this->assertSame('select * from "users" having "email" is null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users') + ->havingNull('email') + ->havingNull('phone'); + $this->assertSame('select * from "users" having "email" is null and "phone" is null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users') + ->orHavingNull('email') + ->orHavingNull('phone'); + $this->assertSame('select * from "users" having "email" is null or "phone" is null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->groupBy('email')->havingNull('email'); + $this->assertSame('select * from "users" group by "email" having "email" is null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('email as foo_email')->from('users')->havingNull('foo_email'); + $this->assertSame('select "email" as "foo_email" from "users" having "foo_email" is null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select(['category', new Raw('count(*) as "total"')])->from('item')->where('department', '=', 'popular')->groupBy('category')->havingNull('total'); + $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" is null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select(['category', new Raw('count(*) as "total"')])->from('item')->where('department', '=', 'popular')->groupBy('category')->havingNull('total'); + $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" is null', $builder->toSql()); + } + + public function testHavingNotNull() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->havingNotNull('email'); + $this->assertSame('select * from "users" having "email" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users') + ->havingNotNull('email') + ->havingNotNull('phone'); + $this->assertSame('select * from "users" having "email" is not null and "phone" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users') + ->orHavingNotNull('email') + ->orHavingNotNull('phone'); + $this->assertSame('select * from "users" having "email" is not null or "phone" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->groupBy('email')->havingNotNull('email'); + $this->assertSame('select * from "users" group by "email" having "email" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('email as foo_email')->from('users')->havingNotNull('foo_email'); + $this->assertSame('select "email" as "foo_email" from "users" having "foo_email" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select(['category', new Raw('count(*) as "total"')])->from('item')->where('department', '=', 'popular')->groupBy('category')->havingNotNull('total'); + $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select(['category', new Raw('count(*) as "total"')])->from('item')->where('department', '=', 'popular')->groupBy('category')->havingNotNull('total'); + $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" is not null', $builder->toSql()); + } + public function testHavingShortcut() { $builder = $this->getBuilder(); From bc54ad97f379329137145c575d95725bc8a3886c Mon Sep 17 00:00:00 2001 From: Kai Sassnowski Date: Mon, 10 May 2021 16:00:41 +0200 Subject: [PATCH 123/194] Add option to ignore case in `Str::contains` and `Str::containsAll` (#37330) --- src/Illuminate/Support/Str.php | 16 ++++++++-- tests/Support/SupportStrTest.php | 53 ++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index d023a446b74e..7a8cc8b4460c 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -176,10 +176,16 @@ public static function camel($value) * * @param string $haystack * @param string|string[] $needles + * @param bool $ignoreCase * @return bool */ - public static function contains($haystack, $needles) + public static function contains($haystack, $needles, $ignoreCase = false) { + if ($ignoreCase) { + $haystack = mb_strtolower($haystack); + $needles = array_map('mb_strtolower', (array) $needles); + } + foreach ((array) $needles as $needle) { if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { return true; @@ -194,10 +200,16 @@ public static function contains($haystack, $needles) * * @param string $haystack * @param string[] $needles + * @param bool $ignoreCase * @return bool */ - public static function containsAll($haystack, array $needles) + public static function containsAll($haystack, array $needles, $ignoreCase = false) { + if ($ignoreCase) { + $haystack = mb_strtolower($haystack); + $needles = array_map('mb_strtolower', $needles); + } + foreach ($needles as $needle) { if (! static::contains($haystack, $needle)) { return false; diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 8443437ce578..234119370b22 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -184,23 +184,20 @@ public function testStrAfterLast() $this->assertSame('foo', Str::afterLast('----foo', '---')); } - public function testStrContains() + /** + * @dataProvider strContainsProvider + */ + public function testStrContains($haystack, $needles, $expected, $ignoreCase = false) { - $this->assertTrue(Str::contains('taylor', 'ylo')); - $this->assertTrue(Str::contains('taylor', 'taylor')); - $this->assertTrue(Str::contains('taylor', ['ylo'])); - $this->assertTrue(Str::contains('taylor', ['xxx', 'ylo'])); - $this->assertFalse(Str::contains('taylor', 'xxx')); - $this->assertFalse(Str::contains('taylor', ['xxx'])); - $this->assertFalse(Str::contains('taylor', '')); - $this->assertFalse(Str::contains('', '')); + $this->assertEquals($expected, Str::contains($haystack, $needles, $ignoreCase)); } - public function testStrContainsAll() + /** + * @dataProvider strContainsAllProvider + */ + public function testStrContainsAll($haystack, $needles, $expected, $ignoreCase = false) { - $this->assertTrue(Str::containsAll('taylor otwell', ['taylor', 'otwell'])); - $this->assertTrue(Str::containsAll('taylor otwell', ['taylor'])); - $this->assertFalse(Str::containsAll('taylor otwell', ['taylor', 'xxx'])); + $this->assertEquals($expected, Str::containsAll($haystack, $needles, $ignoreCase)); } public function testParseCallback() @@ -553,6 +550,36 @@ public function invalidUuidList() ]; } + public function strContainsProvider() + { + return [ + ['Taylor', 'ylo', true, true], + ['Taylor', 'ylo', true, false], + ['Taylor', 'taylor', true, true], + ['Taylor', 'taylor', false, false], + ['Taylor', ['ylo'], true, true], + ['Taylor', ['ylo'], true, false], + ['Taylor', ['xxx', 'ylo'], true, true], + ['Taylor', ['xxx', 'ylo'], true, false], + ['Taylor', 'xxx', false], + ['Taylor', ['xxx'], false], + ['Taylor', '', false], + ['', '', false], + ]; + } + + public function strContainsAllProvider() + { + return [ + ['Taylor Otwell', ['taylor', 'otwell'], false, false], + ['Taylor Otwell', ['taylor', 'otwell'], true, true], + ['Taylor Otwell', ['taylor'], false, false], + ['Taylor Otwell', ['taylor'], true, true], + ['Taylor Otwell', ['taylor', 'xxx'], false, false], + ['Taylor Otwell', ['taylor', 'xxx'], false, true], + ]; + } + public function testMarkdown() { $this->assertSame("

hello world

\n", Str::markdown('*hello world*')); From d923676eeed5f08464ce7306d6fcb29e7ad4f13b Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Wed, 12 May 2021 14:37:19 +0200 Subject: [PATCH 124/194] Fix the return type on the password broker factory (#37355) --- src/Illuminate/Contracts/Auth/PasswordBrokerFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Contracts/Auth/PasswordBrokerFactory.php b/src/Illuminate/Contracts/Auth/PasswordBrokerFactory.php index 47b1c089687e..683a90308b84 100644 --- a/src/Illuminate/Contracts/Auth/PasswordBrokerFactory.php +++ b/src/Illuminate/Contracts/Auth/PasswordBrokerFactory.php @@ -8,7 +8,7 @@ interface PasswordBrokerFactory * Get a password broker instance by name. * * @param string|null $name - * @return mixed + * @return \Illuminate\Contracts\Auth\PasswordBroker */ public function broker($name = null); } From e0ae5fc256d003d427bae61366314a49796561c0 Mon Sep 17 00:00:00 2001 From: Lloric Mayuga Garcia Date: Wed, 12 May 2021 20:37:48 +0800 Subject: [PATCH 125/194] [9.x] Set anonymous migration (#37352) * Set anonymous migration * Set anonymous migration * Set anonymous migration --- .../Database/Migrations/stubs/migration.create.stub | 4 ++-- src/Illuminate/Database/Migrations/stubs/migration.stub | 4 ++-- .../Database/Migrations/stubs/migration.update.stub | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Migrations/stubs/migration.create.stub b/src/Illuminate/Database/Migrations/stubs/migration.create.stub index f4a56a0774dd..0e0ec22b85ce 100755 --- a/src/Illuminate/Database/Migrations/stubs/migration.create.stub +++ b/src/Illuminate/Database/Migrations/stubs/migration.create.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class {{ class }} extends Migration +return new class extends Migration { /** * Run the migrations. @@ -28,4 +28,4 @@ class {{ class }} extends Migration { Schema::dropIfExists('{{ table }}'); } -} +}; diff --git a/src/Illuminate/Database/Migrations/stubs/migration.stub b/src/Illuminate/Database/Migrations/stubs/migration.stub index fd0e4378566d..41dd1c8e6af9 100755 --- a/src/Illuminate/Database/Migrations/stubs/migration.stub +++ b/src/Illuminate/Database/Migrations/stubs/migration.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class {{ class }} extends Migration +return new class extends Migration { /** * Run the migrations. @@ -25,4 +25,4 @@ class {{ class }} extends Migration { // } -} +}; diff --git a/src/Illuminate/Database/Migrations/stubs/migration.update.stub b/src/Illuminate/Database/Migrations/stubs/migration.update.stub index f1a04ebe54d7..d31a2c022b5a 100755 --- a/src/Illuminate/Database/Migrations/stubs/migration.update.stub +++ b/src/Illuminate/Database/Migrations/stubs/migration.update.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class {{ class }} extends Migration +return new class extends Migration { /** * Run the migrations. @@ -29,4 +29,4 @@ class {{ class }} extends Migration // }); } -} +}; From 699abd0d283db7d7f8c0885e19dea08d365307f2 Mon Sep 17 00:00:00 2001 From: Timothy Winters Date: Wed, 12 May 2021 08:47:31 -0500 Subject: [PATCH 126/194] Consistent BelongsToMany#firstOrCreate behaviour (#37337) --- .../Eloquent/Relations/BelongsToMany.php | 5 ++-- .../Database/EloquentBelongsToManyTest.php | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 13e02fae7f9f..195b000082af 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -609,14 +609,15 @@ public function firstOrNew(array $attributes) * Get the first related record matching the attributes or create it. * * @param array $attributes + * @param array $values * @param array $joining * @param bool $touch * @return \Illuminate\Database\Eloquent\Model */ - public function firstOrCreate(array $attributes, array $joining = [], $touch = true) + public function firstOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true) { if (is_null($instance = $this->related->where($attributes)->first())) { - $instance = $this->create($attributes, $joining, $touch); + $instance = $this->create($attributes + $values, $joining, $touch); } return $instance; diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index a7c042cca864..9710953a7c9c 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -439,6 +439,30 @@ public function testFirstOrCreateMethod() $this->assertNotNull($new->id); } + public function testFirstOrCreateMethodWithValues() + { + $post = Post::create(['title' => Str::random()]); + $tag = Tag::create(['name' => Str::random()]); + $post->tags()->attach(Tag::all()); + + $existing = $post->tags()->firstOrCreate( + ['name' => $tag->name], + ['type' => 'featured'] + ); + + $this->assertEquals($tag->id, $existing->id); + $this->assertNotEquals('foo', $existing->name); + + $new = $post->tags()->firstOrCreate( + ['name' => 'foo'], + ['type' => 'featured'] + ); + + $this->assertSame('foo', $new->name); + $this->assertSame('featured', $new->type); + $this->assertNotNull($new->id); + } + public function testUpdateOrCreateMethod() { $post = Post::create(['title' => Str::random()]); From 4590d55bff1e8b5888794860fb18591adde3713c Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Wed, 19 May 2021 14:32:05 +0200 Subject: [PATCH 127/194] Replace Whoops interface with generic ExceptionRenderer interface --- composer.json | 1 - .../Foundation/ExceptionRenderer.php | 15 ++++ .../Foundation/Exceptions/Handler.php | 33 ++----- .../Foundation/Exceptions/WhoopsHandler.php | 86 ------------------- 4 files changed, 21 insertions(+), 114 deletions(-) create mode 100644 src/Illuminate/Contracts/Foundation/ExceptionRenderer.php delete mode 100644 src/Illuminate/Foundation/Exceptions/WhoopsHandler.php diff --git a/composer.json b/composer.json index 3cb5fe8592e0..cfa9eec49273 100644 --- a/composer.json +++ b/composer.json @@ -81,7 +81,6 @@ "aws/aws-sdk-php": "^3.155", "doctrine/dbal": "^2.12|^3.0", "fakerphp/faker": "^1.9.2", - "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^7.2", "league/flysystem-aws-s3-v3": "^2.0", "league/flysystem-ftp": "^2.0", diff --git a/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php b/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php new file mode 100644 index 000000000000..92d56f4a0ab1 --- /dev/null +++ b/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php @@ -0,0 +1,15 @@ +renderExceptionWithWhoops($e) + return config('app.debug') && app()->has(ExceptionRenderer::class) + ? $this->renderExceptionWithCustomRenderer($e) : $this->renderExceptionWithSymfony($e, config('app.debug')); } catch (Exception $e) { return $this->renderExceptionWithSymfony($e, config('app.debug')); @@ -508,34 +507,14 @@ protected function renderExceptionContent(Throwable $e) } /** - * Render an exception to a string using "Whoops". + * Render an exception to a string using the registered `ExceptionRenderer`. * * @param \Throwable $e * @return string */ - protected function renderExceptionWithWhoops(Throwable $e) + protected function renderExceptionWithCustomRenderer(Throwable $e) { - return tap(new Whoops, function ($whoops) { - $whoops->appendHandler($this->whoopsHandler()); - - $whoops->writeToOutput(false); - - $whoops->allowQuit(false); - })->handleException($e); - } - - /** - * Get the Whoops handler for the application. - * - * @return \Whoops\Handler\Handler - */ - protected function whoopsHandler() - { - try { - return app(HandlerInterface::class); - } catch (BindingResolutionException $e) { - return (new WhoopsHandler)->forDebug(); - } + return app(ExceptionRenderer::class)->render($e); } /** diff --git a/src/Illuminate/Foundation/Exceptions/WhoopsHandler.php b/src/Illuminate/Foundation/Exceptions/WhoopsHandler.php deleted file mode 100644 index c91d1ac7b7ae..000000000000 --- a/src/Illuminate/Foundation/Exceptions/WhoopsHandler.php +++ /dev/null @@ -1,86 +0,0 @@ -handleUnconditionally(true); - - $this->registerApplicationPaths($handler) - ->registerBlacklist($handler) - ->registerEditor($handler); - }); - } - - /** - * Register the application paths with the handler. - * - * @param \Whoops\Handler\PrettyPageHandler $handler - * @return $this - */ - protected function registerApplicationPaths($handler) - { - $handler->setApplicationPaths( - array_flip($this->directoriesExceptVendor()) - ); - - return $this; - } - - /** - * Get the application paths except for the "vendor" directory. - * - * @return array - */ - protected function directoriesExceptVendor() - { - return Arr::except( - array_flip((new Filesystem)->directories(base_path())), - [base_path('vendor')] - ); - } - - /** - * Register the blacklist with the handler. - * - * @param \Whoops\Handler\PrettyPageHandler $handler - * @return $this - */ - protected function registerBlacklist($handler) - { - foreach (config('app.debug_blacklist', config('app.debug_hide', [])) as $key => $secrets) { - foreach ($secrets as $secret) { - $handler->blacklist($key, $secret); - } - } - - return $this; - } - - /** - * Register the editor with the handler. - * - * @param \Whoops\Handler\PrettyPageHandler $handler - * @return $this - */ - protected function registerEditor($handler) - { - if (config('app.editor', false)) { - $handler->setEditor(config('app.editor')); - } - - return $this; - } -} From b68826962fe28117f0efa9be001eee4d8fe7ad2e Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Wed, 19 May 2021 15:55:28 +0200 Subject: [PATCH 128/194] Fix code style --- src/Illuminate/Contracts/Foundation/ExceptionRenderer.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php b/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php index 92d56f4a0ab1..24f4e4be0961 100644 --- a/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php +++ b/src/Illuminate/Contracts/Foundation/ExceptionRenderer.php @@ -7,8 +7,7 @@ interface ExceptionRenderer /** * Renders the given exception as HTML. * - * @param \Throwable $throwable - * + * @param \Throwable $throwable * @return string */ public function render($throwable); From b701d953d0e1983d4fafbf747c4c2fe4d8453a49 Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Fri, 21 May 2021 10:24:30 +0200 Subject: [PATCH 129/194] Add WhoopsExceptionRenderer --- .../Whoops/WhoopsExceptionRenderer.php | 32 +++++++ .../Exceptions/Whoops/WhoopsHandler.php | 86 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php create mode 100644 src/Illuminate/Foundation/Exceptions/Whoops/WhoopsHandler.php diff --git a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php new file mode 100644 index 000000000000..a955e896106b --- /dev/null +++ b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php @@ -0,0 +1,32 @@ +appendHandler($this->whoopsHandler()); + + $whoops->writeToOutput(false); + + $whoops->allowQuit(false); + })->handleException($throwable); + } + + /** + * Get the Whoops handler for the application. + * + * @return \Whoops\Handler\Handler + */ + protected function whoopsHandler() + { + return (new WhoopsHandler)->forDebug(); + } +} diff --git a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsHandler.php b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsHandler.php new file mode 100644 index 000000000000..40ee9f2fcecf --- /dev/null +++ b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsHandler.php @@ -0,0 +1,86 @@ +handleUnconditionally(true); + + $this->registerApplicationPaths($handler) + ->registerBlacklist($handler) + ->registerEditor($handler); + }); + } + + /** + * Register the application paths with the handler. + * + * @param \Whoops\Handler\PrettyPageHandler $handler + * @return $this + */ + protected function registerApplicationPaths($handler) + { + $handler->setApplicationPaths( + array_flip($this->directoriesExceptVendor()) + ); + + return $this; + } + + /** + * Get the application paths except for the "vendor" directory. + * + * @return array + */ + protected function directoriesExceptVendor() + { + return Arr::except( + array_flip((new Filesystem)->directories(base_path())), + [base_path('vendor')] + ); + } + + /** + * Register the blacklist with the handler. + * + * @param \Whoops\Handler\PrettyPageHandler $handler + * @return $this + */ + protected function registerBlacklist($handler) + { + foreach (config('app.debug_blacklist', config('app.debug_hide', [])) as $key => $secrets) { + foreach ($secrets as $secret) { + $handler->blacklist($key, $secret); + } + } + + return $this; + } + + /** + * Register the editor with the handler. + * + * @param \Whoops\Handler\PrettyPageHandler $handler + * @return $this + */ + protected function registerEditor($handler) + { + if (config('app.editor', false)) { + $handler->setEditor(config('app.editor')); + } + + return $this; + } +} From 9213d302d485a383a5bf86772f82690864e77767 Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Fri, 21 May 2021 10:26:15 +0200 Subject: [PATCH 130/194] Code style fixes --- src/Illuminate/Foundation/Exceptions/Handler.php | 1 - .../Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 0ce6e40b1e43..2e8e38a2e016 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -6,7 +6,6 @@ use Exception; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\AuthenticationException; -use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract; use Illuminate\Contracts\Foundation\ExceptionRenderer; diff --git a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php index a955e896106b..406460fe1fc4 100644 --- a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php +++ b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php @@ -3,7 +3,6 @@ namespace Illuminate\Foundation\Exceptions\Whoops; use Illuminate\Contracts\Foundation\ExceptionRenderer; -use Illuminate\Foundation\Exceptions\Whoops\WhoopsHandler; use Whoops\Run as Whoops; use function tap; From fd56f1bad52f00b39e3b72012596b99e0625e453 Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Fri, 21 May 2021 14:09:46 +0200 Subject: [PATCH 131/194] Code style --- .../Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php index 406460fe1fc4..a606752b67ec 100644 --- a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php +++ b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php @@ -3,8 +3,8 @@ namespace Illuminate\Foundation\Exceptions\Whoops; use Illuminate\Contracts\Foundation\ExceptionRenderer; -use Whoops\Run as Whoops; use function tap; +use Whoops\Run as Whoops; class WhoopsExceptionRenderer implements ExceptionRenderer { From a7970f70e41eb1ebac63d636d501992d82bdbbd9 Mon Sep 17 00:00:00 2001 From: Marco Bellido Date: Mon, 24 May 2021 20:49:42 +0200 Subject: [PATCH 132/194] Support iterables objects on data_get nested arrays (#37453) --- src/Illuminate/Collections/helpers.php | 2 +- tests/Support/SupportHelpersTest.php | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/helpers.php b/src/Illuminate/Collections/helpers.php index 67669e5ce1c6..5138b2cd1a12 100644 --- a/src/Illuminate/Collections/helpers.php +++ b/src/Illuminate/Collections/helpers.php @@ -58,7 +58,7 @@ function data_get($target, $key, $default = null) if ($segment === '*') { if ($target instanceof Collection) { $target = $target->all(); - } elseif (! is_array($target)) { + } elseif (! is_iterable($target)) { return value($default); } diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index bc2d71f19463..8acc3c7e7d00 100755 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -3,9 +3,11 @@ namespace Illuminate\Tests\Support; use ArrayAccess; +use ArrayIterator; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Env; use Illuminate\Support\Optional; +use IteratorAggregate; use LogicException; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -87,10 +89,18 @@ public function testDataGetWithNestedArrays() ['name' => 'abigail'], ['name' => 'dayle'], ]; + $arrayIterable = new SupportTestArrayIterable([ + ['name' => 'taylor', 'email' => 'taylorotwell@gmail.com'], + ['name' => 'abigail'], + ['name' => 'dayle'], + ]); $this->assertEquals(['taylor', 'abigail', 'dayle'], data_get($array, '*.name')); $this->assertEquals(['taylorotwell@gmail.com', null, null], data_get($array, '*.email', 'irrelevant')); + $this->assertEquals(['taylor', 'abigail', 'dayle'], data_get($arrayIterable, '*.name')); + $this->assertEquals(['taylorotwell@gmail.com', null, null], data_get($arrayIterable, '*.email', 'irrelevant')); + $array = [ 'users' => [ ['first' => 'taylor', 'last' => 'otwell', 'email' => 'taylorotwell@gmail.com'], @@ -792,3 +802,18 @@ public function offsetUnset($offset) unset($this->attributes[$offset]); } } + +class SupportTestArrayIterable implements IteratorAggregate +{ + protected $items = []; + + public function __construct($items = []) + { + $this->items = $items; + } + + public function getIterator() + { + return new ArrayIterator($this->items); + } +} From fe93d991fb190092d9f45643d6fa9b79844f1c0e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 26 May 2021 07:52:13 -0500 Subject: [PATCH 133/194] formatting --- .../Exceptions/Whoops/WhoopsExceptionRenderer.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php index a606752b67ec..908d9a262866 100644 --- a/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php +++ b/src/Illuminate/Foundation/Exceptions/Whoops/WhoopsExceptionRenderer.php @@ -8,6 +8,12 @@ class WhoopsExceptionRenderer implements ExceptionRenderer { + /** + * Renders the given exception as HTML. + * + * @param \Throwable $throwable + * @return string + */ public function render($throwable) { return tap(new Whoops, function ($whoops) { From 95b1899d1a191a99c64cf0848ecba6d9dd201c76 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 4 Jun 2021 20:28:36 +0200 Subject: [PATCH 134/194] [9.x] Move to anonymous migrations (#37598) * Move to anonymous migrations * Fix tests --- src/Illuminate/Cache/Console/stubs/cache.stub | 4 ++-- .../Database/Migrations/MigrationCreator.php | 10 ++-------- .../Console/stubs/notifications.stub | 4 ++-- .../Queue/Console/BatchesTableCommand.php | 10 +++------- .../Queue/Console/FailedTableCommand.php | 10 +++------- src/Illuminate/Queue/Console/TableCommand.php | 10 +++------- src/Illuminate/Queue/Console/stubs/batches.stub | 4 ++-- .../Queue/Console/stubs/failed_jobs.stub | 4 ++-- src/Illuminate/Queue/Console/stubs/jobs.stub | 4 ++-- .../Session/Console/stubs/database.stub | 4 ++-- tests/Database/DatabaseMigrationCreatorTest.php | 16 ++++++++-------- 11 files changed, 31 insertions(+), 49 deletions(-) diff --git a/src/Illuminate/Cache/Console/stubs/cache.stub b/src/Illuminate/Cache/Console/stubs/cache.stub index 7b73e5fd1a69..bb49432fe4a1 100644 --- a/src/Illuminate/Cache/Console/stubs/cache.stub +++ b/src/Illuminate/Cache/Console/stubs/cache.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateCacheTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -29,4 +29,4 @@ class CreateCacheTable extends Migration { Schema::dropIfExists('cache'); } -} +}; diff --git a/src/Illuminate/Database/Migrations/MigrationCreator.php b/src/Illuminate/Database/Migrations/MigrationCreator.php index 78223f7dff4d..d8f1ce9d0b1e 100755 --- a/src/Illuminate/Database/Migrations/MigrationCreator.php +++ b/src/Illuminate/Database/Migrations/MigrationCreator.php @@ -68,7 +68,7 @@ public function create($name, $path, $table = null, $create = false) $this->files->ensureDirectoryExists(dirname($path)); $this->files->put( - $path, $this->populateStub($name, $stub, $table) + $path, $this->populateStub($stub, $table) ); // Next, we will fire any hooks that are supposed to fire after a migration is @@ -132,18 +132,12 @@ protected function getStub($table, $create) /** * Populate the place-holders in the migration stub. * - * @param string $name * @param string $stub * @param string|null $table * @return string */ - protected function populateStub($name, $stub, $table) + protected function populateStub($stub, $table) { - $stub = str_replace( - ['DummyClass', '{{ class }}', '{{class}}'], - $this->getClassName($name), $stub - ); - // Here we will replace the table place-holders with the table specified by // the developer, which is useful for quickly creating a tables creation // or update migration from the console instead of typing it manually. diff --git a/src/Illuminate/Notifications/Console/stubs/notifications.stub b/src/Illuminate/Notifications/Console/stubs/notifications.stub index 9797596dc4ce..4357c9efa5dc 100644 --- a/src/Illuminate/Notifications/Console/stubs/notifications.stub +++ b/src/Illuminate/Notifications/Console/stubs/notifications.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateNotificationsTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -32,4 +32,4 @@ class CreateNotificationsTable extends Migration { Schema::dropIfExists('notifications'); } -} +}; diff --git a/src/Illuminate/Queue/Console/BatchesTableCommand.php b/src/Illuminate/Queue/Console/BatchesTableCommand.php index 86c9d928fb90..01cb784e1d76 100644 --- a/src/Illuminate/Queue/Console/BatchesTableCommand.php +++ b/src/Illuminate/Queue/Console/BatchesTableCommand.php @@ -5,7 +5,6 @@ use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Composer; -use Illuminate\Support\Str; class BatchesTableCommand extends Command { @@ -69,7 +68,7 @@ public function handle() $table = $this->laravel['config']['queue.batching.table'] ?? 'job_batches'; $this->replaceMigration( - $this->createBaseMigration($table), $table, Str::studly($table) + $this->createBaseMigration($table), $table ); $this->info('Migration created successfully!'); @@ -95,15 +94,12 @@ protected function createBaseMigration($table = 'failed_jobs') * * @param string $path * @param string $table - * @param string $tableClassName * @return void */ - protected function replaceMigration($path, $table, $tableClassName) + protected function replaceMigration($path, $table) { $stub = str_replace( - ['{{table}}', '{{tableClassName}}'], - [$table, $tableClassName], - $this->files->get(__DIR__.'/stubs/batches.stub') + '{{table}}', $table, $this->files->get(__DIR__.'/stubs/batches.stub') ); $this->files->put($path, $stub); diff --git a/src/Illuminate/Queue/Console/FailedTableCommand.php b/src/Illuminate/Queue/Console/FailedTableCommand.php index aab84d21a5dd..8cb20bc4c7d3 100644 --- a/src/Illuminate/Queue/Console/FailedTableCommand.php +++ b/src/Illuminate/Queue/Console/FailedTableCommand.php @@ -5,7 +5,6 @@ use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Composer; -use Illuminate\Support\Str; class FailedTableCommand extends Command { @@ -69,7 +68,7 @@ public function handle() $table = $this->laravel['config']['queue.failed.table']; $this->replaceMigration( - $this->createBaseMigration($table), $table, Str::studly($table) + $this->createBaseMigration($table), $table ); $this->info('Migration created successfully!'); @@ -95,15 +94,12 @@ protected function createBaseMigration($table = 'failed_jobs') * * @param string $path * @param string $table - * @param string $tableClassName * @return void */ - protected function replaceMigration($path, $table, $tableClassName) + protected function replaceMigration($path, $table) { $stub = str_replace( - ['{{table}}', '{{tableClassName}}'], - [$table, $tableClassName], - $this->files->get(__DIR__.'/stubs/failed_jobs.stub') + '{{table}}', $table, $this->files->get(__DIR__.'/stubs/failed_jobs.stub') ); $this->files->put($path, $stub); diff --git a/src/Illuminate/Queue/Console/TableCommand.php b/src/Illuminate/Queue/Console/TableCommand.php index 3a083d487ccf..dfdb3615730f 100644 --- a/src/Illuminate/Queue/Console/TableCommand.php +++ b/src/Illuminate/Queue/Console/TableCommand.php @@ -5,7 +5,6 @@ use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Composer; -use Illuminate\Support\Str; class TableCommand extends Command { @@ -69,7 +68,7 @@ public function handle() $table = $this->laravel['config']['queue.connections.database.table']; $this->replaceMigration( - $this->createBaseMigration($table), $table, Str::studly($table) + $this->createBaseMigration($table), $table ); $this->info('Migration created successfully!'); @@ -95,15 +94,12 @@ protected function createBaseMigration($table = 'jobs') * * @param string $path * @param string $table - * @param string $tableClassName * @return void */ - protected function replaceMigration($path, $table, $tableClassName) + protected function replaceMigration($path, $table) { $stub = str_replace( - ['{{table}}', '{{tableClassName}}'], - [$table, $tableClassName], - $this->files->get(__DIR__.'/stubs/jobs.stub') + '{{table}}', $table, $this->files->get(__DIR__.'/stubs/jobs.stub') ); $this->files->put($path, $stub); diff --git a/src/Illuminate/Queue/Console/stubs/batches.stub b/src/Illuminate/Queue/Console/stubs/batches.stub index d4fa380c7624..60be4d2b2ef1 100644 --- a/src/Illuminate/Queue/Console/stubs/batches.stub +++ b/src/Illuminate/Queue/Console/stubs/batches.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class Create{{tableClassName}}Table extends Migration +return new class extends Migration { /** * Run the migrations. @@ -36,4 +36,4 @@ class Create{{tableClassName}}Table extends Migration { Schema::dropIfExists('{{table}}'); } -} +}; diff --git a/src/Illuminate/Queue/Console/stubs/failed_jobs.stub b/src/Illuminate/Queue/Console/stubs/failed_jobs.stub index 6179e7f2f378..c804dd6d6e2e 100644 --- a/src/Illuminate/Queue/Console/stubs/failed_jobs.stub +++ b/src/Illuminate/Queue/Console/stubs/failed_jobs.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class Create{{tableClassName}}Table extends Migration +return new class extends Migration { /** * Run the migrations. @@ -33,4 +33,4 @@ class Create{{tableClassName}}Table extends Migration { Schema::dropIfExists('{{table}}'); } -} +}; diff --git a/src/Illuminate/Queue/Console/stubs/jobs.stub b/src/Illuminate/Queue/Console/stubs/jobs.stub index 45d6031de37a..5ea6d0cb39c3 100644 --- a/src/Illuminate/Queue/Console/stubs/jobs.stub +++ b/src/Illuminate/Queue/Console/stubs/jobs.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class Create{{tableClassName}}Table extends Migration +return new class extends Migration { /** * Run the migrations. @@ -33,4 +33,4 @@ class Create{{tableClassName}}Table extends Migration { Schema::dropIfExists('{{table}}'); } -} +}; diff --git a/src/Illuminate/Session/Console/stubs/database.stub b/src/Illuminate/Session/Console/stubs/database.stub index 88b4a316e6cd..c455537a9cc0 100755 --- a/src/Illuminate/Session/Console/stubs/database.stub +++ b/src/Illuminate/Session/Console/stubs/database.stub @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateSessionsTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -32,4 +32,4 @@ class CreateSessionsTable extends Migration { Schema::dropIfExists('sessions'); } -} +}; diff --git a/tests/Database/DatabaseMigrationCreatorTest.php b/tests/Database/DatabaseMigrationCreatorTest.php index 491be54c3eba..2b856ac74bbe 100755 --- a/tests/Database/DatabaseMigrationCreatorTest.php +++ b/tests/Database/DatabaseMigrationCreatorTest.php @@ -21,9 +21,9 @@ public function testBasicCreateMethodStoresMigrationFile() $creator->expects($this->any())->method('getDatePrefix')->willReturn('foo'); $creator->getFilesystem()->shouldReceive('exists')->once()->with('stubs/migration.stub')->andReturn(false); - $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.stub')->andReturn('DummyClass'); + $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.stub')->andReturn('return new class'); $creator->getFilesystem()->shouldReceive('ensureDirectoryExists')->once()->with('foo'); - $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar'); + $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class'); $creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']); $creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php'); @@ -44,9 +44,9 @@ public function testBasicCreateMethodCallsPostCreateHooks() $creator->expects($this->any())->method('getDatePrefix')->willReturn('foo'); $creator->getFilesystem()->shouldReceive('exists')->once()->with('stubs/migration.update.stub')->andReturn(false); - $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.update.stub')->andReturn('DummyClass DummyTable'); + $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.update.stub')->andReturn('return new class DummyTable'); $creator->getFilesystem()->shouldReceive('ensureDirectoryExists')->once()->with('foo'); - $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar baz'); + $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class baz'); $creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']); $creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php'); @@ -64,9 +64,9 @@ public function testTableUpdateMigrationStoresMigrationFile() $creator = $this->getCreator(); $creator->expects($this->any())->method('getDatePrefix')->willReturn('foo'); $creator->getFilesystem()->shouldReceive('exists')->once()->with('stubs/migration.update.stub')->andReturn(false); - $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.update.stub')->andReturn('DummyClass DummyTable'); + $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.update.stub')->andReturn('return new class DummyTable'); $creator->getFilesystem()->shouldReceive('ensureDirectoryExists')->once()->with('foo'); - $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar baz'); + $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class baz'); $creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']); $creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php'); @@ -78,9 +78,9 @@ public function testTableCreationMigrationStoresMigrationFile() $creator = $this->getCreator(); $creator->expects($this->any())->method('getDatePrefix')->willReturn('foo'); $creator->getFilesystem()->shouldReceive('exists')->once()->with('stubs/migration.create.stub')->andReturn(false); - $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.create.stub')->andReturn('DummyClass DummyTable'); + $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath().'/migration.create.stub')->andReturn('return new class DummyTable'); $creator->getFilesystem()->shouldReceive('ensureDirectoryExists')->once()->with('foo'); - $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar baz'); + $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class baz'); $creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']); $creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php'); From b20f8d056f612dfbc0f86570edd2f9aff892e4cb Mon Sep 17 00:00:00 2001 From: Martin Krisell Date: Fri, 4 Jun 2021 20:44:32 +0200 Subject: [PATCH 135/194] Combine signed url verification fix from 8.x with excepted parameters support from 9.x --- .../Providers/FoundationServiceProvider.php | 4 + src/Illuminate/Routing/UrlGenerator.php | 9 +- tests/Integration/Routing/UrlSigningTest.php | 84 +++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index f5ffb33658f5..90c0cfbd66cb 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -85,5 +85,9 @@ public function registerRequestSignatureValidation() Request::macro('hasValidRelativeSignature', function () { return URL::hasValidSignature($this, $absolute = false); }); + + Request::macro('hasValidSignatureWithExceptions', function ($ignoreQuery = [], $absolute = true) { + return URL::hasValidSignature($this, $absolute, $ignoreQuery); + }); } } diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 9a2522ddbb1e..b5cc31f3b251 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -393,9 +393,12 @@ public function hasCorrectSignature(Request $request, $absolute = true, array $i $url = $absolute ? $request->url() : '/'.$request->path(); - $original = rtrim($url.'?'.Arr::query( - Arr::except($request->query(), $ignoreQuery) - ), '?'); + $queryString = $request->server->get('QUERY_STRING'); + foreach ($ignoreQuery as $ignore) { + $queryString = ltrim(preg_replace("/(^|&){$ignore}=[^&]+/", '', $queryString), '&'); + } + + $original = rtrim($url.'?'.$queryString, '?'); $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver)); diff --git a/tests/Integration/Routing/UrlSigningTest.php b/tests/Integration/Routing/UrlSigningTest.php index 8c31100de292..49ecd52cd730 100644 --- a/tests/Integration/Routing/UrlSigningTest.php +++ b/tests/Integration/Routing/UrlSigningTest.php @@ -59,6 +59,90 @@ public function testSignedUrlWithUrlWithoutSignatureParameter() $this->assertSame('invalid', $this->get('/foo/1')->original); } + public function testSignedUrlWithNullParameter() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignature() ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, 'param'])); + $this->assertSame('valid', $this->get($url)->original); + } + + public function testSignedUrlWithEmptyStringParameter() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignature() ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, 'param' => ''])); + $this->assertSame('valid', $this->get($url)->original); + } + + public function testSignedUrlWithMultipleParameters() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignature() ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, 'param1' => 'value1', 'param2' => 'value2'])); + $this->assertSame('valid', $this->get($url)->original); + } + + public function testSignedUrlWithSignatureTextInKeyOrValue() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignature() ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, 'custom-signature' => 'signature=value'])); + $this->assertSame('valid', $this->get($url)->original); + } + + public function testSignedUrlWithAppendedNullParameterInvalid() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignature() ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1])); + $this->assertSame('invalid', $this->get($url.'&appended')->original); + } + + public function testSignedUrlParametersParsedCorrectly() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignature() + && intval($id) === 1 + && $request->has('paramEmpty') + && $request->has('paramEmptyString') + && $request->query('paramWithValue') === 'value' + ? 'valid' + : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, + 'paramEmpty', + 'paramEmptyString' => '', + 'paramWithValue' => 'value', + ])); + $this->assertSame('valid', $this->get($url)->original); + } + + public function testExceptedParametersCanBeAddedInAnyOrder() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignatureWithExceptions(['excepted1', 'excepted2']) ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, + 'bar' => 'baz', + ])); + + $this->assertSame('valid', $this->get($url.'&excepted1=value&excepted2=another-value')->original); + $this->assertSame('valid', $this->get($url.'&excepted2=value&excepted1=another-value')->original); + } + public function testSignedMiddleware() { Route::get('/foo/{id}', function (Request $request, $id) { From fce9dce27c5f44220f7a6f156ce0a16675392173 Mon Sep 17 00:00:00 2001 From: Martin Krisell Date: Sun, 6 Jun 2021 09:37:25 +0200 Subject: [PATCH 136/194] Handle special cases for signed url validation exceptions --- src/Illuminate/Routing/UrlGenerator.php | 6 +++- tests/Integration/Routing/UrlSigningTest.php | 30 ++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index b5cc31f3b251..33ddbf34a951 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -395,7 +395,11 @@ public function hasCorrectSignature(Request $request, $absolute = true, array $i $queryString = $request->server->get('QUERY_STRING'); foreach ($ignoreQuery as $ignore) { - $queryString = ltrim(preg_replace("/(^|&){$ignore}=[^&]+/", '', $queryString), '&'); + if (strlen($ignore) === 0) { + continue; + } + + $queryString = ltrim(preg_replace('/(^|&)'.preg_quote($ignore).'=?[^&]*/', '', $queryString), '&'); } $original = rtrim($url.'?'.$queryString, '?'); diff --git a/tests/Integration/Routing/UrlSigningTest.php b/tests/Integration/Routing/UrlSigningTest.php index 49ecd52cd730..9c153f8f2766 100644 --- a/tests/Integration/Routing/UrlSigningTest.php +++ b/tests/Integration/Routing/UrlSigningTest.php @@ -132,15 +132,39 @@ public function testSignedUrlParametersParsedCorrectly() public function testExceptedParametersCanBeAddedInAnyOrder() { Route::get('/foo/{id}', function (Request $request, $id) { - return $request->hasValidSignatureWithExceptions(['excepted1', 'excepted2']) ? 'valid' : 'invalid'; + return $request->hasValidSignatureWithExceptions(['one', 'two', 'three']) ? 'valid' : 'invalid'; })->name('foo'); $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, 'bar' => 'baz', ])); - $this->assertSame('valid', $this->get($url.'&excepted1=value&excepted2=another-value')->original); - $this->assertSame('valid', $this->get($url.'&excepted2=value&excepted1=another-value')->original); + $this->assertSame('valid', $this->get($url.'&one=value&two=another-value')->original); + $this->assertSame('valid', $this->get($url.'&two=value&one=&three')->original); + } + + public function testUnusualExceptedParametersWorksAsExpexted() + { + $this->withoutExceptionHandling(); + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignatureWithExceptions(['']) ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, + 'bar' => 'baz', + ])); + + $this->assertSame('valid', $this->get($url)->original); + + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignatureWithExceptions(['*', '[a-z]+']) ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, + 'bar' => 'baz', + ])); + + $this->assertSame('valid', $this->get($url.'&*=value&[a-z]+=value')->original); } public function testSignedMiddleware() From b7dda6ba00150ce39891f88bf26b07a5beec4bd9 Mon Sep 17 00:00:00 2001 From: Martin Krisell Date: Sun, 6 Jun 2021 22:15:17 +0200 Subject: [PATCH 137/194] Allow signed url excepted parameters to be a prefix or suffix of another query parameter --- src/Illuminate/Routing/UrlGenerator.php | 4 +++- tests/Integration/Routing/UrlSigningTest.php | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 33ddbf34a951..fa29d4683d74 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -399,7 +399,9 @@ public function hasCorrectSignature(Request $request, $absolute = true, array $i continue; } - $queryString = ltrim(preg_replace('/(^|&)'.preg_quote($ignore).'=?[^&]*/', '', $queryString), '&'); + $queryString = ltrim( + preg_replace('/(^|&)'.preg_quote($ignore).'((=[^&]*)|(=?(&|$)))/', '', $queryString), + '&'); } $original = rtrim($url.'?'.$queryString, '?'); diff --git a/tests/Integration/Routing/UrlSigningTest.php b/tests/Integration/Routing/UrlSigningTest.php index 9c153f8f2766..e281bf29562b 100644 --- a/tests/Integration/Routing/UrlSigningTest.php +++ b/tests/Integration/Routing/UrlSigningTest.php @@ -167,6 +167,20 @@ public function testUnusualExceptedParametersWorksAsExpexted() $this->assertSame('valid', $this->get($url.'&*=value&[a-z]+=value')->original); } + public function testExceptedParameterCanBeAPrefixOrSuffixOfAnotherParameter() + { + Route::get('/foo/{id}', function (Request $request, $id) { + return $request->hasValidSignatureWithExceptions(['pre', 'fix']) ? 'valid' : 'invalid'; + })->name('foo'); + + $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, + 'prefix' => 'value', + 'suffix' => 'value', + ])); + + $this->assertSame('valid', $this->get($url.'&pre=fix&fix=suff')->original); + } + public function testSignedMiddleware() { Route::get('/foo/{id}', function (Request $request, $id) { From 932f6baef0ead6c30e7df8a93e7646d5b4671d2b Mon Sep 17 00:00:00 2001 From: Martin Krisell Date: Mon, 7 Jun 2021 17:45:33 +0200 Subject: [PATCH 138/194] Replace regexp with split to filter out ignored query parameters --- src/Illuminate/Routing/UrlGenerator.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index fa29d4683d74..3623d609b257 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -393,16 +393,9 @@ public function hasCorrectSignature(Request $request, $absolute = true, array $i $url = $absolute ? $request->url() : '/'.$request->path(); - $queryString = $request->server->get('QUERY_STRING'); - foreach ($ignoreQuery as $ignore) { - if (strlen($ignore) === 0) { - continue; - } - - $queryString = ltrim( - preg_replace('/(^|&)'.preg_quote($ignore).'((=[^&]*)|(=?(&|$)))/', '', $queryString), - '&'); - } + $queryString = collect(explode('&', $request->server->get('QUERY_STRING'))) + ->filter(fn ($parameter) => ! in_array(Str::before($parameter, '='), $ignoreQuery)) + ->join('&'); $original = rtrim($url.'?'.$queryString, '?'); From 895dca9b58adf7522facf8647d01e47610d98dbb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 7 Jun 2021 15:15:54 -0500 Subject: [PATCH 139/194] Update UrlGenerator.php --- src/Illuminate/Routing/UrlGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 3623d609b257..e144934dab72 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -394,7 +394,7 @@ public function hasCorrectSignature(Request $request, $absolute = true, array $i $url = $absolute ? $request->url() : '/'.$request->path(); $queryString = collect(explode('&', $request->server->get('QUERY_STRING'))) - ->filter(fn ($parameter) => ! in_array(Str::before($parameter, '='), $ignoreQuery)) + ->reject(fn ($parameter) => in_array(Str::before($parameter, '='), $ignoreQuery)) ->join('&'); $original = rtrim($url.'?'.$queryString, '?'); From 4c2c181ba38c1f27383329e148fa77dba0c42e50 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 7 Jun 2021 15:18:42 -0500 Subject: [PATCH 140/194] Update FoundationServiceProvider.php --- .../Foundation/Providers/FoundationServiceProvider.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index 90c0cfbd66cb..f5ffb33658f5 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -85,9 +85,5 @@ public function registerRequestSignatureValidation() Request::macro('hasValidRelativeSignature', function () { return URL::hasValidSignature($this, $absolute = false); }); - - Request::macro('hasValidSignatureWithExceptions', function ($ignoreQuery = [], $absolute = true) { - return URL::hasValidSignature($this, $absolute, $ignoreQuery); - }); } } From ce27f307a458c48ee59c4fdc846e5a70ca9928f1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 7 Jun 2021 15:21:28 -0500 Subject: [PATCH 141/194] formatting --- .../Foundation/Providers/FoundationServiceProvider.php | 4 ++++ tests/Integration/Routing/UrlSigningTest.php | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index f5ffb33658f5..2ed507f49461 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -85,5 +85,9 @@ public function registerRequestSignatureValidation() Request::macro('hasValidRelativeSignature', function () { return URL::hasValidSignature($this, $absolute = false); }); + + Request::macro('hasValidSignatureWhileIgnoring', function ($ignoreQuery = [], $absolute = true) { + return URL::hasValidSignature($this, $absolute, $ignoreQuery); + }); } } diff --git a/tests/Integration/Routing/UrlSigningTest.php b/tests/Integration/Routing/UrlSigningTest.php index e281bf29562b..d4c2aab16528 100644 --- a/tests/Integration/Routing/UrlSigningTest.php +++ b/tests/Integration/Routing/UrlSigningTest.php @@ -132,7 +132,7 @@ public function testSignedUrlParametersParsedCorrectly() public function testExceptedParametersCanBeAddedInAnyOrder() { Route::get('/foo/{id}', function (Request $request, $id) { - return $request->hasValidSignatureWithExceptions(['one', 'two', 'three']) ? 'valid' : 'invalid'; + return $request->hasValidSignatureWhileIgnoring(['one', 'two', 'three']) ? 'valid' : 'invalid'; })->name('foo'); $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, @@ -147,7 +147,7 @@ public function testUnusualExceptedParametersWorksAsExpexted() { $this->withoutExceptionHandling(); Route::get('/foo/{id}', function (Request $request, $id) { - return $request->hasValidSignatureWithExceptions(['']) ? 'valid' : 'invalid'; + return $request->hasValidSignatureWhileIgnoring(['']) ? 'valid' : 'invalid'; })->name('foo'); $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, @@ -157,7 +157,7 @@ public function testUnusualExceptedParametersWorksAsExpexted() $this->assertSame('valid', $this->get($url)->original); Route::get('/foo/{id}', function (Request $request, $id) { - return $request->hasValidSignatureWithExceptions(['*', '[a-z]+']) ? 'valid' : 'invalid'; + return $request->hasValidSignatureWhileIgnoring(['*', '[a-z]+']) ? 'valid' : 'invalid'; })->name('foo'); $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, @@ -170,7 +170,7 @@ public function testUnusualExceptedParametersWorksAsExpexted() public function testExceptedParameterCanBeAPrefixOrSuffixOfAnotherParameter() { Route::get('/foo/{id}', function (Request $request, $id) { - return $request->hasValidSignatureWithExceptions(['pre', 'fix']) ? 'valid' : 'invalid'; + return $request->hasValidSignatureWhileIgnoring(['pre', 'fix']) ? 'valid' : 'invalid'; })->name('foo'); $this->assertIsString($url = URL::signedRoute('foo', ['id' => 1, From fc46309cfa4678f06acf0a91a5eee34d33f3516d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 7 Jun 2021 15:22:18 -0500 Subject: [PATCH 142/194] Apply fixes from StyleCI (#37620) --- .../Foundation/Providers/FoundationServiceProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index 2ed507f49461..024ebcd17214 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -87,7 +87,7 @@ public function registerRequestSignatureValidation() }); Request::macro('hasValidSignatureWhileIgnoring', function ($ignoreQuery = [], $absolute = true) { - return URL::hasValidSignature($this, $absolute, $ignoreQuery); - }); + return URL::hasValidSignature($this, $absolute, $ignoreQuery); + }); } } From 77ed2c7d46daaa5549003eb4be187537996529d4 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 7 Jun 2021 22:37:13 +0200 Subject: [PATCH 143/194] fix test --- tests/Integration/Database/EloquentStrictLoadingTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Integration/Database/EloquentStrictLoadingTest.php b/tests/Integration/Database/EloquentStrictLoadingTest.php index 5e97a330c1ed..77aefc59d841 100644 --- a/tests/Integration/Database/EloquentStrictLoadingTest.php +++ b/tests/Integration/Database/EloquentStrictLoadingTest.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\LazyLoadingViolationException; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; /** @@ -115,7 +116,7 @@ public function testStrictModeThrowsAnExceptionOnLazyLoadingInRelations() public function testStrictModeWithCustomCallbackOnLazyLoading() { - $this->expectsEvents(ViolatedLazyLoadingEvent::class); + Event::fake(); Model::handleLazyLoadingViolationUsing(function ($model, $key) { event(new ViolatedLazyLoadingEvent($model, $key)); @@ -127,6 +128,8 @@ public function testStrictModeWithCustomCallbackOnLazyLoading() $models = EloquentStrictLoadingTestModel1::get(); $models[0]->modelTwos; + + Event::assertDispatched(ViolatedLazyLoadingEvent::class); } public function testStrictModeWithOverriddenHandlerOnLazyLoading() From d49e8213e90c25f825b27f02dfb032e0d0ef2efd Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Thu, 10 Jun 2021 09:11:40 -0400 Subject: [PATCH 144/194] [9.x] Universal HigherOrderWhenProxy (#37632) * [9.x] Universal HigherOrderWhenProxy * StyleCI * Replace by-reference variables with exceptions --- src/Illuminate/Collections/Enumerable.php | 4 +- .../Collections/HigherOrderWhenProxy.php | 27 ++--- .../Collections/Traits/EnumeratesValues.php | 39 +------ .../Support/Traits/Conditionable.php | 18 ++- tests/Support/SupportCollectionTest.php | 28 ++++- tests/Support/SupportConditionableTest.php | 109 ++++++++++++++++++ 6 files changed, 165 insertions(+), 60 deletions(-) create mode 100644 tests/Support/SupportConditionableTest.php diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 8a0b69455f92..ef99c3143a92 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -271,11 +271,11 @@ public function filter(callable $callback = null); * Apply the callback if the value is truthy. * * @param bool $value - * @param callable $callback + * @param callable|null $callback * @param callable|null $default * @return static|mixed */ - public function when($value, callable $callback, callable $default = null); + public function when($value, callable $callback = null, callable $default = null); /** * Apply the callback if the collection is empty. diff --git a/src/Illuminate/Collections/HigherOrderWhenProxy.php b/src/Illuminate/Collections/HigherOrderWhenProxy.php index 6653c03a656f..173a78396790 100644 --- a/src/Illuminate/Collections/HigherOrderWhenProxy.php +++ b/src/Illuminate/Collections/HigherOrderWhenProxy.php @@ -2,17 +2,14 @@ namespace Illuminate\Support; -/** - * @mixin \Illuminate\Support\Enumerable - */ class HigherOrderWhenProxy { /** - * The collection being operated on. + * The target being conditionally operated on. * - * @var \Illuminate\Support\Enumerable + * @var mixed */ - protected $collection; + protected $target; /** * The condition for proxying. @@ -24,18 +21,18 @@ class HigherOrderWhenProxy /** * Create a new proxy instance. * - * @param \Illuminate\Support\Enumerable $collection + * @param mixed $target * @param bool $condition * @return void */ - public function __construct(Enumerable $collection, $condition) + public function __construct($target, $condition) { + $this->target = $target; $this->condition = $condition; - $this->collection = $collection; } /** - * Proxy accessing an attribute onto the collection. + * Proxy accessing an attribute onto the target. * * @param string $key * @return mixed @@ -43,12 +40,12 @@ public function __construct(Enumerable $collection, $condition) public function __get($key) { return $this->condition - ? $this->collection->{$key} - : $this->collection; + ? $this->target->{$key} + : $this->target; } /** - * Proxy a method call onto the collection. + * Proxy a method call on the target. * * @param string $method * @param array $parameters @@ -57,7 +54,7 @@ public function __get($key) public function __call($method, $parameters) { return $this->condition - ? $this->collection->{$method}(...$parameters) - : $this->collection; + ? $this->target->{$method}(...$parameters) + : $this->target; } } diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index c707c36dfbf6..21b0dc6c29e7 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -11,7 +11,6 @@ use Illuminate\Support\Collection; use Illuminate\Support\Enumerable; use Illuminate\Support\HigherOrderCollectionProxy; -use Illuminate\Support\HigherOrderWhenProxy; use JsonSerializable; use Symfony\Component\VarDumper\VarDumper; use Traversable; @@ -45,6 +44,8 @@ */ trait EnumeratesValues { + use Conditionable; + /** * The methods that can be proxied. * @@ -453,29 +454,6 @@ public function sum($callback = null) }, 0); } - /** - * Apply the callback if the value is truthy. - * - * @param bool|mixed $value - * @param callable|null $callback - * @param callable|null $default - * @return static|mixed - */ - public function when($value, callable $callback = null, callable $default = null) - { - if (! $callback) { - return new HigherOrderWhenProxy($this, $value); - } - - if ($value) { - return $callback($this, $value); - } elseif ($default) { - return $default($this, $value); - } - - return $this; - } - /** * Apply the callback if the collection is empty. * @@ -500,19 +478,6 @@ public function whenNotEmpty(callable $callback, callable $default = null) return $this->when($this->isNotEmpty(), $callback, $default); } - /** - * Apply the callback if the value is falsy. - * - * @param bool $value - * @param callable $callback - * @param callable|null $default - * @return static|mixed - */ - public function unless($value, callable $callback, callable $default = null) - { - return $this->when(! $value, $callback, $default); - } - /** * Apply the callback unless the collection is empty. * diff --git a/src/Illuminate/Support/Traits/Conditionable.php b/src/Illuminate/Support/Traits/Conditionable.php index 183d63c66f02..f70fe8412ee6 100644 --- a/src/Illuminate/Support/Traits/Conditionable.php +++ b/src/Illuminate/Support/Traits/Conditionable.php @@ -2,19 +2,25 @@ namespace Illuminate\Support\Traits; +use Illuminate\Support\HigherOrderWhenProxy; + trait Conditionable { /** * Apply the callback if the given "value" is truthy. * * @param mixed $value - * @param callable $callback + * @param callable|null $callback * @param callable|null $default * * @return mixed */ - public function when($value, $callback, $default = null) + public function when($value, callable $callback = null, callable $default = null) { + if (! $callback) { + return new HigherOrderWhenProxy($this, $value); + } + if ($value) { return $callback($this, $value) ?: $this; } elseif ($default) { @@ -28,13 +34,17 @@ public function when($value, $callback, $default = null) * Apply the callback if the given "value" is falsy. * * @param mixed $value - * @param callable $callback + * @param callable|null $callback * @param callable|null $default * * @return mixed */ - public function unless($value, $callback, $default = null) + public function unless($value, callable $callback = null, callable $default = null) { + if (! $callback) { + return new HigherOrderWhenProxy($this, ! $value); + } + if (! $value) { return $callback($this, $value) ?: $this; } elseif ($default) { diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 2b335b64f986..0f0a8af49b6d 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -4298,8 +4298,8 @@ public function testWhenEmpty($collection) { $data = new $collection(['michael', 'tom']); - $data = $data->whenEmpty(function ($collection) { - return $data->concat(['adam']); + $data = $data->whenEmpty(function () { + throw new Exception('whenEmpty() should not trigger on a collection with items'); }); $this->assertSame(['michael', 'tom'], $data->toArray()); @@ -4367,6 +4367,30 @@ public function testWhenNotEmptyDefault($collection) $this->assertSame(['michael', 'tom', 'adam'], $data->toArray()); } + /** + * @dataProvider collectionClassProvider + */ + public function testHigherOrderWhenAndUnless($collection) + { + $data = new $collection(['michael', 'tom']); + + $data = $data->when(true)->concat(['chris']); + + $this->assertSame(['michael', 'tom', 'chris'], $data->toArray()); + + $data = $data->when(false)->concat(['adam']); + + $this->assertSame(['michael', 'tom', 'chris'], $data->toArray()); + + $data = $data->unless(false)->concat(['adam']); + + $this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray()); + + $data = $data->unless(true)->concat(['bogdan']); + + $this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray()); + } + /** * @dataProvider collectionClassProvider */ diff --git a/tests/Support/SupportConditionableTest.php b/tests/Support/SupportConditionableTest.php new file mode 100644 index 000000000000..c61fdd0bbee2 --- /dev/null +++ b/tests/Support/SupportConditionableTest.php @@ -0,0 +1,109 @@ +when(2, function ($object, $condition) { + $object->on(); + $this->assertEquals(2, $condition); + }, function () { + throw new Exception('when() should not trigger default callback on a truthy value'); + }); + + $this->assertTrue($object->enabled); + } + + public function testWhenDefaultCallback() + { + $object = (new CustomConditionableObject()) + ->when(null, function () { + throw new Exception('when() should not trigger on a falsy value'); + }, function ($object, $condition) { + $object->on(); + $this->assertNull($condition); + }); + + $this->assertTrue($object->enabled); + } + + public function testUnlessConditionCallback() + { + $object = (new CustomConditionableObject()) + ->unless(null, function ($object, $condition) { + $object->on(); + $this->assertNull($condition); + }, function () { + throw new Exception('unless() should not trigger default callback on a falsy value'); + }); + + $this->assertTrue($object->enabled); + } + + public function testUnlessDefaultCallback() + { + $object = (new CustomConditionableObject()) + ->unless(2, function () { + throw new Exception('unless() should not trigger on a truthy value'); + }, function ($object, $condition) { + $object->on(); + $this->assertEquals(2, $condition); + }); + + $this->assertTrue($object->enabled); + } + + public function testWhenProxy() + { + $object = (new CustomConditionableObject())->when(true)->on(); + + $this->assertInstanceOf(CustomConditionableObject::class, $object); + $this->assertTrue($object->enabled); + + $object = (new CustomConditionableObject())->when(false)->on(); + + $this->assertInstanceOf(CustomConditionableObject::class, $object); + $this->assertFalse($object->enabled); + } + + public function testUnlessProxy() + { + $object = (new CustomConditionableObject())->unless(false)->on(); + + $this->assertInstanceOf(CustomConditionableObject::class, $object); + $this->assertTrue($object->enabled); + + $object = (new CustomConditionableObject())->unless(true)->on(); + + $this->assertInstanceOf(CustomConditionableObject::class, $object); + $this->assertFalse($object->enabled); + } +} + +class CustomConditionableObject +{ + use Conditionable; + + public $enabled = false; + + public function on() + { + $this->enabled = true; + + return $this; + } + + public function off() + { + $this->enabled = false; + + return $this; + } +} From a590739385318b7fba687c91142d72049a01a307 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Fri, 11 Jun 2021 09:28:43 -0400 Subject: [PATCH 145/194] Simplify `Conditionable` tests (#37657) --- tests/Support/SupportConditionableTest.php | 84 +++++++++------------- 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/tests/Support/SupportConditionableTest.php b/tests/Support/SupportConditionableTest.php index c61fdd0bbee2..7a28dc7bd543 100644 --- a/tests/Support/SupportConditionableTest.php +++ b/tests/Support/SupportConditionableTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Support; -use Exception; use Illuminate\Support\Traits\Conditionable; use PHPUnit\Framework\TestCase; @@ -10,99 +9,80 @@ class SupportConditionableTest extends TestCase { public function testWhenConditionCallback() { - $object = (new CustomConditionableObject()) - ->when(2, function ($object, $condition) { - $object->on(); - $this->assertEquals(2, $condition); + $logger = (new ConditionableLogger()) + ->when(2, function ($logger, $condition) { + $logger->log('when', $condition); }, function () { - throw new Exception('when() should not trigger default callback on a truthy value'); + $logger->log('default', $condition); }); - $this->assertTrue($object->enabled); + $this->assertSame(['when', 2], $logger->values); } public function testWhenDefaultCallback() { - $object = (new CustomConditionableObject()) + $logger = (new ConditionableLogger()) ->when(null, function () { - throw new Exception('when() should not trigger on a falsy value'); - }, function ($object, $condition) { - $object->on(); - $this->assertNull($condition); + $logger->log('when', $condition); + }, function ($logger, $condition) { + $logger->log('default', $condition); }); - $this->assertTrue($object->enabled); + $this->assertSame(['default', null], $logger->values); } public function testUnlessConditionCallback() { - $object = (new CustomConditionableObject()) - ->unless(null, function ($object, $condition) { - $object->on(); - $this->assertNull($condition); + $logger = (new ConditionableLogger()) + ->unless(null, function ($logger, $condition) { + $logger->log('unless', $condition); }, function () { - throw new Exception('unless() should not trigger default callback on a falsy value'); + $logger->log('default', $condition); }); - $this->assertTrue($object->enabled); + $this->assertSame(['unless', null], $logger->values); } public function testUnlessDefaultCallback() { - $object = (new CustomConditionableObject()) + $logger = (new ConditionableLogger()) ->unless(2, function () { - throw new Exception('unless() should not trigger on a truthy value'); - }, function ($object, $condition) { - $object->on(); - $this->assertEquals(2, $condition); + $logger->log('unless', $condition); + }, function ($logger, $condition) { + $logger->log('default', $condition); }); - $this->assertTrue($object->enabled); + $this->assertSame(['default', 2], $logger->values); } public function testWhenProxy() { - $object = (new CustomConditionableObject())->when(true)->on(); + $logger = (new ConditionableLogger()) + ->when(true)->log('one') + ->when(false)->log('two'); - $this->assertInstanceOf(CustomConditionableObject::class, $object); - $this->assertTrue($object->enabled); - - $object = (new CustomConditionableObject())->when(false)->on(); - - $this->assertInstanceOf(CustomConditionableObject::class, $object); - $this->assertFalse($object->enabled); + $this->assertSame(['one'], $logger->values); } public function testUnlessProxy() { - $object = (new CustomConditionableObject())->unless(false)->on(); - - $this->assertInstanceOf(CustomConditionableObject::class, $object); - $this->assertTrue($object->enabled); + $logger = (new ConditionableLogger()) + ->unless(true)->log('one') + ->unless(false)->log('two'); - $object = (new CustomConditionableObject())->unless(true)->on(); - - $this->assertInstanceOf(CustomConditionableObject::class, $object); - $this->assertFalse($object->enabled); + $this->assertSame(['two'], $logger->values); } } -class CustomConditionableObject +class ConditionableLogger { use Conditionable; - public $enabled = false; - - public function on() - { - $this->enabled = true; - - return $this; - } + public $values = []; - public function off() + public function log(...$values) { - $this->enabled = false; + array_push($this->values, ...$values); return $this; } From 075b6b296c2492611919becaac3cc637948d398a Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Mon, 14 Jun 2021 10:41:37 -0300 Subject: [PATCH 146/194] [9.x] Adds the `scoped` method to the container contract (#37679) * Adds the scoped to the container contract * Add the scopedIf method to the container contract --- .../Contracts/Container/Container.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index 710e7b15bb5d..7d7f2c96a09f 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -81,6 +81,24 @@ public function singleton($abstract, $concrete = null); */ public function singletonIf($abstract, $concrete = null); + /** + * Register a scoped binding in the container. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function scoped($abstract, $concrete = null); + + /** + * Register a scoped binding if it hasn't already been registered. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function scopedIf($abstract, $concrete = null); + /** * "Extend" an abstract type in the container. * From b7f0359dc944a04fe868542b4ec9e6a6f20d8385 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Thu, 17 Jun 2021 16:58:17 -0400 Subject: [PATCH 147/194] [9.x] Add `Conditionable` support for callback conditions (#37667) * Add `Conditionable` support for callback conditions * Update DocBlocks in `Enumerable` to match `Conditionable` * Update uses * Add to collection higher order proxy --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/Enumerable.php | 4 +- src/Illuminate/Collections/LazyCollection.php | 2 +- .../Collections/Traits/EnumeratesValues.php | 10 +- .../Support/Traits/Conditionable.php | 9 +- tests/Support/SupportCollectionTest.php | 24 +++++ tests/Support/SupportConditionableTest.php | 93 ++++++++++++++++++- 7 files changed, 131 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 74e5f9d5053e..d9e07cdecb23 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1069,7 +1069,7 @@ public function sole($key = null, $operator = null, $value = null) ? $this->operatorForWhere(...func_get_args()) : $key; - $items = $this->when($filter)->filter($filter); + $items = $this->unless($filter == null)->filter($filter); if ($items->isEmpty()) { throw new ItemNotFoundException; diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index ef99c3143a92..a3e570ffe8db 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -268,7 +268,7 @@ public function except($keys); public function filter(callable $callback = null); /** - * Apply the callback if the value is truthy. + * Apply the callback if the given "value" is (or resolves to) truthy. * * @param bool $value * @param callable|null $callback @@ -296,7 +296,7 @@ public function whenEmpty(callable $callback, callable $default = null); public function whenNotEmpty(callable $callback, callable $default = null); /** - * Apply the callback if the value is falsy. + * Apply the callback if the given "value" is (or resolves to) truthy. * * @param bool $value * @param callable $callback diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 5b2f19f8add7..54acc3f90ed1 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1028,7 +1028,7 @@ public function sole($key = null, $operator = null, $value = null) : $key; return $this - ->when($filter) + ->unless($filter == null) ->filter($filter) ->take(2) ->collect() diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 21b0dc6c29e7..3d29ce74cecf 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -31,16 +31,18 @@ * @property-read HigherOrderCollectionProxy $min * @property-read HigherOrderCollectionProxy $partition * @property-read HigherOrderCollectionProxy $reject + * @property-read HigherOrderCollectionProxy $skipUntil + * @property-read HigherOrderCollectionProxy $skipWhile * @property-read HigherOrderCollectionProxy $some * @property-read HigherOrderCollectionProxy $sortBy * @property-read HigherOrderCollectionProxy $sortByDesc - * @property-read HigherOrderCollectionProxy $skipUntil - * @property-read HigherOrderCollectionProxy $skipWhile * @property-read HigherOrderCollectionProxy $sum * @property-read HigherOrderCollectionProxy $takeUntil * @property-read HigherOrderCollectionProxy $takeWhile * @property-read HigherOrderCollectionProxy $unique + * @property-read HigherOrderCollectionProxy $unless * @property-read HigherOrderCollectionProxy $until + * @property-read HigherOrderCollectionProxy $when */ trait EnumeratesValues { @@ -76,7 +78,9 @@ trait EnumeratesValues 'takeUntil', 'takeWhile', 'unique', + 'unless', 'until', + 'when', ]; /** @@ -138,7 +142,7 @@ public static function times($number, callable $callback = null) } return static::range(1, $number) - ->when($callback) + ->unless($callback == null) ->map($callback); } diff --git a/src/Illuminate/Support/Traits/Conditionable.php b/src/Illuminate/Support/Traits/Conditionable.php index f70fe8412ee6..5e5d082e5c34 100644 --- a/src/Illuminate/Support/Traits/Conditionable.php +++ b/src/Illuminate/Support/Traits/Conditionable.php @@ -2,12 +2,13 @@ namespace Illuminate\Support\Traits; +use Closure; use Illuminate\Support\HigherOrderWhenProxy; trait Conditionable { /** - * Apply the callback if the given "value" is truthy. + * Apply the callback if the given "value" is (or resolves to) truthy. * * @param mixed $value * @param callable|null $callback @@ -17,6 +18,8 @@ trait Conditionable */ public function when($value, callable $callback = null, callable $default = null) { + $value = $value instanceof Closure ? $value($this) : $value; + if (! $callback) { return new HigherOrderWhenProxy($this, $value); } @@ -31,7 +34,7 @@ public function when($value, callable $callback = null, callable $default = null } /** - * Apply the callback if the given "value" is falsy. + * Apply the callback if the given "value" is (or resolves to) falsy. * * @param mixed $value * @param callable|null $callback @@ -41,6 +44,8 @@ public function when($value, callable $callback = null, callable $default = null */ public function unless($value, callable $callback = null, callable $default = null) { + $value = $value instanceof Closure ? $value($this) : $value; + if (! $callback) { return new HigherOrderWhenProxy($this, ! $value); } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 0f0a8af49b6d..0c4d65bbacd6 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -4391,6 +4391,30 @@ public function testHigherOrderWhenAndUnless($collection) $this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray()); } + /** + * @dataProvider collectionClassProvider + */ + public function testHigherOrderWhenAndUnlessWithProxy($collection) + { + $data = new $collection(['michael', 'tom']); + + $data = $data->when->contains('michael')->concat(['chris']); + + $this->assertSame(['michael', 'tom', 'chris'], $data->toArray()); + + $data = $data->when->contains('missing')->concat(['adam']); + + $this->assertSame(['michael', 'tom', 'chris'], $data->toArray()); + + $data = $data->unless->contains('missing')->concat(['adam']); + + $this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray()); + + $data = $data->unless->contains('adam')->concat(['bogdan']); + + $this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray()); + } + /** * @dataProvider collectionClassProvider */ diff --git a/tests/Support/SupportConditionableTest.php b/tests/Support/SupportConditionableTest.php index 7a28dc7bd543..3e0166820f8d 100644 --- a/tests/Support/SupportConditionableTest.php +++ b/tests/Support/SupportConditionableTest.php @@ -9,68 +9,148 @@ class SupportConditionableTest extends TestCase { public function testWhenConditionCallback() { + // With static condition $logger = (new ConditionableLogger()) ->when(2, function ($logger, $condition) { $logger->log('when', $condition); - }, function () { + }, function ($logger, $condition) { $logger->log('default', $condition); }); $this->assertSame(['when', 2], $logger->values); + + // With callback condition + $logger = (new ConditionableLogger())->log('init') + ->when(function ($logger) { + return $logger->has('init'); + }, function ($logger, $condition) { + $logger->log('when', $condition); + }, function ($logger, $condition) { + $logger->log('default', $condition); + }); + + $this->assertSame(['init', 'when', true], $logger->values); } public function testWhenDefaultCallback() { + // With static condition $logger = (new ConditionableLogger()) - ->when(null, function () { + ->when(null, function ($logger, $condition) { $logger->log('when', $condition); }, function ($logger, $condition) { $logger->log('default', $condition); }); $this->assertSame(['default', null], $logger->values); + + // With callback condition + $logger = (new ConditionableLogger()) + ->when(function ($logger) { + return $logger->has('missing'); + }, function ($logger, $condition) { + $logger->log('when', $condition); + }, function ($logger, $condition) { + $logger->log('default', $condition); + }); + + $this->assertSame(['default', false], $logger->values); } public function testUnlessConditionCallback() { + // With static condition $logger = (new ConditionableLogger()) ->unless(null, function ($logger, $condition) { $logger->log('unless', $condition); - }, function () { + }, function ($logger, $condition) { $logger->log('default', $condition); }); $this->assertSame(['unless', null], $logger->values); + + // With callback condition + $logger = (new ConditionableLogger()) + ->unless(function ($logger) { + return $logger->has('missing'); + }, function ($logger, $condition) { + $logger->log('unless', $condition); + }, function ($logger, $condition) { + $logger->log('default', $condition); + }); + + $this->assertSame(['unless', false], $logger->values); } public function testUnlessDefaultCallback() { + // With static condition $logger = (new ConditionableLogger()) - ->unless(2, function () { + ->unless(2, function ($logger, $condition) { $logger->log('unless', $condition); }, function ($logger, $condition) { $logger->log('default', $condition); }); $this->assertSame(['default', 2], $logger->values); + + // With callback condition + $logger = (new ConditionableLogger())->log('init') + ->unless(function ($logger) { + return $logger->has('init'); + }, function ($logger, $condition) { + $logger->log('unless', $condition); + }, function ($logger, $condition) { + $logger->log('default', $condition); + }); + + $this->assertSame(['init', 'default', true], $logger->values); } public function testWhenProxy() { + // With static condition $logger = (new ConditionableLogger()) ->when(true)->log('one') ->when(false)->log('two'); $this->assertSame(['one'], $logger->values); + + // With callback condition + $logger = (new ConditionableLogger())->log('init') + ->when(function ($logger) { + return $logger->has('init'); + }) + ->log('one') + ->when(function ($logger) { + return $logger->has('missing'); + }) + ->log('two'); + + $this->assertSame(['init', 'one'], $logger->values); } public function testUnlessProxy() { + // With static condition $logger = (new ConditionableLogger()) ->unless(true)->log('one') ->unless(false)->log('two'); $this->assertSame(['two'], $logger->values); + + // With callback condition + $logger = (new ConditionableLogger())->log('init') + ->unless(function ($logger) { + return $logger->has('init'); + }) + ->log('one') + ->unless(function ($logger) { + return $logger->has('missing'); + }) + ->log('two'); + + $this->assertSame(['init', 'two'], $logger->values); } } @@ -86,4 +166,9 @@ public function log(...$values) return $this; } + + public function has($value) + { + return in_array($value, $this->values); + } } From cc84229a96870027793e11e7e8cf2182fc9fbba1 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 21 Jun 2021 17:49:14 +0200 Subject: [PATCH 148/194] Fix merge conflicts --- .../Providers/ArtisanServiceProvider.php | 38 ++----------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index d59357adbba5..0940a13e006f 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -68,12 +68,8 @@ use Illuminate\Queue\Console\ForgetFailedCommand as ForgetFailedQueueCommand; use Illuminate\Queue\Console\ListenCommand as QueueListenCommand; use Illuminate\Queue\Console\ListFailedCommand as ListFailedQueueCommand; -<<<<<<< HEAD use Illuminate\Queue\Console\PruneBatchesCommand as QueuePruneBatchesCommand; -======= -use Illuminate\Queue\Console\PruneBatchesCommand as PruneBatchesQueueCommand; -use Illuminate\Queue\Console\PruneFailedJobsCommand; ->>>>>>> 8.x +use Illuminate\Queue\Console\PruneFailedJobsCommand as QueuePruneFailedJobsCommand; use Illuminate\Queue\Console\RestartCommand as QueueRestartCommand; use Illuminate\Queue\Console\RetryBatchCommand as QueueRetryBatchCommand; use Illuminate\Queue\Console\RetryCommand as QueueRetryCommand; @@ -99,7 +95,6 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'ConfigCache' => ConfigCacheCommand::class, 'ConfigClear' => ConfigClearCommand::class, 'Db' => DbCommand::class, -<<<<<<< HEAD 'DbWipe' => WipeCommand::class, 'Down' => DownCommand::class, 'Environment' => EnvironmentCommand::class, @@ -116,6 +111,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'QueueForget' => ForgetFailedQueueCommand::class, 'QueueListen' => QueueListenCommand::class, 'QueuePruneBatches' => QueuePruneBatchesCommand::class, + 'QueuePruneFailedJobs' => QueuePruneFailedJobsCommand::class, 'QueueRestart' => QueueRestartCommand::class, 'QueueRetry' => QueueRetryCommand::class, 'QueueRetryBatch' => QueueRetryBatchCommand::class, @@ -125,34 +121,6 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'RouteList' => RouteListCommand::class, 'SchemaDump' => DumpCommand::class, 'Seed' => SeedCommand::class, -======= - 'DbWipe' => 'command.db.wipe', - 'Down' => 'command.down', - 'Environment' => 'command.environment', - 'EventCache' => 'command.event.cache', - 'EventClear' => 'command.event.clear', - 'EventList' => 'command.event.list', - 'KeyGenerate' => 'command.key.generate', - 'Optimize' => 'command.optimize', - 'OptimizeClear' => 'command.optimize.clear', - 'PackageDiscover' => 'command.package.discover', - 'QueueClear' => 'command.queue.clear', - 'QueueFailed' => 'command.queue.failed', - 'QueueFlush' => 'command.queue.flush', - 'QueueForget' => 'command.queue.forget', - 'QueueListen' => 'command.queue.listen', - 'QueuePruneBatches' => 'command.queue.prune-batches', - 'QueuePruneFailedJobs' => 'command.queue.prune-failed-jobs', - 'QueueRestart' => 'command.queue.restart', - 'QueueRetry' => 'command.queue.retry', - 'QueueRetryBatch' => 'command.queue.retry-batch', - 'QueueWork' => 'command.queue.work', - 'RouteCache' => 'command.route.cache', - 'RouteClear' => 'command.route.clear', - 'RouteList' => 'command.route.list', - 'SchemaDump' => 'command.schema.dump', - 'Seed' => 'command.seed', ->>>>>>> 8.x 'ScheduleFinish' => ScheduleFinishCommand::class, 'ScheduleList' => ScheduleListCommand::class, 'ScheduleRun' => ScheduleRunCommand::class, @@ -712,7 +680,7 @@ protected function registerQueuePruneBatchesCommand() protected function registerQueuePruneFailedJobsCommand() { $this->app->singleton('command.queue.prune-failed-jobs', function () { - return new PruneFailedJobsCommand; + return new QueuePruneFailedJobsCommand; }); } From 850182e6e6259b921406437c157aa205d4c12a3f Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Thu, 24 Jun 2021 16:14:03 +0200 Subject: [PATCH 149/194] allow to call BelongsToMany::firstOrNew/Create without parameters (#37791) --- src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index a5166fb4910c..58c64ea5c51a 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -596,7 +596,7 @@ public function findOrNew($id, $columns = ['*']) * @param array $attributes * @return \Illuminate\Database\Eloquent\Model */ - public function firstOrNew(array $attributes) + public function firstOrNew(array $attributes = []) { if (is_null($instance = $this->related->where($attributes)->first())) { $instance = $this->related->newInstance($attributes); @@ -614,7 +614,7 @@ public function firstOrNew(array $attributes) * @param bool $touch * @return \Illuminate\Database\Eloquent\Model */ - public function firstOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true) + public function firstOrCreate(array $attributes = [], array $values = [], array $joining = [], $touch = true) { if (is_null($instance = $this->related->where($attributes)->first())) { $instance = $this->create($attributes + $values, $joining, $touch); From fb332138d0755e51e151cfe4b22c589e7dd414bf Mon Sep 17 00:00:00 2001 From: Chris Fidao Date: Thu, 1 Jul 2021 08:37:29 -0500 Subject: [PATCH 150/194] [9.x] Sesv2client (#37878) * update SesTransport to use SesV2Client * update tests for SesV2Client usage --- src/Illuminate/Mail/MailManager.php | 4 ++-- src/Illuminate/Mail/Transport/SesTransport.php | 14 +++++++------- tests/Mail/MailSesTransportTest.php | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index ad25ff5d7668..353788756130 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -2,7 +2,7 @@ namespace Illuminate\Mail; -use Aws\Ses\SesClient; +use Aws\SesV2\SesV2Client; use Closure; use GuzzleHttp\Client as HttpClient; use Illuminate\Contracts\Mail\Factory as FactoryContract; @@ -271,7 +271,7 @@ protected function createSesTransport(array $config) $config = Arr::except($config, ['transport']); return new SesTransport( - new SesClient($this->addSesCredentials($config)), + new SesV2Client($this->addSesCredentials($config)), $config['options'] ?? [] ); } diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index 76eb2a8a03c3..964fecb8878d 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -2,7 +2,7 @@ namespace Illuminate\Mail\Transport; -use Aws\Ses\SesClient; +use Aws\SesV2\SesV2Client; use Swift_Mime_SimpleMessage; class SesTransport extends Transport @@ -10,7 +10,7 @@ class SesTransport extends Transport /** * The Amazon SES instance. * - * @var \Aws\Ses\SesClient + * @var \Aws\SesV2\SesV2Client */ protected $ses; @@ -24,11 +24,11 @@ class SesTransport extends Transport /** * Create a new SES transport instance. * - * @param \Aws\Ses\SesClient $ses + * @param \Aws\SesV2\SesV2Client $ses * @param array $options * @return void */ - public function __construct(SesClient $ses, $options = []) + public function __construct(SesV2Client $ses, $options = []) { $this->ses = $ses; $this->options = $options; @@ -41,10 +41,10 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul { $this->beforeSendPerformed($message); - $result = $this->ses->sendRawEmail( + $result = $this->ses->sendEmail( array_merge( $this->options, [ - 'Source' => key($message->getSender() ?: $message->getFrom()), + 'FromEmailAddress' => key($message->getSender() ?: $message->getFrom()), 'RawMessage' => [ 'Data' => $message->toString(), ], @@ -65,7 +65,7 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul /** * Get the Amazon SES client for the SesTransport instance. * - * @return \Aws\Ses\SesClient + * @return \Aws\SesV2\SesV2Client */ public function ses() { diff --git a/tests/Mail/MailSesTransportTest.php b/tests/Mail/MailSesTransportTest.php index ee2d4d35b826..a02b0152ca46 100644 --- a/tests/Mail/MailSesTransportTest.php +++ b/tests/Mail/MailSesTransportTest.php @@ -2,7 +2,7 @@ namespace Illuminate\Tests\Mail; -use Aws\Ses\SesClient; +use Aws\SesV2\SesV2Client; use Illuminate\Config\Repository; use Illuminate\Container\Container; use Illuminate\Mail\MailManager; @@ -46,8 +46,8 @@ public function testSend() $message->setTo('me@example.com'); $message->setBcc('you@example.com'); - $client = $this->getMockBuilder(SesClient::class) - ->addMethods(['sendRawEmail']) + $client = $this->getMockBuilder(SesV2Client::class) + ->addMethods(['sendEmail']) ->disableOriginalConstructor() ->getMock(); $transport = new SesTransport($client); @@ -57,9 +57,9 @@ public function testSend() $messageId = Str::random(32); $sendRawEmailMock = new sendRawEmailMock($messageId); $client->expects($this->once()) - ->method('sendRawEmail') + ->method('sendEmail') ->with($this->equalTo([ - 'Source' => 'myself@example.com', + 'FromEmailAddress' => 'myself@example.com', 'RawMessage' => ['Data' => (string) $message], ])) ->willReturn($sendRawEmailMock); @@ -83,7 +83,7 @@ public function testSesLocalConfiguration() 'region' => 'eu-west-1', 'options' => [ 'ConfigurationSetName' => 'Laravel', - 'Tags' => [ + 'EmailTags' => [ ['Name' => 'Laravel', 'Value' => 'Framework'], ], ], @@ -116,7 +116,7 @@ public function testSesLocalConfiguration() $this->assertSame([ 'ConfigurationSetName' => 'Laravel', - 'Tags' => [ + 'EmailTags' => [ ['Name' => 'Laravel', 'Value' => 'Framework'], ], ], $transport->getOptions()); From 8a1a7b526419768256dfafc2f790c94618a906d0 Mon Sep 17 00:00:00 2001 From: Chris Fidao Date: Fri, 2 Jul 2021 11:41:03 -0500 Subject: [PATCH 151/194] [9.x] Bug fix: Use correct parameters to send email through SES via SesV2Client (#37881) * use correct parameters for sending raw email via SES v2 * remove FromEmailAddress parameter --- src/Illuminate/Mail/Transport/SesTransport.php | 5 ++--- tests/Mail/MailSesTransportTest.php | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index 964fecb8878d..cae80810fd20 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -44,9 +44,8 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul $result = $this->ses->sendEmail( array_merge( $this->options, [ - 'FromEmailAddress' => key($message->getSender() ?: $message->getFrom()), - 'RawMessage' => [ - 'Data' => $message->toString(), + 'Content' => [ + 'Raw' => ['Data' => $message->toString()], ], ] ) diff --git a/tests/Mail/MailSesTransportTest.php b/tests/Mail/MailSesTransportTest.php index a02b0152ca46..c08110ffdb73 100644 --- a/tests/Mail/MailSesTransportTest.php +++ b/tests/Mail/MailSesTransportTest.php @@ -59,8 +59,9 @@ public function testSend() $client->expects($this->once()) ->method('sendEmail') ->with($this->equalTo([ - 'FromEmailAddress' => 'myself@example.com', - 'RawMessage' => ['Data' => (string) $message], + 'Content' => [ + 'Raw' => ['Data' => (string) $message], + ], ])) ->willReturn($sendRawEmailMock); From 03fa6a2566626920738d2c27eec20aad75be4561 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 7 Jul 2021 19:10:11 +0200 Subject: [PATCH 152/194] [9.x] Update to Symfony v6 and drop PHP 7.4 support (#37941) * revert * revert * PHP 8 only * Update setHidden * Disable windows tests for now * Replace removed constant * re-enable windows tests * Bump minimum Mockery --- .github/workflows/tests.yml | 4 ++-- composer.json | 22 +++++++++++----------- src/Illuminate/Console/Command.php | 10 ---------- tests/Routing/RoutingUrlGeneratorTest.php | 2 +- 4 files changed, 14 insertions(+), 24 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f6b96a7042e1..0ac8efa8d54d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: true matrix: - php: ['7.4', '8.0'] + php: ['8.0'] stability: [prefer-lowest, prefer-stable] include: - php: '8.1' @@ -89,7 +89,7 @@ jobs: strategy: fail-fast: true matrix: - php: ['7.4', '8.0'] + php: ['8.0'] stability: [prefer-lowest, prefer-stable] include: - php: '8.1' diff --git a/composer.json b/composer.json index a27414ac8eef..d13db5bd0539 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", @@ -31,15 +31,15 @@ "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", "swiftmailer/swiftmailer": "^6.2.7", - "symfony/console": "^5.3", - "symfony/error-handler": "^5.3", - "symfony/finder": "^5.3", - "symfony/http-foundation": "^5.3", - "symfony/http-kernel": "^5.3", - "symfony/mime": "^5.3", - "symfony/process": "^5.3", - "symfony/routing": "^5.3", - "symfony/var-dumper": "^5.3", + "symfony/console": "^6.0", + "symfony/error-handler": "^6.0", + "symfony/finder": "^6.0", + "symfony/http-foundation": "^6.0", + "symfony/http-kernel": "^6.0", + "symfony/mime": "^6.0", + "symfony/process": "^6.0", + "symfony/routing": "^6.0", + "symfony/var-dumper": "^6.0", "tijsverkoyen/css-to-inline-styles": "^2.2.2", "vlucas/phpdotenv": "^5.3", "voku/portable-ascii": "^1.4.8" @@ -85,7 +85,7 @@ "league/flysystem-aws-s3-v3": "^2.0", "league/flysystem-ftp": "^2.0", "league/flysystem-sftp": "^2.0", - "mockery/mockery": "^1.4.2", + "mockery/mockery": "^1.4.3", "orchestra/testbench-core": "^7.0", "pda/pheanstalk": "^4.0", "phpunit/phpunit": "^9.4", diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 4ad47351e4a1..9ec134cf39b5 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -169,16 +169,6 @@ public function isHidden() return $this->hidden; } - /** - * {@inheritdoc} - */ - public function setHidden(bool $hidden) - { - parent::setHidden($this->hidden = $hidden); - - return $this; - } - /** * Get the Laravel application instance. * diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index 676f609b15fa..267a318cf3ba 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -508,7 +508,7 @@ public function testHttpsRoutesWithDomains() public function testRoutesWithDomainsThroughProxy() { - Request::setTrustedProxies(['10.0.0.1'], SymfonyRequest::HEADER_X_FORWARDED_ALL); + Request::setTrustedProxies(['10.0.0.1'], SymfonyRequest::HEADER_X_FORWARDED_FOR | SymfonyRequest::HEADER_X_FORWARDED_HOST | SymfonyRequest::HEADER_X_FORWARDED_PORT | SymfonyRequest::HEADER_X_FORWARDED_PROTO); $url = new UrlGenerator( $routes = new RouteCollection, From f15b9ae12c45152bf7377104b8edb270343cbe10 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 7 Jul 2021 18:12:22 +0100 Subject: [PATCH 153/194] Fixed typo in `PruneCommand` --- src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index fcb69b5035f9..5961d56c2720 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -96,7 +96,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'ConfigCache' => ConfigCacheCommand::class, 'ConfigClear' => ConfigClearCommand::class, 'Db' => DbCommand::class, - 'DbPrune' => Prune::class, + 'DbPrune' => PruneCommand::class, 'DbWipe' => WipeCommand::class, 'Down' => DownCommand::class, 'Environment' => EnvironmentCommand::class, From 32a0e8e68c45e245746714055727ebc0c0d9f891 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sat, 10 Jul 2021 17:23:50 +0200 Subject: [PATCH 154/194] [9.x] Drop CommonMark v1 support (#37953) * Update to CommonMark v2 * Update composer.json files --- composer.json | 2 +- src/Illuminate/Mail/Markdown.php | 11 ++++++++--- src/Illuminate/Mail/composer.json | 2 +- src/Illuminate/Support/composer.json | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 23959a64aa6e..94d9fe4aad7e 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "doctrine/inflector": "^2.0", "dragonmantank/cron-expression": "^3.1", "egulias/email-validator": "^3.1", - "league/commonmark": "^1.3|^2.0", + "league/commonmark": "^2.0", "league/flysystem": "^2.0", "monolog/monolog": "^2.0", "nesbot/carbon": "^2.31", diff --git a/src/Illuminate/Mail/Markdown.php b/src/Illuminate/Mail/Markdown.php index 9bd083605c60..75c254f1168c 100644 --- a/src/Illuminate/Mail/Markdown.php +++ b/src/Illuminate/Mail/Markdown.php @@ -5,8 +5,10 @@ use Illuminate\Contracts\View\Factory as ViewFactory; use Illuminate\Support\HtmlString; use Illuminate\Support\Str; -use League\CommonMark\CommonMarkConverter; +use League\CommonMark\Environment\Environment; +use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; use League\CommonMark\Extension\Table\TableExtension; +use League\CommonMark\MarkdownConverter; use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles; class Markdown @@ -103,11 +105,14 @@ public function renderText($view, array $data = []) */ public static function parse($text) { - $converter = new CommonMarkConverter([ + $environment = new Environment([ 'allow_unsafe_links' => false, ]); - $converter->getEnvironment()->addExtension(new TableExtension()); + $environment->addExtension(new CommonMarkCoreExtension); + $environment->addExtension(new TableExtension); + + $converter = new MarkdownConverter($environment); return new HtmlString((string) $converter->convertToHtml($text)); } diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index acd447060506..684bcd214470 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -21,7 +21,7 @@ "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "league/commonmark": "^1.3|^2.0", + "league/commonmark": "^2.0", "psr/log": "^1.0", "swiftmailer/swiftmailer": "^6.2.7", "tijsverkoyen/css-to-inline-styles": "^2.2.2" diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 59298162595b..ebeb607d7083 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -42,7 +42,7 @@ }, "suggest": { "illuminate/filesystem": "Required to use the composer class (^9.0).", - "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^1.3|^2.0).", + "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0).", "ramsey/uuid": "Required to use Str::uuid() (^4.0).", "symfony/process": "Required to use the composer class (^5.3).", "symfony/var-dumper": "Required to use the dd function (^5.3).", From 7bfc3154dce4576aca44054e8c7359ee2346d6f6 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 13 Jul 2021 15:39:16 +0200 Subject: [PATCH 155/194] Remove CursorPaginationException (#37995) --- .../Pagination/CursorPaginationException.php | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/Illuminate/Pagination/CursorPaginationException.php diff --git a/src/Illuminate/Pagination/CursorPaginationException.php b/src/Illuminate/Pagination/CursorPaginationException.php deleted file mode 100644 index b12ca607f185..000000000000 --- a/src/Illuminate/Pagination/CursorPaginationException.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Thu, 15 Jul 2021 12:05:37 +0200 Subject: [PATCH 156/194] Use string based accessor for Schema facade --- .../Database/DatabaseServiceProvider.php | 4 +++ src/Illuminate/Foundation/Application.php | 1 + src/Illuminate/Support/Facades/Facade.php | 25 ++++++++++++------- .../Support/Facades/RateLimiter.php | 2 +- src/Illuminate/Support/Facades/Schema.php | 13 +++++++--- .../DatabaseMigratorIntegrationTest.php | 3 +++ 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Database/DatabaseServiceProvider.php b/src/Illuminate/Database/DatabaseServiceProvider.php index 9f2ab18503e1..f22b71ce3285 100755 --- a/src/Illuminate/Database/DatabaseServiceProvider.php +++ b/src/Illuminate/Database/DatabaseServiceProvider.php @@ -72,6 +72,10 @@ protected function registerConnectionServices() return $app['db']->connection(); }); + $this->app->bind('db.schema', function ($app) { + return $app['db']->connection()->getSchemaBuilder(); + }); + $this->app->singleton('db.transactions', function ($app) { return new DatabaseTransactionsManager; }); diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 1759d6cfb5e0..21fcbacc6ebb 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -1304,6 +1304,7 @@ public function registerCoreContainerAliases() 'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class], 'db' => [\Illuminate\Database\DatabaseManager::class, \Illuminate\Database\ConnectionResolverInterface::class], 'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class], + 'db.schema' => [\Illuminate\Database\Schema\Builder::class], 'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\StringEncrypter::class], 'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class], 'files' => [\Illuminate\Filesystem\Filesystem::class], diff --git a/src/Illuminate/Support/Facades/Facade.php b/src/Illuminate/Support/Facades/Facade.php index cb11ba7cfbfd..7f2cdcc56d96 100755 --- a/src/Illuminate/Support/Facades/Facade.php +++ b/src/Illuminate/Support/Facades/Facade.php @@ -23,6 +23,13 @@ abstract class Facade */ protected static $resolvedInstance; + /** + * Determine if the resolved facade should be cached. + * + * @var bool + */ + protected static $cached = true; + /** * Run a Closure when the facade has been resolved. * @@ -84,8 +91,8 @@ public static function shouldReceive() $name = static::getFacadeAccessor(); $mock = static::isMock() - ? static::$resolvedInstance[$name] - : static::createFreshMockInstance(); + ? static::$resolvedInstance[$name] + : static::createFreshMockInstance(); return $mock->shouldReceive(...func_get_args()); } @@ -197,21 +204,21 @@ protected static function getFacadeAccessor() /** * Resolve the facade root instance from the container. * - * @param object|string $name + * @param string $name * @return mixed */ protected static function resolveFacadeInstance($name) { - if (is_object($name)) { - return $name; - } - if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } - + dump(array_keys(static::$resolvedInstance)); if (static::$app) { - return static::$resolvedInstance[$name] = static::$app[$name]; + if (static::$cached) { + return static::$resolvedInstance[$name] = static::$app[$name]; + } + + return static::$app[$name]; } } diff --git a/src/Illuminate/Support/Facades/RateLimiter.php b/src/Illuminate/Support/Facades/RateLimiter.php index 23b1a31e1538..1c8b6e3ce7b1 100644 --- a/src/Illuminate/Support/Facades/RateLimiter.php +++ b/src/Illuminate/Support/Facades/RateLimiter.php @@ -24,6 +24,6 @@ class RateLimiter extends Facade */ protected static function getFacadeAccessor() { - return 'Illuminate\Cache\RateLimiter'; + return \Illuminate\Cache\RateLimiter::class; } } diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 896e1764cd83..8b4f821f5944 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -24,6 +24,13 @@ */ class Schema extends Facade { + /** + * Determine if the resolved facade should be cached. + * + * @var bool + */ + protected static $cached = false; + /** * Get a schema builder instance for a connection. * @@ -36,12 +43,12 @@ public static function connection($name) } /** - * Get a schema builder instance for the default connection. + * Get the registered name of the component. * - * @return \Illuminate\Database\Schema\Builder + * @return string */ protected static function getFacadeAccessor() { - return static::$app['db']->connection()->getSchemaBuilder(); + return 'db.schema'; } } diff --git a/tests/Database/DatabaseMigratorIntegrationTest.php b/tests/Database/DatabaseMigratorIntegrationTest.php index 3ee9815cadcf..060482d52d68 100644 --- a/tests/Database/DatabaseMigratorIntegrationTest.php +++ b/tests/Database/DatabaseMigratorIntegrationTest.php @@ -41,6 +41,9 @@ protected function setUp(): void $container = new Container; $container->instance('db', $db->getDatabaseManager()); + $container->bind('db.schema', function ($app) { + return $app['db']->connection()->getSchemaBuilder(); + }); Facade::setFacadeApplication($container); From 67f6542557f6d3a64bf693795f87ae3634bd8503 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 15 Jul 2021 12:52:37 +0200 Subject: [PATCH 157/194] Update Facade.php --- src/Illuminate/Support/Facades/Facade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Facade.php b/src/Illuminate/Support/Facades/Facade.php index 7f2cdcc56d96..fefade1bc1e2 100755 --- a/src/Illuminate/Support/Facades/Facade.php +++ b/src/Illuminate/Support/Facades/Facade.php @@ -212,7 +212,7 @@ protected static function resolveFacadeInstance($name) if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } - dump(array_keys(static::$resolvedInstance)); + if (static::$app) { if (static::$cached) { return static::$resolvedInstance[$name] = static::$app[$name]; From 5d57904866c6f79d5d6eaad054aaf7fe319ba6ce Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 15 Jul 2021 12:54:59 +0200 Subject: [PATCH 158/194] Update Facade.php --- src/Illuminate/Support/Facades/Facade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Facade.php b/src/Illuminate/Support/Facades/Facade.php index fefade1bc1e2..1eb01f4eb1c5 100755 --- a/src/Illuminate/Support/Facades/Facade.php +++ b/src/Illuminate/Support/Facades/Facade.php @@ -24,7 +24,7 @@ abstract class Facade protected static $resolvedInstance; /** - * Determine if the resolved facade should be cached. + * Determine if the resolved instance should be cached. * * @var bool */ From 331e53acb734c7669302842ec6e400f74df1673a Mon Sep 17 00:00:00 2001 From: Tom Schlick Date: Thu, 15 Jul 2021 09:35:37 -0400 Subject: [PATCH 159/194] [9.x] PHP8 string functions for Str class (#38011) * use str_contains over mb_strpos * use str_ends_with over substr * use str_starts_with over strncmp --- src/Illuminate/Support/Str.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 46d15353882f..260b25a8ef6b 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -187,7 +187,7 @@ public static function contains($haystack, $needles, $ignoreCase = false) } foreach ((array) $needles as $needle) { - if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { + if ($needle !== '' && str_contains($haystack, $needle)) { return true; } } @@ -231,7 +231,7 @@ public static function endsWith($haystack, $needles) foreach ((array) $needles as $needle) { if ( $needle !== '' && $needle !== null - && substr($haystack, -strlen($needle)) === (string) $needle + && str_ends_with($haystack, $needle) ) { return true; } @@ -763,7 +763,7 @@ public static function snake($value, $delimiter = '_') public static function startsWith($haystack, $needles) { foreach ((array) $needles as $needle) { - if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { + if ((string) $needle !== '' && str_starts_with($haystack, $needle)) { return true; } } From f62e503bc30ba1456260a1512d4af02617217d36 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 16 Jul 2021 08:33:57 -0500 Subject: [PATCH 160/194] formatting --- src/Illuminate/Support/Facades/Facade.php | 2 +- src/Illuminate/Support/Facades/Schema.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Facades/Facade.php b/src/Illuminate/Support/Facades/Facade.php index 1eb01f4eb1c5..d3e4300e4309 100755 --- a/src/Illuminate/Support/Facades/Facade.php +++ b/src/Illuminate/Support/Facades/Facade.php @@ -24,7 +24,7 @@ abstract class Facade protected static $resolvedInstance; /** - * Determine if the resolved instance should be cached. + * Indicates if the resolved instance should be cached. * * @var bool */ diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 8b4f821f5944..748f7f7127d8 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -25,7 +25,7 @@ class Schema extends Facade { /** - * Determine if the resolved facade should be cached. + * Indicates if the resolved facade should be cached. * * @var bool */ From 3ec5bdc001759506f3e218a5ac471903e3186011 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Fri, 16 Jul 2021 10:24:13 -0400 Subject: [PATCH 161/194] [9.x] Query builder interface (#37956) * Initial extraction of contract and trait * Add support for MorphTo macro buffer * Improved docblocks * A little refactoring * Add inheritdoc statements * Update two more passthru methods * Removed duplicate macroBuffer logic * Rename query builder contract * Remove extra space from inheritdoc tags * Fix issue with contract name collision * Remove extra space in inheritdoc * Remove space from last inheritdoc blocks * Revert import alias to QueryBuilder * formatting Co-authored-by: Taylor Otwell --- .../Contracts/Database/Query/Builder.php | 1079 +++++++++++++++ src/Illuminate/Database/Eloquent/Builder.php | 48 +- .../Concerns/DecoratesQueryBuilder.php | 1227 +++++++++++++++++ .../Database/Eloquent/Relations/MorphTo.php | 42 +- .../Database/Eloquent/Relations/Relation.php | 23 +- src/Illuminate/Database/Query/Builder.php | 759 ++-------- 6 files changed, 2492 insertions(+), 686 deletions(-) create mode 100644 src/Illuminate/Contracts/Database/Query/Builder.php create mode 100644 src/Illuminate/Database/Eloquent/Concerns/DecoratesQueryBuilder.php diff --git a/src/Illuminate/Contracts/Database/Query/Builder.php b/src/Illuminate/Contracts/Database/Query/Builder.php new file mode 100644 index 000000000000..ec0d50ab2fcc --- /dev/null +++ b/src/Illuminate/Contracts/Database/Query/Builder.php @@ -0,0 +1,1079 @@ +callNamedScope($method, $parameters); } - if (in_array($method, $this->passthru)) { - return $this->toBase()->{$method}(...$parameters); - } - $this->forwardCallTo($this->query, $method, $parameters); return $this; diff --git a/src/Illuminate/Database/Eloquent/Concerns/DecoratesQueryBuilder.php b/src/Illuminate/Database/Eloquent/Concerns/DecoratesQueryBuilder.php new file mode 100644 index 000000000000..b22c5b831a14 --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Concerns/DecoratesQueryBuilder.php @@ -0,0 +1,1227 @@ +forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function selectSub($query, $as) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function selectRaw($expression, array $bindings = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function fromSub($query, $as) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function fromRaw($expression, $bindings = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function addSelect($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function distinct() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function from($table, $as = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function joinWhere($table, $first, $operator, $second, $type = 'inner') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function leftJoin($table, $first, $operator = null, $second = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function leftJoinWhere($table, $first, $operator, $second) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function leftJoinSub($query, $as, $first, $operator = null, $second = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function rightJoin($table, $first, $operator = null, $second = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function rightJoinWhere($table, $first, $operator, $second) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function rightJoinSub($query, $as, $first, $operator = null, $second = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function crossJoin($table, $first = null, $operator = null, $second = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function crossJoinSub($query, $as) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function mergeWheres($wheres, $bindings) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function where($column, $operator = null, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function prepareValueAndOperator($value, $operator, $useDefault = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhere($column, $operator = null, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereColumn($first, $operator = null, $second = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereColumn($first, $operator = null, $second = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereRaw($sql, $bindings = [], $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereRaw($sql, $bindings = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereIn($column, $values, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereIn($column, $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNotIn($column, $values, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereNotIn($column, $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereIntegerInRaw($column, $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereIntegerNotInRaw($column, $values, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereIntegerNotInRaw($column, $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNull($columns, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereNull($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNotNull($columns, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereBetweenColumns($column, array $values, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereBetween($column, iterable $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereBetweenColumns($column, array $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNotBetween($column, iterable $values, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNotBetweenColumns($column, array $values, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereNotBetween($column, iterable $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereNotBetweenColumns($column, array $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereNotNull($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereDate($column, $operator, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereDate($column, $operator, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereTime($column, $operator, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereTime($column, $operator, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereDay($column, $operator, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereDay($column, $operator, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereMonth($column, $operator, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereMonth($column, $operator, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereYear($column, $operator, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereYear($column, $operator, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNested(Closure $callback, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function addNestedWhereQuery($query, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereExists(Closure $callback, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereExists(Closure $callback, $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereNotExists(Closure $callback, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereNotExists(Closure $callback) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereRowValues($columns, $operator, $values, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereRowValues($columns, $operator, $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereJsonContains($column, $value, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereJsonContains($column, $value) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereJsonDoesntContain($column, $value, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereJsonDoesntContain($column, $value) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function whereJsonLength($column, $operator, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orWhereJsonLength($column, $operator, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function groupBy(...$groups) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function groupByRaw($sql, array $bindings = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function having($column, $operator = null, $value = null, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orHaving($column, $operator = null, $value = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function havingNull($columns, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function orHavingNull($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function havingNotNull($columns, $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function orHavingNotNull($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function havingBetween($column, array $values, $boolean = 'and', $not = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function havingRaw($sql, array $bindings = [], $boolean = 'and') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function orHavingRaw($sql, array $bindings = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function orderBy($column, $direction = 'asc') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function orderByDesc($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function latest($column = 'created_at') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function oldest($column = 'created_at') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function inRandomOrder($seed = '') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function orderByRaw($sql, $bindings = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function skip($value) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function offset($value) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function take($value) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function limit($value) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function forPage($page, $perPage = 15) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function reorder($column = null, $direction = 'asc') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function union($query, $all = false) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function unionAll($query) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function lock($value = true) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function lockForUpdate() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function sharedLock() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function toSql() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function find($id, $columns = ['*']) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function value($column) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function get($columns = ['*']) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function cursor() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function pluck($column, $key = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function implode($column, $glue = '') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function exists() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function doesntExist() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function existsOr(Closure $callback) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function doesntExistOr(Closure $callback) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function count($columns = '*') + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function min($column) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function max($column) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function sum($column) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function avg($column) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function average($column) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function aggregate($function, $columns = ['*']) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function numericAggregate($function, $columns = ['*']) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function insert(array $values) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function insertOrIgnore(array $values) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function insertGetId(array $values, $sequence = null) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function insertUsing(array $columns, $query) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function update(array $values) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function updateOrInsert(array $attributes, array $values = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function upsert(array $values, $uniqueBy, $update = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function increment($column, $amount = 1, array $extra = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function decrement($column, $amount = 1, array $extra = []) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function delete($id = null) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function truncate() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function newQuery() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function raw($value) + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function getBindings() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function getRawBindings() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function setBindings(array $bindings, $type = 'where') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function addBinding($value, $type = 'where') + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function mergeBindings(Builder $query) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function cleanBindings(array $bindings) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function getConnection() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function getProcessor() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function getGrammar() + { + return $this->toBase()->{__FUNCTION__}(...func_get_args()); + } + + /** + * @inheritdoc + */ + public function useWritePdo() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function clone() + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function cloneWithout(array $properties) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * @inheritdoc + */ + public function cloneWithoutBindings(array $except) + { + return $this->forwardCallToQueryBuilder(__FUNCTION__, func_get_args()); + } + + /** + * Handle dynamic method calls to the query builder. + * + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + return $this->forwardCallToQueryBuilder($method, $parameters); + } + + /** + * Forward the given method to the query builder. + * + * @param string $method + * @param array $parameters + * @return static|mixed + */ + protected function forwardCallToQueryBuilder($method, $parameters) + { + $result = $this->forwardCallTo($this->query, $method, $parameters); + + if ($result === $this->query) { + return $this; + } + + return $result; + } +} diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index 262741f30cfb..811853fb0c61 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -79,6 +79,46 @@ public function __construct(Builder $query, Model $parent, $foreignKey, $ownerKe parent::__construct($query, $parent, $foreignKey, $ownerKey, $relation); } + /** + * {@inheritdoc} + */ + public function select($columns = ['*']) + { + $this->macroBuffer[] = ['method' => 'select', 'parameters' => [$columns]]; + + return parent::select($columns); + } + + /** + * {@inheritdoc} + */ + public function selectRaw($expression, array $bindings = []) + { + $this->macroBuffer[] = ['method' => 'selectRaw', 'parameters' => [$expression, $bindings]]; + + return parent::selectRaw($expression, $bindings); + } + + /** + * {@inheritdoc} + */ + public function selectSub($query, $as) + { + $this->macroBuffer[] = ['method' => 'selectSub', 'parameters' => [$query, $as]]; + + return parent::selectSub($query, $as); + } + + /** + * {@inheritdoc} + */ + public function addSelect($column) + { + $this->macroBuffer[] = ['method' => 'addSelect', 'parameters' => [$column]]; + + return parent::addSelect($column); + } + /** * Set the constraints for an eager load of the relation. * @@ -377,7 +417,7 @@ public function __call($method, $parameters) try { $result = parent::__call($method, $parameters); - if (in_array($method, ['select', 'selectRaw', 'selectSub', 'addSelect', 'withoutGlobalScopes'])) { + if ($method === 'withoutGlobalScopes') { $this->macroBuffer[] = compact('method', 'parameters'); } diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 7fe9f3e9fa82..e30f9875cfda 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -3,8 +3,10 @@ namespace Illuminate\Database\Eloquent\Relations; use Closure; +use Illuminate\Contracts\Database\Query\Builder as BuilderContract; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\Concerns\DecoratesQueryBuilder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\MultipleRecordsFoundException; @@ -13,13 +15,10 @@ use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Support\Traits\Macroable; -/** - * @mixin \Illuminate\Database\Eloquent\Builder - */ -abstract class Relation +abstract class Relation implements BuilderContract { - use ForwardsCalls, Macroable { - __call as macroCall; + use DecoratesQueryBuilder, ForwardsCalls, Macroable { + Macroable::__call as macroCall; } /** @@ -294,9 +293,21 @@ public function getQuery() /** * Get the base query builder driving the Eloquent builder. * + * @deprecated Use toBase() instead + * * @return \Illuminate\Database\Query\Builder */ public function getBaseQuery() + { + return $this->toBase(); + } + + /** + * Get a base query builder instance. + * + * @return \Illuminate\Database\Query\Builder + */ + public function toBase() { return $this->query->getQuery(); } diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 925fb903a1e5..710e5c48f799 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -4,6 +4,7 @@ use Closure; use DateTimeInterface; +use Illuminate\Contracts\Database\Query\Builder as BuilderContract; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Concerns\BuildsQueries; use Illuminate\Database\Concerns\ExplainsQueries; @@ -22,7 +23,7 @@ use InvalidArgumentException; use RuntimeException; -class Builder +class Builder implements BuilderContract { use BuildsQueries, ExplainsQueries, ForwardsCalls, Macroable { __call as macroCall; @@ -226,10 +227,7 @@ public function __construct(ConnectionInterface $connection, } /** - * Set the columns to be selected. - * - * @param array|mixed $columns - * @return $this + * {@inheritdoc} */ public function select($columns = ['*']) { @@ -249,13 +247,7 @@ public function select($columns = ['*']) } /** - * Add a subselect expression to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query - * @param string $as - * @return $this - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function selectSub($query, $as) { @@ -267,11 +259,7 @@ public function selectSub($query, $as) } /** - * Add a new "raw" select expression to the query. - * - * @param string $expression - * @param array $bindings - * @return $this + * {@inheritdoc} */ public function selectRaw($expression, array $bindings = []) { @@ -285,13 +273,7 @@ public function selectRaw($expression, array $bindings = []) } /** - * Makes "from" fetch from a subquery. - * - * @param \Closure|\Illuminate\Database\Query\Builder|string $query - * @param string $as - * @return $this - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function fromSub($query, $as) { @@ -301,11 +283,7 @@ public function fromSub($query, $as) } /** - * Add a raw from clause to the query. - * - * @param string $expression - * @param mixed $bindings - * @return $this + * {@inheritdoc} */ public function fromRaw($expression, $bindings = []) { @@ -380,10 +358,7 @@ protected function prependDatabaseNameIfCrossDatabaseQuery($query) } /** - * Add a new select column to the query. - * - * @param array|mixed $column - * @return $this + * {@inheritdoc} */ public function addSelect($column) { @@ -405,9 +380,7 @@ public function addSelect($column) } /** - * Force the query to only return distinct results. - * - * @return $this + * {@inheritdoc} */ public function distinct() { @@ -423,11 +396,7 @@ public function distinct() } /** - * Set the table which the query is targeting. - * - * @param \Closure|\Illuminate\Database\Query\Builder|string $table - * @param string|null $as - * @return $this + * {@inheritdoc} */ public function from($table, $as = null) { @@ -441,15 +410,7 @@ public function from($table, $as = null) } /** - * Add a join clause to the query. - * - * @param string $table - * @param \Closure|string $first - * @param string|null $operator - * @param string|null $second - * @param string $type - * @param bool $where - * @return $this + * {@inheritdoc} */ public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false) { @@ -481,14 +442,7 @@ public function join($table, $first, $operator = null, $second = null, $type = ' } /** - * Add a "join where" clause to the query. - * - * @param string $table - * @param \Closure|string $first - * @param string $operator - * @param string $second - * @param string $type - * @return $this + * {@inheritdoc} */ public function joinWhere($table, $first, $operator, $second, $type = 'inner') { @@ -496,18 +450,7 @@ public function joinWhere($table, $first, $operator, $second, $type = 'inner') } /** - * Add a subquery join clause to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query - * @param string $as - * @param \Closure|string $first - * @param string|null $operator - * @param string|null $second - * @param string $type - * @param bool $where - * @return $this - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false) { @@ -521,13 +464,7 @@ public function joinSub($query, $as, $first, $operator = null, $second = null, $ } /** - * Add a left join to the query. - * - * @param string $table - * @param \Closure|string $first - * @param string|null $operator - * @param string|null $second - * @return $this + * {@inheritdoc} */ public function leftJoin($table, $first, $operator = null, $second = null) { @@ -535,13 +472,7 @@ public function leftJoin($table, $first, $operator = null, $second = null) } /** - * Add a "join where" clause to the query. - * - * @param string $table - * @param \Closure|string $first - * @param string $operator - * @param string $second - * @return $this + * {@inheritdoc} */ public function leftJoinWhere($table, $first, $operator, $second) { @@ -549,14 +480,7 @@ public function leftJoinWhere($table, $first, $operator, $second) } /** - * Add a subquery left join to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query - * @param string $as - * @param \Closure|string $first - * @param string|null $operator - * @param string|null $second - * @return $this + * {@inheritdoc} */ public function leftJoinSub($query, $as, $first, $operator = null, $second = null) { @@ -564,13 +488,7 @@ public function leftJoinSub($query, $as, $first, $operator = null, $second = nul } /** - * Add a right join to the query. - * - * @param string $table - * @param \Closure|string $first - * @param string|null $operator - * @param string|null $second - * @return $this + * {@inheritdoc} */ public function rightJoin($table, $first, $operator = null, $second = null) { @@ -578,13 +496,7 @@ public function rightJoin($table, $first, $operator = null, $second = null) } /** - * Add a "right join where" clause to the query. - * - * @param string $table - * @param \Closure|string $first - * @param string $operator - * @param string $second - * @return $this + * {@inheritdoc} */ public function rightJoinWhere($table, $first, $operator, $second) { @@ -592,14 +504,7 @@ public function rightJoinWhere($table, $first, $operator, $second) } /** - * Add a subquery right join to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query - * @param string $as - * @param \Closure|string $first - * @param string|null $operator - * @param string|null $second - * @return $this + * {@inheritdoc} */ public function rightJoinSub($query, $as, $first, $operator = null, $second = null) { @@ -607,13 +512,7 @@ public function rightJoinSub($query, $as, $first, $operator = null, $second = nu } /** - * Add a "cross join" clause to the query. - * - * @param string $table - * @param \Closure|string|null $first - * @param string|null $operator - * @param string|null $second - * @return $this + * {@inheritdoc} */ public function crossJoin($table, $first = null, $operator = null, $second = null) { @@ -627,11 +526,7 @@ public function crossJoin($table, $first = null, $operator = null, $second = nul } /** - * Add a subquery cross join to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|string $query - * @param string $as - * @return $this + * {@inheritdoc} */ public function crossJoinSub($query, $as) { @@ -660,11 +555,7 @@ protected function newJoinClause(self $parentQuery, $type, $table) } /** - * Merge an array of where clauses and bindings. - * - * @param array $wheres - * @param array $bindings - * @return void + * {@inheritdoc} */ public function mergeWheres($wheres, $bindings) { @@ -673,16 +564,12 @@ public function mergeWheres($wheres, $bindings) $this->bindings['where'] = array_values( array_merge($this->bindings['where'], (array) $bindings) ); + + return $this; } /** - * Add a basic where clause to the query. - * - * @param \Closure|string|array $column - * @param mixed $operator - * @param mixed $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function where($column, $operator = null, $value = null, $boolean = 'and') { @@ -787,14 +674,7 @@ protected function addArrayOfWheres($column, $boolean, $method = 'where') } /** - * Prepare the value and operator for a where clause. - * - * @param string $value - * @param string $operator - * @param bool $useDefault - * @return array - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function prepareValueAndOperator($value, $operator, $useDefault = false) { @@ -835,12 +715,7 @@ protected function invalidOperator($operator) } /** - * Add an "or where" clause to the query. - * - * @param \Closure|string|array $column - * @param mixed $operator - * @param mixed $value - * @return $this + * {@inheritdoc} */ public function orWhere($column, $operator = null, $value = null) { @@ -852,13 +727,7 @@ public function orWhere($column, $operator = null, $value = null) } /** - * Add a "where" clause comparing two columns to the query. - * - * @param string|array $first - * @param string|null $operator - * @param string|null $second - * @param string|null $boolean - * @return $this + * {@inheritdoc} */ public function whereColumn($first, $operator = null, $second = null, $boolean = 'and') { @@ -889,12 +758,7 @@ public function whereColumn($first, $operator = null, $second = null, $boolean = } /** - * Add an "or where" clause comparing two columns to the query. - * - * @param string|array $first - * @param string|null $operator - * @param string|null $second - * @return $this + * {@inheritdoc} */ public function orWhereColumn($first, $operator = null, $second = null) { @@ -902,12 +766,7 @@ public function orWhereColumn($first, $operator = null, $second = null) } /** - * Add a raw where clause to the query. - * - * @param string $sql - * @param mixed $bindings - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereRaw($sql, $bindings = [], $boolean = 'and') { @@ -919,11 +778,7 @@ public function whereRaw($sql, $bindings = [], $boolean = 'and') } /** - * Add a raw or where clause to the query. - * - * @param string $sql - * @param mixed $bindings - * @return $this + * {@inheritdoc} */ public function orWhereRaw($sql, $bindings = []) { @@ -931,13 +786,7 @@ public function orWhereRaw($sql, $bindings = []) } /** - * Add a "where in" clause to the query. - * - * @param string $column - * @param mixed $values - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereIn($column, $values, $boolean = 'and', $not = false) { @@ -972,11 +821,7 @@ public function whereIn($column, $values, $boolean = 'and', $not = false) } /** - * Add an "or where in" clause to the query. - * - * @param string $column - * @param mixed $values - * @return $this + * {@inheritdoc} */ public function orWhereIn($column, $values) { @@ -984,12 +829,7 @@ public function orWhereIn($column, $values) } /** - * Add a "where not in" clause to the query. - * - * @param string $column - * @param mixed $values - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereNotIn($column, $values, $boolean = 'and') { @@ -997,11 +837,7 @@ public function whereNotIn($column, $values, $boolean = 'and') } /** - * Add an "or where not in" clause to the query. - * - * @param string $column - * @param mixed $values - * @return $this + * {@inheritdoc} */ public function orWhereNotIn($column, $values) { @@ -1009,13 +845,7 @@ public function orWhereNotIn($column, $values) } /** - * Add a "where in raw" clause for integer values to the query. - * - * @param string $column - * @param \Illuminate\Contracts\Support\Arrayable|array $values - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false) { @@ -1035,11 +865,7 @@ public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = fal } /** - * Add an "or where in raw" clause for integer values to the query. - * - * @param string $column - * @param \Illuminate\Contracts\Support\Arrayable|array $values - * @return $this + * {@inheritdoc} */ public function orWhereIntegerInRaw($column, $values) { @@ -1047,12 +873,7 @@ public function orWhereIntegerInRaw($column, $values) } /** - * Add a "where not in raw" clause for integer values to the query. - * - * @param string $column - * @param \Illuminate\Contracts\Support\Arrayable|array $values - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereIntegerNotInRaw($column, $values, $boolean = 'and') { @@ -1060,11 +881,7 @@ public function whereIntegerNotInRaw($column, $values, $boolean = 'and') } /** - * Add an "or where not in raw" clause for integer values to the query. - * - * @param string $column - * @param \Illuminate\Contracts\Support\Arrayable|array $values - * @return $this + * {@inheritdoc} */ public function orWhereIntegerNotInRaw($column, $values) { @@ -1072,12 +889,7 @@ public function orWhereIntegerNotInRaw($column, $values) } /** - * Add a "where null" clause to the query. - * - * @param string|array $columns - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereNull($columns, $boolean = 'and', $not = false) { @@ -1091,10 +903,7 @@ public function whereNull($columns, $boolean = 'and', $not = false) } /** - * Add an "or where null" clause to the query. - * - * @param string|array $column - * @return $this + * {@inheritdoc} */ public function orWhereNull($column) { @@ -1102,11 +911,7 @@ public function orWhereNull($column) } /** - * Add a "where not null" clause to the query. - * - * @param string|array $columns - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereNotNull($columns, $boolean = 'and') { @@ -1114,13 +919,7 @@ public function whereNotNull($columns, $boolean = 'and') } /** - * Add a where between statement to the query. - * - * @param string|\Illuminate\Database\Query\Expression $column - * @param iterable $values - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) { @@ -1134,13 +933,7 @@ public function whereBetween($column, iterable $values, $boolean = 'and', $not = } /** - * Add a where between statement using columns to the query. - * - * @param string $column - * @param array $values - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereBetweenColumns($column, array $values, $boolean = 'and', $not = false) { @@ -1152,11 +945,7 @@ public function whereBetweenColumns($column, array $values, $boolean = 'and', $n } /** - * Add an or where between statement to the query. - * - * @param string $column - * @param iterable $values - * @return $this + * {@inheritdoc} */ public function orWhereBetween($column, iterable $values) { @@ -1164,11 +953,7 @@ public function orWhereBetween($column, iterable $values) } /** - * Add an or where between statement using columns to the query. - * - * @param string $column - * @param array $values - * @return $this + * {@inheritdoc} */ public function orWhereBetweenColumns($column, array $values) { @@ -1176,12 +961,7 @@ public function orWhereBetweenColumns($column, array $values) } /** - * Add a where not between statement to the query. - * - * @param string $column - * @param iterable $values - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereNotBetween($column, iterable $values, $boolean = 'and') { @@ -1189,12 +969,7 @@ public function whereNotBetween($column, iterable $values, $boolean = 'and') } /** - * Add a where not between statement using columns to the query. - * - * @param string $column - * @param array $values - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereNotBetweenColumns($column, array $values, $boolean = 'and') { @@ -1202,11 +977,7 @@ public function whereNotBetweenColumns($column, array $values, $boolean = 'and') } /** - * Add an or where not between statement to the query. - * - * @param string $column - * @param iterable $values - * @return $this + * {@inheritdoc} */ public function orWhereNotBetween($column, iterable $values) { @@ -1214,11 +985,7 @@ public function orWhereNotBetween($column, iterable $values) } /** - * Add an or where not between statement using columns to the query. - * - * @param string $column - * @param array $values - * @return $this + * {@inheritdoc} */ public function orWhereNotBetweenColumns($column, array $values) { @@ -1226,10 +993,7 @@ public function orWhereNotBetweenColumns($column, array $values) } /** - * Add an "or where not null" clause to the query. - * - * @param string $column - * @return $this + * {@inheritdoc} */ public function orWhereNotNull($column) { @@ -1237,13 +1001,7 @@ public function orWhereNotNull($column) } /** - * Add a "where date" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereDate($column, $operator, $value = null, $boolean = 'and') { @@ -1261,12 +1019,7 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') } /** - * Add an "or where date" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @return $this + * {@inheritdoc} */ public function orWhereDate($column, $operator, $value = null) { @@ -1278,13 +1031,7 @@ public function orWhereDate($column, $operator, $value = null) } /** - * Add a "where time" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereTime($column, $operator, $value = null, $boolean = 'and') { @@ -1302,12 +1049,7 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') } /** - * Add an "or where time" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @return $this + * {@inheritdoc} */ public function orWhereTime($column, $operator, $value = null) { @@ -1319,13 +1061,7 @@ public function orWhereTime($column, $operator, $value = null) } /** - * Add a "where day" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereDay($column, $operator, $value = null, $boolean = 'and') { @@ -1347,12 +1083,7 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') } /** - * Add an "or where day" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @return $this + * {@inheritdoc} */ public function orWhereDay($column, $operator, $value = null) { @@ -1364,13 +1095,7 @@ public function orWhereDay($column, $operator, $value = null) } /** - * Add a "where month" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereMonth($column, $operator, $value = null, $boolean = 'and') { @@ -1392,12 +1117,7 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') } /** - * Add an "or where month" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|null $value - * @return $this + * {@inheritdoc} */ public function orWhereMonth($column, $operator, $value = null) { @@ -1409,13 +1129,7 @@ public function orWhereMonth($column, $operator, $value = null) } /** - * Add a "where year" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|int|null $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereYear($column, $operator, $value = null, $boolean = 'and') { @@ -1433,12 +1147,7 @@ public function whereYear($column, $operator, $value = null, $boolean = 'and') } /** - * Add an "or where year" statement to the query. - * - * @param string $column - * @param string $operator - * @param \DateTimeInterface|string|int|null $value - * @return $this + * {@inheritdoc} */ public function orWhereYear($column, $operator, $value = null) { @@ -1471,11 +1180,7 @@ protected function addDateBasedWhere($type, $column, $operator, $value, $boolean } /** - * Add a nested where statement to the query. - * - * @param \Closure $callback - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereNested(Closure $callback, $boolean = 'and') { @@ -1495,11 +1200,7 @@ public function forNestedWhere() } /** - * Add another query builder as a nested where to the query builder. - * - * @param \Illuminate\Database\Query\Builder $query - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function addNestedWhereQuery($query, $boolean = 'and') { @@ -1542,12 +1243,7 @@ protected function whereSub($column, $operator, Closure $callback, $boolean) } /** - * Add an exists clause to the query. - * - * @param \Closure $callback - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereExists(Closure $callback, $boolean = 'and', $not = false) { @@ -1562,11 +1258,7 @@ public function whereExists(Closure $callback, $boolean = 'and', $not = false) } /** - * Add an or exists clause to the query. - * - * @param \Closure $callback - * @param bool $not - * @return $this + * {@inheritdoc} */ public function orWhereExists(Closure $callback, $not = false) { @@ -1574,11 +1266,7 @@ public function orWhereExists(Closure $callback, $not = false) } /** - * Add a where not exists clause to the query. - * - * @param \Closure $callback - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereNotExists(Closure $callback, $boolean = 'and') { @@ -1586,10 +1274,7 @@ public function whereNotExists(Closure $callback, $boolean = 'and') } /** - * Add a where not exists clause to the query. - * - * @param \Closure $callback - * @return $this + * {@inheritdoc} */ public function orWhereNotExists(Closure $callback) { @@ -1616,15 +1301,7 @@ public function addWhereExistsQuery(self $query, $boolean = 'and', $not = false) } /** - * Adds a where condition using row values. - * - * @param array $columns - * @param string $operator - * @param array $values - * @param string $boolean - * @return $this - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function whereRowValues($columns, $operator, $values, $boolean = 'and') { @@ -1642,12 +1319,7 @@ public function whereRowValues($columns, $operator, $values, $boolean = 'and') } /** - * Adds an or where condition using row values. - * - * @param array $columns - * @param string $operator - * @param array $values - * @return $this + * {@inheritdoc} */ public function orWhereRowValues($columns, $operator, $values) { @@ -1655,13 +1327,7 @@ public function orWhereRowValues($columns, $operator, $values) } /** - * Add a "where JSON contains" clause to the query. - * - * @param string $column - * @param mixed $value - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function whereJsonContains($column, $value, $boolean = 'and', $not = false) { @@ -1677,11 +1343,7 @@ public function whereJsonContains($column, $value, $boolean = 'and', $not = fals } /** - * Add an "or where JSON contains" clause to the query. - * - * @param string $column - * @param mixed $value - * @return $this + * {@inheritdoc} */ public function orWhereJsonContains($column, $value) { @@ -1689,12 +1351,7 @@ public function orWhereJsonContains($column, $value) } /** - * Add a "where JSON not contains" clause to the query. - * - * @param string $column - * @param mixed $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereJsonDoesntContain($column, $value, $boolean = 'and') { @@ -1702,11 +1359,7 @@ public function whereJsonDoesntContain($column, $value, $boolean = 'and') } /** - * Add an "or where JSON not contains" clause to the query. - * - * @param string $column - * @param mixed $value - * @return $this + * {@inheritdoc} */ public function orWhereJsonDoesntContain($column, $value) { @@ -1714,13 +1367,7 @@ public function orWhereJsonDoesntContain($column, $value) } /** - * Add a "where JSON length" clause to the query. - * - * @param string $column - * @param mixed $operator - * @param mixed $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function whereJsonLength($column, $operator, $value = null, $boolean = 'and') { @@ -1740,12 +1387,7 @@ public function whereJsonLength($column, $operator, $value = null, $boolean = 'a } /** - * Add an "or where JSON length" clause to the query. - * - * @param string $column - * @param mixed $operator - * @param mixed $value - * @return $this + * {@inheritdoc} */ public function orWhereJsonLength($column, $operator, $value = null) { @@ -1819,10 +1461,7 @@ protected function addDynamic($segment, $connector, $parameters, $index) } /** - * Add a "group by" clause to the query. - * - * @param array|string ...$groups - * @return $this + * {@inheritdoc} */ public function groupBy(...$groups) { @@ -1837,11 +1476,7 @@ public function groupBy(...$groups) } /** - * Add a raw groupBy clause to the query. - * - * @param string $sql - * @param array $bindings - * @return $this + * {@inheritdoc} */ public function groupByRaw($sql, array $bindings = []) { @@ -1853,13 +1488,7 @@ public function groupByRaw($sql, array $bindings = []) } /** - * Add a "having" clause to the query. - * - * @param string $column - * @param string|null $operator - * @param string|null $value - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function having($column, $operator = null, $value = null, $boolean = 'and') { @@ -1889,12 +1518,7 @@ public function having($column, $operator = null, $value = null, $boolean = 'and } /** - * Add an "or having" clause to the query. - * - * @param string $column - * @param string|null $operator - * @param string|null $value - * @return $this + * {@inheritdoc} */ public function orHaving($column, $operator = null, $value = null) { @@ -1906,12 +1530,7 @@ public function orHaving($column, $operator = null, $value = null) } /** - * Add a "having null" clause to the query. - * - * @param string|array $columns - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function havingNull($columns, $boolean = 'and', $not = false) { @@ -1925,10 +1544,7 @@ public function havingNull($columns, $boolean = 'and', $not = false) } /** - * Add an "or having null" clause to the query. - * - * @param string $column - * @return $this + * {@inheritdoc} */ public function orHavingNull($column) { @@ -1936,11 +1552,7 @@ public function orHavingNull($column) } /** - * Add a "having not null" clause to the query. - * - * @param string|array $columns - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function havingNotNull($columns, $boolean = 'and') { @@ -1948,10 +1560,7 @@ public function havingNotNull($columns, $boolean = 'and') } /** - * Add an "or having not null" clause to the query. - * - * @param string $column - * @return $this + * {@inheritdoc} */ public function orHavingNotNull($column) { @@ -1959,13 +1568,7 @@ public function orHavingNotNull($column) } /** - * Add a "having between " clause to the query. - * - * @param string $column - * @param array $values - * @param string $boolean - * @param bool $not - * @return $this + * {@inheritdoc} */ public function havingBetween($column, array $values, $boolean = 'and', $not = false) { @@ -1979,12 +1582,7 @@ public function havingBetween($column, array $values, $boolean = 'and', $not = f } /** - * Add a raw having clause to the query. - * - * @param string $sql - * @param array $bindings - * @param string $boolean - * @return $this + * {@inheritdoc} */ public function havingRaw($sql, array $bindings = [], $boolean = 'and') { @@ -1998,11 +1596,7 @@ public function havingRaw($sql, array $bindings = [], $boolean = 'and') } /** - * Add a raw or having clause to the query. - * - * @param string $sql - * @param array $bindings - * @return $this + * {@inheritdoc} */ public function orHavingRaw($sql, array $bindings = []) { @@ -2010,13 +1604,7 @@ public function orHavingRaw($sql, array $bindings = []) } /** - * Add an "order by" clause to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column - * @param string $direction - * @return $this - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function orderBy($column, $direction = 'asc') { @@ -2043,10 +1631,7 @@ public function orderBy($column, $direction = 'asc') } /** - * Add a descending "order by" clause to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column - * @return $this + * {@inheritdoc} */ public function orderByDesc($column) { @@ -2054,10 +1639,7 @@ public function orderByDesc($column) } /** - * Add an "order by" clause for a timestamp to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column - * @return $this + * {@inheritdoc} */ public function latest($column = 'created_at') { @@ -2065,10 +1647,7 @@ public function latest($column = 'created_at') } /** - * Add an "order by" clause for a timestamp to the query. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column - * @return $this + * {@inheritdoc} */ public function oldest($column = 'created_at') { @@ -2076,10 +1655,7 @@ public function oldest($column = 'created_at') } /** - * Put the query's results in random order. - * - * @param string $seed - * @return $this + * {@inheritdoc} */ public function inRandomOrder($seed = '') { @@ -2087,11 +1663,7 @@ public function inRandomOrder($seed = '') } /** - * Add a raw "order by" clause to the query. - * - * @param string $sql - * @param array $bindings - * @return $this + * {@inheritdoc} */ public function orderByRaw($sql, $bindings = []) { @@ -2105,10 +1677,7 @@ public function orderByRaw($sql, $bindings = []) } /** - * Alias to set the "offset" value of the query. - * - * @param int $value - * @return $this + * {@inheritdoc} */ public function skip($value) { @@ -2116,10 +1685,7 @@ public function skip($value) } /** - * Set the "offset" value of the query. - * - * @param int $value - * @return $this + * {@inheritdoc} */ public function offset($value) { @@ -2131,10 +1697,7 @@ public function offset($value) } /** - * Alias to set the "limit" value of the query. - * - * @param int $value - * @return $this + * {@inheritdoc} */ public function take($value) { @@ -2142,10 +1705,7 @@ public function take($value) } /** - * Set the "limit" value of the query. - * - * @param int $value - * @return $this + * {@inheritdoc} */ public function limit($value) { @@ -2159,11 +1719,7 @@ public function limit($value) } /** - * Set the limit and offset for a given page. - * - * @param int $page - * @param int $perPage - * @return $this + * @inheritdoc */ public function forPage($page, $perPage = 15) { @@ -2171,12 +1727,7 @@ public function forPage($page, $perPage = 15) } /** - * Constrain the query to the previous "page" of results before a given ID. - * - * @param int $perPage - * @param int|null $lastId - * @param string $column - * @return $this + * @inheritdoc */ public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') { @@ -2191,12 +1742,7 @@ public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') } /** - * Constrain the query to the next "page" of results after a given ID. - * - * @param int $perPage - * @param int|null $lastId - * @param string $column - * @return $this + * @inheritdoc */ public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') { @@ -2211,11 +1757,7 @@ public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') } /** - * Remove all existing orders and optionally add a new order. - * - * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string|null $column - * @param string $direction - * @return $this + * @inheritdoc */ public function reorder($column = null, $direction = 'asc') { @@ -2247,11 +1789,7 @@ protected function removeExistingOrdersFor($column) } /** - * Add a union statement to the query. - * - * @param \Illuminate\Database\Query\Builder|\Closure $query - * @param bool $all - * @return $this + * @inheritdoc */ public function union($query, $all = false) { @@ -2267,10 +1805,7 @@ public function union($query, $all = false) } /** - * Add a union all statement to the query. - * - * @param \Illuminate\Database\Query\Builder|\Closure $query - * @return $this + * @inheritdoc */ public function unionAll($query) { @@ -2278,10 +1813,7 @@ public function unionAll($query) } /** - * Lock the selected rows in the table. - * - * @param string|bool $value - * @return $this + * @inheritdoc */ public function lock($value = true) { @@ -2295,9 +1827,7 @@ public function lock($value = true) } /** - * Lock the selected rows in the table for updating. - * - * @return \Illuminate\Database\Query\Builder + * @inheritdoc */ public function lockForUpdate() { @@ -2305,9 +1835,7 @@ public function lockForUpdate() } /** - * Share lock the selected rows in the table. - * - * @return \Illuminate\Database\Query\Builder + * @inheritdoc */ public function sharedLock() { @@ -3202,9 +2730,7 @@ public function truncate() } /** - * Get a new instance of the query builder. - * - * @return \Illuminate\Database\Query\Builder + * @inheritdoc */ public function newQuery() { @@ -3222,10 +2748,7 @@ protected function forSubQuery() } /** - * Create a raw database expression. - * - * @param mixed $value - * @return \Illuminate\Database\Query\Expression + * @inheritdoc */ public function raw($value) { @@ -3233,9 +2756,7 @@ public function raw($value) } /** - * Get the current query value bindings in a flattened array. - * - * @return array + * @inheritdoc */ public function getBindings() { @@ -3243,9 +2764,7 @@ public function getBindings() } /** - * Get the raw array of bindings. - * - * @return array + * @inheritdoc */ public function getRawBindings() { @@ -3253,13 +2772,7 @@ public function getRawBindings() } /** - * Set the bindings on the query builder. - * - * @param array $bindings - * @param string $type - * @return $this - * - * @throws \InvalidArgumentException + * @inheritdoc */ public function setBindings(array $bindings, $type = 'where') { @@ -3273,13 +2786,7 @@ public function setBindings(array $bindings, $type = 'where') } /** - * Add a binding to the query. - * - * @param mixed $value - * @param string $type - * @return $this - * - * @throws \InvalidArgumentException + * @inheritdoc */ public function addBinding($value, $type = 'where') { @@ -3297,23 +2804,17 @@ public function addBinding($value, $type = 'where') } /** - * Merge an array of bindings into our bindings. - * - * @param \Illuminate\Database\Query\Builder $query - * @return $this + * @inheritdoc */ - public function mergeBindings(self $query) + public function mergeBindings(BuilderContract $query) { - $this->bindings = array_merge_recursive($this->bindings, $query->bindings); + $this->bindings = array_merge_recursive($this->bindings, $query->getRawBindings()); return $this; } /** - * Remove all of the expressions from a list of bindings. - * - * @param array $bindings - * @return array + * @inheritdoc */ public function cleanBindings(array $bindings) { @@ -3344,9 +2845,7 @@ protected function defaultKeyName() } /** - * Get the database connection instance. - * - * @return \Illuminate\Database\ConnectionInterface + * @inheritdoc */ public function getConnection() { @@ -3354,9 +2853,7 @@ public function getConnection() } /** - * Get the database query processor instance. - * - * @return \Illuminate\Database\Query\Processors\Processor + * @inheritdoc */ public function getProcessor() { @@ -3364,9 +2861,7 @@ public function getProcessor() } /** - * Get the query grammar instance. - * - * @return \Illuminate\Database\Query\Grammars\Grammar + * @inheritdoc */ public function getGrammar() { @@ -3374,9 +2869,7 @@ public function getGrammar() } /** - * Use the write pdo for query. - * - * @return $this + * @inheritdoc */ public function useWritePdo() { @@ -3400,9 +2893,7 @@ protected function isQueryable($value) } /** - * Clone the query. - * - * @return static + * @inheritdoc */ public function clone() { @@ -3410,10 +2901,7 @@ public function clone() } /** - * Clone the query without the given properties. - * - * @param array $properties - * @return static + * @inheritdoc */ public function cloneWithout(array $properties) { @@ -3425,10 +2913,7 @@ public function cloneWithout(array $properties) } /** - * Clone the query without the given bindings. - * - * @param array $except - * @return static + * @inheritdoc */ public function cloneWithoutBindings(array $except) { From ab5fd4bfc2a93283c26a4bfbc63f48355694bca4 Mon Sep 17 00:00:00 2001 From: Shuvro Roy Date: Tue, 20 Jul 2021 00:22:13 +0600 Subject: [PATCH 162/194] update php8 string function (#38071) --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index e70378c6b078..f07817bdce25 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -702,8 +702,8 @@ protected function serializeClassCastableAttribute($key, $value) */ protected function isCustomDateTimeCast($cast) { - return strncmp($cast, 'date:', 5) === 0 || - strncmp($cast, 'datetime:', 9) === 0; + return str_starts_with($cast, 'date:') || + str_starts_with($cast, 'datetime:'); } /** @@ -714,7 +714,7 @@ protected function isCustomDateTimeCast($cast) */ protected function isDecimalCast($cast) { - return strncmp($cast, 'decimal:', 8) === 0; + return str_starts_with($cast, 'decimal:'); } /** From 709714d3d296b1557038e362b9405b9d65528572 Mon Sep 17 00:00:00 2001 From: silai Date: Fri, 23 Jul 2021 22:34:55 +0800 Subject: [PATCH 163/194] TrimString middleware adds invisible characters (#38117) Co-authored-by: jie --- .../Foundation/Http/Middleware/TrimStrings.php | 2 +- .../Http/Middleware/TrimStringsTest.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php index fe8f8f872043..857baf4b49d3 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php +++ b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php @@ -53,7 +53,7 @@ protected function transform($key, $value) return $value; } - return is_string($value) ? trim($value) : $value; + return is_string($value) ? trim($value, "  \t\n\r\0\x0B") : $value; } /** diff --git a/tests/Foundation/Http/Middleware/TrimStringsTest.php b/tests/Foundation/Http/Middleware/TrimStringsTest.php index 33262af684f7..5003dc1bf0ba 100644 --- a/tests/Foundation/Http/Middleware/TrimStringsTest.php +++ b/tests/Foundation/Http/Middleware/TrimStringsTest.php @@ -28,6 +28,21 @@ public function testTrimStringsIgnoringExceptAttribute() $this->assertSame(' 010 ', $request->get('bar')); }); } + + public function testTrimStringsNBSP() + { + $middleware = new TrimStrings; + $symfonyRequest = new SymfonyRequest([ + // Here has some NBSP, but it still display to space. + 'abc' => '  123   ', + ]); + $symfonyRequest->server->set('REQUEST_METHOD', 'GET'); + $request = Request::createFromBase($symfonyRequest); + + $middleware->handle($request, function (Request $request) { + $this->assertSame('123', $request->get('abc')); + }); + } } class TrimStringsWithExceptAttribute extends TrimStrings From 9581cd6feb5be3e21c5b32ef154431f63eae89a8 Mon Sep 17 00:00:00 2001 From: Julius Kiekbusch Date: Mon, 2 Aug 2021 15:40:18 +0200 Subject: [PATCH 164/194] Remove ext-json from composer.json (#38202) --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 94d9fe4aad7e..55544d49881e 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,6 @@ ], "require": { "php": "^8.0", - "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", "doctrine/inflector": "^2.0", From 13e4a7ff1799ee51698faa10161b2d2af889b713 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Mon, 9 Aug 2021 07:46:19 -0600 Subject: [PATCH 165/194] [9.x] Manually populate POST request body with JSON data only when required (#37921) * Manually populate POST request body with JSON data only when required This fixes a 6 year old bug introduced in #7026 where GET requests would have GET data populated in the POST body property leading to issues around Request::post() and $request->getParsedBody() returning GET values when called on GET requests. This is a resubmit of #17087 & #36708, and fixes #22805. Credit to @dan-har for the initial solution and @mixlion for updating it for >=6.x. The original PR was meant to support POST requests where their Content-type was set to application/json (instead of the typical application/x-www-form-urlencoded), but it introduced a subtle and dangerous bug because while $request->getInputSource() does return the JSON data for JSON requests, it also returns the GET data for GET requests. This commit solves the underlying issue without breaking compatibility with the original functionality. * Add test for non-JSON GET requests * Style fixes * Extra space removal * GitHub's editor needs some work --- src/Illuminate/Http/Request.php | 4 +++- tests/Http/HttpRequestTest.php | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 0dd1208778d6..bdef8ce308c7 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -432,7 +432,9 @@ public static function createFromBase(SymfonyRequest $request) $newRequest->content = $request->content; - $newRequest->request = $newRequest->getInputSource(); + if ($newRequest->isJson()) { + $newRequest->request = $newRequest->json(); + } return $newRequest; } diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 33611a32d28a..3718fd9768ba 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -1007,7 +1007,12 @@ public function testFingerprintWithoutRoute() $request->fingerprint(); } - public function testCreateFromBase() + /** + * Ensure JSON GET requests populate $request->request with the JSON content. + * + * @link https://github.com/laravel/framework/pull/7052 Correctly fill the $request->request parameter bag on creation. + */ + public function testJsonRequestFillsRequestBodyParams() { $body = [ 'foo' => 'bar', @@ -1025,6 +1030,24 @@ public function testCreateFromBase() $this->assertEquals($request->request->all(), $body); } + /** + * Ensure non-JSON GET requests don't pollute $request->request with the GET parameters. + * + * @link https://github.com/laravel/framework/pull/37921 Manually populate POST request body with JSON data only when required. + */ + public function testNonJsonRequestDoesntFillRequestBodyParams() + { + $params = ['foo' => 'bar']; + + $getRequest = Request::create('/', 'GET', $params, [], [], []); + $this->assertEquals($getRequest->request->all(), []); + $this->assertEquals($getRequest->query->all(), $params); + + $postRequest = Request::create('/', 'POST', $params, [], [], []); + $this->assertEquals($postRequest->request->all(), $params); + $this->assertEquals($postRequest->query->all(), []); + } + /** * Tests for Http\Request magic methods `__get()` and `__isset()`. * From 0ec3e78e85d44da1c6784f403dc1d8db0e4604f2 Mon Sep 17 00:00:00 2001 From: Michael Dyrynda Date: Tue, 10 Aug 2021 23:43:43 +0930 Subject: [PATCH 166/194] [9.x] Use CarbonImmutable by default (#38258) * Ensure that Illuminate\Support\Carbon is used consistently across the framework * Update tests to support immutable dates by default * Update date calls to support immutable-first behaviour * cs fixes * Per PR review, revert to using Carbon by default --- src/Illuminate/Console/Scheduling/Event.php | 2 +- src/Illuminate/Console/Scheduling/ManagesFrequencies.php | 4 ++-- src/Illuminate/Foundation/Testing/TestCase.php | 2 +- src/Illuminate/Queue/Console/PruneBatchesCommand.php | 2 +- src/Illuminate/Queue/Console/PruneFailedJobsCommand.php | 2 +- tests/Database/DatabaseEloquentIntegrationTest.php | 4 ++-- tests/Pagination/CursorTest.php | 2 +- tests/Queue/QueueSqsQueueTest.php | 2 +- tests/Support/SupportCarbonTest.php | 3 +-- tests/Support/SupportLazyCollectionTest.php | 2 +- 10 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 4ce5a7735d6c..2ae1f76c8b99 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -324,7 +324,7 @@ protected function expressionPasses() $date = Date::now(); if ($this->timezone) { - $date->setTimezone($this->timezone); + $date = $date->setTimezone($this->timezone); } return (new CronExpression($this->expression))->isDue($date->toDateTimeString()); diff --git a/src/Illuminate/Console/Scheduling/ManagesFrequencies.php b/src/Illuminate/Console/Scheduling/ManagesFrequencies.php index d45bc0f8275b..45b8896338ef 100644 --- a/src/Illuminate/Console/Scheduling/ManagesFrequencies.php +++ b/src/Illuminate/Console/Scheduling/ManagesFrequencies.php @@ -60,9 +60,9 @@ private function inTimeInterval($startTime, $endTime) if ($endTime->lessThan($startTime)) { if ($startTime->greaterThan($now)) { - $startTime->subDay(1); + $startTime = $startTime->subDay(1); } else { - $endTime->addDay(1); + $endTime = $endTime->addDay(1); } } diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index ee19a864b591..c085a3ce1418 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -2,11 +2,11 @@ namespace Illuminate\Foundation\Testing; -use Carbon\Carbon; use Carbon\CarbonImmutable; use Illuminate\Console\Application as Artisan; use Illuminate\Database\Eloquent\Model; use Illuminate\Queue\Queue; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\ParallelTesting; use Illuminate\Support\Str; diff --git a/src/Illuminate/Queue/Console/PruneBatchesCommand.php b/src/Illuminate/Queue/Console/PruneBatchesCommand.php index 808c82c5dcbf..deb4eb96f685 100644 --- a/src/Illuminate/Queue/Console/PruneBatchesCommand.php +++ b/src/Illuminate/Queue/Console/PruneBatchesCommand.php @@ -2,11 +2,11 @@ namespace Illuminate\Queue\Console; -use Carbon\Carbon; use Illuminate\Bus\BatchRepository; use Illuminate\Bus\DatabaseBatchRepository; use Illuminate\Bus\PrunableBatchRepository; use Illuminate\Console\Command; +use Illuminate\Support\Carbon; class PruneBatchesCommand extends Command { diff --git a/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php b/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php index f82d9be3b955..64badcad2d28 100644 --- a/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php +++ b/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php @@ -2,9 +2,9 @@ namespace Illuminate\Queue\Console; -use Carbon\Carbon; use Illuminate\Console\Command; use Illuminate\Queue\Failed\PrunableFailedJobProvider; +use Illuminate\Support\Carbon; class PruneFailedJobsCommand extends Command { diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 9624af06add4..4ef9b1ffc901 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -1374,8 +1374,8 @@ public function testIsAfterRetrievingTheSameModel() public function testFreshMethodOnModel() { - $now = Carbon::now(); - $nowSerialized = $now->startOfSecond()->toJSON(); + $now = Carbon::now()->startOfSecond(); + $nowSerialized = $now->toJSON(); $nowWithFractionsSerialized = $now->toJSON(); Carbon::setTestNow($now); diff --git a/tests/Pagination/CursorTest.php b/tests/Pagination/CursorTest.php index 05c2629619b9..78f7cfc2e4f9 100644 --- a/tests/Pagination/CursorTest.php +++ b/tests/Pagination/CursorTest.php @@ -2,8 +2,8 @@ namespace Illuminate\Tests\Pagination; -use Carbon\Carbon; use Illuminate\Pagination\Cursor; +use Illuminate\Support\Carbon; use PHPUnit\Framework\TestCase; class CursorTest extends TestCase diff --git a/tests/Queue/QueueSqsQueueTest.php b/tests/Queue/QueueSqsQueueTest.php index 60e02b161ebb..0ae708f91e9f 100755 --- a/tests/Queue/QueueSqsQueueTest.php +++ b/tests/Queue/QueueSqsQueueTest.php @@ -94,7 +94,7 @@ public function testDelayedPushWithDateTimeProperlyPushesJobOntoSqs() $queue = $this->getMockBuilder(SqsQueue::class)->onlyMethods(['createPayload', 'secondsUntil', 'getQueue'])->setConstructorArgs([$this->sqs, $this->queueName, $this->account])->getMock(); $queue->setContainer($container = m::spy(Container::class)); $queue->expects($this->once())->method('createPayload')->with($this->mockedJob, $this->queueName, $this->mockedData)->willReturn($this->mockedPayload); - $queue->expects($this->once())->method('secondsUntil')->with($now)->willReturn(5); + $queue->expects($this->once())->method('secondsUntil')->with($now->addSeconds(5))->willReturn(5); $queue->expects($this->once())->method('getQueue')->with($this->queueName)->willReturn($this->queueUrl); $this->sqs->shouldReceive('sendMessage')->once()->with(['QueueUrl' => $this->queueUrl, 'MessageBody' => $this->mockedPayload, 'DelaySeconds' => 5])->andReturn($this->mockedSendMessageResponseModel); $id = $queue->later($now->addSeconds(5), $this->mockedJob, $this->mockedData, $this->queueName); diff --git a/tests/Support/SupportCarbonTest.php b/tests/Support/SupportCarbonTest.php index cdd865b8b470..a01ca35ec254 100644 --- a/tests/Support/SupportCarbonTest.php +++ b/tests/Support/SupportCarbonTest.php @@ -5,7 +5,6 @@ use BadMethodCallException; use Carbon\Carbon as BaseCarbon; use Carbon\CarbonImmutable as BaseCarbonImmutable; -use DateTime; use DateTimeInterface; use Illuminate\Support\Carbon; use PHPUnit\Framework\TestCase; @@ -34,7 +33,7 @@ protected function tearDown(): void public function testInstance() { - $this->assertInstanceOf(DateTime::class, $this->now); + $this->assertInstanceOf(Carbon::class, $this->now); $this->assertInstanceOf(DateTimeInterface::class, $this->now); $this->assertInstanceOf(BaseCarbon::class, $this->now); $this->assertInstanceOf(Carbon::class, $this->now); diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index bb85818b7d8f..b7b0ebcbbb29 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -2,7 +2,7 @@ namespace Illuminate\Tests\Support; -use Carbon\Carbon; +use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\LazyCollection; use Mockery as m; From 94c1b8a72250b07d4a16233f545f1ec8bc195f9a Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 12 Aug 2021 15:05:18 +0200 Subject: [PATCH 167/194] Fix incorrect type --- src/Illuminate/Http/Exceptions/PostTooLargeException.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Exceptions/PostTooLargeException.php b/src/Illuminate/Http/Exceptions/PostTooLargeException.php index 75f6cdde313d..d5bbc60dc44c 100644 --- a/src/Illuminate/Http/Exceptions/PostTooLargeException.php +++ b/src/Illuminate/Http/Exceptions/PostTooLargeException.php @@ -10,13 +10,13 @@ class PostTooLargeException extends HttpException /** * Create a new "post too large" exception instance. * - * @param string|null $message + * @param string $message * @param \Throwable|null $previous * @param array $headers * @param int $code * @return void */ - public function __construct($message = null, Throwable $previous = null, array $headers = [], $code = 0) + public function __construct($message = '', Throwable $previous = null, array $headers = [], $code = 0) { parent::__construct(413, $message, $previous, $headers, $code); } From 8defbc6564649d1f2f11ec10a1a88c12f832d8d3 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Thu, 12 Aug 2021 19:12:34 +0200 Subject: [PATCH 168/194] Make BuildsQueries::tap consistent with other versions of tap (#38359) --- src/Illuminate/Database/Concerns/BuildsQueries.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 8e712f0d7434..c5b124fd38f3 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -422,10 +422,12 @@ protected function cursorPaginator($items, $perPage, $cursor, $options) * Pass the query to a given callback. * * @param callable $callback - * @return $this|mixed + * @return $this */ public function tap($callback) { - return $this->when(true, $callback); + $callback($this); + + return $this; } } From 34771cbf9324ac1b10ad91ce82422a7a22341a14 Mon Sep 17 00:00:00 2001 From: Mark Beech Date: Fri, 13 Aug 2021 14:16:21 +0100 Subject: [PATCH 169/194] BelongsToMany firstOrCreate and firstOrNew should merge attributes correctly (#38367) --- .../Eloquent/Relations/BelongsToMany.php | 7 ++-- .../Database/EloquentBelongsToManyTest.php | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index db69f3390981..18fa14517bbf 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -594,12 +594,13 @@ public function findOrNew($id, $columns = ['*']) * Get the first related model record matching the attributes or instantiate it. * * @param array $attributes + * @param array $values * @return \Illuminate\Database\Eloquent\Model */ - public function firstOrNew(array $attributes = []) + public function firstOrNew(array $attributes = [], array $values = []) { if (is_null($instance = $this->related->where($attributes)->first())) { - $instance = $this->related->newInstance($attributes); + $instance = $this->related->newInstance(array_merge($attributes, $values)); } return $instance; @@ -617,7 +618,7 @@ public function firstOrNew(array $attributes = []) public function firstOrCreate(array $attributes = [], array $values = [], array $joining = [], $touch = true) { if (is_null($instance = $this->related->where($attributes)->first())) { - $instance = $this->create($attributes + $values, $joining, $touch); + $instance = $this->create(array_merge($attributes, $values), $joining, $touch); } return $instance; diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 61f33f5f8a38..e801b93e46b3 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -439,6 +439,36 @@ public function testFirstOrCreateMethod() $this->assertNotNull($new->id); } + public function testFirstOrNewMethodWithValues() + { + $post = Post::create(['title' => Str::random()]); + $tag = Tag::create(['name' => Str::random()]); + $post->tags()->attach(Tag::all()); + + $existing = $post->tags()->firstOrNew( + ['name' => $tag->name], + ['type' => 'featured'] + ); + + $this->assertEquals($tag->id, $existing->id); + $this->assertNotEquals('foo', $existing->name); + + $new = $post->tags()->firstOrNew( + ['name' => 'foo'], + ['type' => 'featured'] + ); + + $this->assertSame('foo', $new->name); + $this->assertSame('featured', $new->type); + + $new = $post->tags()->firstOrNew( + ['name' => 'foo'], + ['name' => 'bar'] + ); + + $this->assertSame('bar', $new->name); + } + public function testFirstOrCreateMethodWithValues() { $post = Post::create(['title' => Str::random()]); @@ -461,6 +491,14 @@ public function testFirstOrCreateMethodWithValues() $this->assertSame('foo', $new->name); $this->assertSame('featured', $new->type); $this->assertNotNull($new->id); + + $new = $post->tags()->firstOrCreate( + ['name' => 'qux'], + ['name' => 'bar'] + ); + + $this->assertSame('bar', $new->name); + $this->assertNotNull($new->id); } public function testUpdateOrCreateMethod() From 585b6042f6ca75baa2eb63cecfb0a3ada49140e9 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 16 Aug 2021 19:53:36 +0200 Subject: [PATCH 170/194] [9.x] Fix Symfony v6 breaking changes (#38376) * Fix type errors * Fix session handling * Update getSession usages --- src/Illuminate/Console/Application.php | 5 +++-- src/Illuminate/Console/Command.php | 4 ++-- .../Console/ContainerCommandLoader.php | 7 ++++--- src/Illuminate/Console/OutputStyle.php | 8 ++++---- src/Illuminate/Http/JsonResponse.php | 6 +++--- src/Illuminate/Http/Request.php | 18 ++++-------------- src/Illuminate/Http/Response.php | 2 +- src/Illuminate/Http/Testing/File.php | 2 +- 8 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index ed8f9fd0cfdb..36e77ffbdc80 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -15,6 +15,7 @@ use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\StringInput; @@ -84,7 +85,7 @@ public function __construct(Container $laravel, Dispatcher $events, $version) /** * {@inheritdoc} */ - public function run(InputInterface $input = null, OutputInterface $output = null) + public function run(InputInterface $input = null, OutputInterface $output = null): int { $commandName = $this->getCommandName( $input = $input ?: new ArgvInput @@ -309,7 +310,7 @@ public function setContainerCommandLoader() * * @return \Symfony\Component\Console\Input\InputDefinition */ - protected function getDefaultInputDefinition() + protected function getDefaultInputDefinition(): InputDefinition { return tap(parent::getDefaultInputDefinition(), function ($definition) { $definition->addOption($this->getEnvironmentOption()); diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 9ec134cf39b5..095934ec55a3 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -111,7 +111,7 @@ protected function configureUsingFluentDefinition() * @param \Symfony\Component\Console\Output\OutputInterface $output * @return int */ - public function run(InputInterface $input, OutputInterface $output) + public function run(InputInterface $input, OutputInterface $output): int { $this->output = $this->laravel->make( OutputStyle::class, ['input' => $input, 'output' => $output] @@ -164,7 +164,7 @@ protected function resolveCommand($command) /** * {@inheritdoc} */ - public function isHidden() + public function isHidden(): bool { return $this->hidden; } diff --git a/src/Illuminate/Console/ContainerCommandLoader.php b/src/Illuminate/Console/ContainerCommandLoader.php index 3ac26fe345da..f770f6c7101f 100644 --- a/src/Illuminate/Console/ContainerCommandLoader.php +++ b/src/Illuminate/Console/ContainerCommandLoader.php @@ -3,6 +3,7 @@ namespace Illuminate\Console; use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\CommandLoader\CommandLoaderInterface; use Symfony\Component\Console\Exception\CommandNotFoundException; @@ -43,7 +44,7 @@ public function __construct(ContainerInterface $container, array $commandMap) * * @throws \Symfony\Component\Console\Exception\CommandNotFoundException */ - public function get(string $name) + public function get(string $name): Command { if (! $this->has($name)) { throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); @@ -58,7 +59,7 @@ public function get(string $name) * @param string $name * @return bool */ - public function has(string $name) + public function has(string $name): bool { return $name && isset($this->commandMap[$name]); } @@ -68,7 +69,7 @@ public function has(string $name) * * @return string[] */ - public function getNames() + public function getNames(): array { return array_keys($this->commandMap); } diff --git a/src/Illuminate/Console/OutputStyle.php b/src/Illuminate/Console/OutputStyle.php index fe5dc450ca45..d9123e86c903 100644 --- a/src/Illuminate/Console/OutputStyle.php +++ b/src/Illuminate/Console/OutputStyle.php @@ -34,7 +34,7 @@ public function __construct(InputInterface $input, OutputInterface $output) * * @return bool */ - public function isQuiet() + public function isQuiet(): bool { return $this->output->isQuiet(); } @@ -44,7 +44,7 @@ public function isQuiet() * * @return bool */ - public function isVerbose() + public function isVerbose(): bool { return $this->output->isVerbose(); } @@ -54,7 +54,7 @@ public function isVerbose() * * @return bool */ - public function isVeryVerbose() + public function isVeryVerbose(): bool { return $this->output->isVeryVerbose(); } @@ -64,7 +64,7 @@ public function isVeryVerbose() * * @return bool */ - public function isDebug() + public function isDebug(): bool { return $this->output->isDebug(); } diff --git a/src/Illuminate/Http/JsonResponse.php b/src/Illuminate/Http/JsonResponse.php index 5b103480a840..c6c3c4eedc0b 100755 --- a/src/Illuminate/Http/JsonResponse.php +++ b/src/Illuminate/Http/JsonResponse.php @@ -35,7 +35,7 @@ public function __construct($data = null, $status = 200, $headers = [], $options /** * {@inheritdoc} */ - public static function fromJsonString(?string $data = null, int $status = 200, array $headers = []) + public static function fromJsonString(?string $data = null, int $status = 200, array $headers = []): static { return new static($data, $status, $headers, 0, true); } @@ -66,7 +66,7 @@ public function getData($assoc = false, $depth = 512) /** * {@inheritdoc} */ - public function setData($data = []) + public function setData($data = []): static { $this->original = $data; @@ -110,7 +110,7 @@ protected function hasValidJson($jsonError) /** * {@inheritdoc} */ - public function setEncodingOptions($options) + public function setEncodingOptions($options): static { $this->encodingOptions = (int) $options; diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index bdef8ce308c7..fd5a50280411 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -336,7 +336,7 @@ public function replace(array $input) * @param mixed $default * @return mixed */ - public function get(string $key, $default = null) + public function get(string $key, mixed $default = null): mixed { return parent::get($key, $default); } @@ -404,7 +404,7 @@ public static function createFrom(self $from, $to = null) $request->setJson($from->json()); - if ($session = $from->getSession()) { + if ($from->hasSession() && $session = $from->getSession()) { $request->setLaravelSession($session); } @@ -442,7 +442,7 @@ public static function createFromBase(SymfonyRequest $request) /** * {@inheritdoc} */ - public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null) + public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null): static { return parent::duplicate($query, $request, $attributes, $cookies, $this->filterFiles($files), $server); } @@ -488,16 +488,6 @@ public function session() return $this->session; } - /** - * Get the session associated with the request. - * - * @return \Illuminate\Session\Store|null - */ - public function getSession() - { - return $this->session; - } - /** * Set the session instance on the request. * @@ -625,7 +615,7 @@ public function setRouteResolver(Closure $callback) * * @return array */ - public function toArray() + public function toArray(): array { return $this->all(); } diff --git a/src/Illuminate/Http/Response.php b/src/Illuminate/Http/Response.php index 8599a8e53a5d..dad783fcd67a 100755 --- a/src/Illuminate/Http/Response.php +++ b/src/Illuminate/Http/Response.php @@ -45,7 +45,7 @@ public function __construct($content = '', $status = 200, array $headers = []) * * @throws \InvalidArgumentException */ - public function setContent($content) + public function setContent(mixed $content): static { $this->original = $content; diff --git a/src/Illuminate/Http/Testing/File.php b/src/Illuminate/Http/Testing/File.php index c714529feb6c..3e062295fbbd 100644 --- a/src/Illuminate/Http/Testing/File.php +++ b/src/Illuminate/Http/Testing/File.php @@ -131,7 +131,7 @@ public function mimeType($mimeType) * * @return string */ - public function getMimeType() + public function getMimeType(): string { return $this->mimeTypeToReport ?: MimeType::from($this->name); } From edbbcdbbda1ba17e1ae7c210dfb10f67a89da84f Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Tue, 17 Aug 2021 09:11:32 -0400 Subject: [PATCH 171/194] Make Application@handle() meet Symfony 6's updated interface (#38413) Add return type. This is a great use of our time. --- src/Illuminate/Foundation/Application.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 21fcbacc6ebb..57b3aed2037a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -22,6 +22,7 @@ use Illuminate\Support\Str; use RuntimeException; use Symfony\Component\HttpFoundation\Request as SymfonyRequest; +use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -959,7 +960,7 @@ protected function fireAppCallbacks(array $callbacks) /** * {@inheritdoc} */ - public function handle(SymfonyRequest $request, int $type = self::MASTER_REQUEST, bool $catch = true) + public function handle(SymfonyRequest $request, int $type = self::MAIN_REQUEST, bool $catch = true): SymfonyResponse { return $this[HttpKernelContract::class]->handle(Request::createFromBase($request)); } From c95392a2ac84313a3296485f7141b6ae8bac5413 Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Thu, 19 Aug 2021 12:13:15 -0400 Subject: [PATCH 172/194] DB queries containing JSON paths support array index references (#38391) e.g., DB::table('owner') ->where('packages[1]->name', 'laravel/framework') ->update(['packages[1]->versions[0]' => '9.0.0']); Stop compiling: UPDATE `owner` SET `packages` = JSON_SET(`packages`, $"[1]"."versions[0]", '9.0.0') WHERE json_unquote(json_extract(`packages[1]`, '$."name"')) = 'laravel/framework'; ... Instead avoid escaping array dereference characters: UPDATE `owner` SET `framework` = JSON_SET(`framework`, $[1]."versions"[0], '9.0.0') WHERE json_unquote(json_extract(`packages[1]`, '$."name"')) = 'laravel/framework'; --- .../Database/Query/Grammars/Grammar.php | 30 ++++++++++++++++++- tests/Database/DatabaseQueryBuilderTest.php | 23 ++++++++++++++ .../Database/DatabaseMySqlConnectionTest.php | 20 +++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 8bc0784467c9..ac3c8fb23837 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -6,6 +6,7 @@ use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Arr; +use Illuminate\Support\Str; use RuntimeException; class Grammar extends BaseGrammar @@ -1223,7 +1224,34 @@ protected function wrapJsonPath($value, $delimiter = '->') { $value = preg_replace("/([\\\\]+)?\\'/", "''", $value); - return '\'$."'.str_replace($delimiter, '"."', $value).'"\''; + $jsonPath = collect(explode($delimiter, $value)) + ->map(function ($segment) { + return $this->wrapJsonPathSegment($segment); + }) + ->join('.'); + + return "'$".(str_starts_with($jsonPath, '[') ? '' : '.').$jsonPath."'"; + } + + /** + * Wrap the given JSON path segment. + * + * @param string $segment + * @return string + */ + protected function wrapJsonPathSegment($segment) + { + if (preg_match('/(\[[^\]]+\])+$/', $segment, $parts)) { + $key = Str::beforeLast($segment, $parts[0]); + + if (! empty($key)) { + return '"'.$key.'"'.$parts[0]; + } + + return $parts[0]; + } + + return '"'.$segment.'"'; } /** diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 108ab445e135..a025db16c8ad 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2883,6 +2883,29 @@ public function testMySqlUpdateWrappingJsonArray() ]); } + public function testMySqlUpdateWrappingJsonPathArrayIndex() + { + $grammar = new MySqlGrammar; + $processor = m::mock(Processor::class); + + $connection = $this->createMock(ConnectionInterface::class); + $connection->expects($this->once()) + ->method('update') + ->with( + 'update `users` set `options` = json_set(`options`, \'$[1]."2fa"\', false), `meta` = json_set(`meta`, \'$."tags"[0][2]\', ?) where `active` = ?', + [ + 'large', + 1, + ] + ); + + $builder = new Builder($connection, $grammar, $processor); + $builder->from('users')->where('active', 1)->update([ + 'options->[1]->2fa' => false, + 'meta->tags[0][2]' => 'large', + ]); + } + public function testMySqlUpdateWithJsonPreparesBindingsCorrectly() { $grammar = new MySqlGrammar; diff --git a/tests/Integration/Database/DatabaseMySqlConnectionTest.php b/tests/Integration/Database/DatabaseMySqlConnectionTest.php index e70cb6e9e0dc..17be49135565 100644 --- a/tests/Integration/Database/DatabaseMySqlConnectionTest.php +++ b/tests/Integration/Database/DatabaseMySqlConnectionTest.php @@ -106,6 +106,26 @@ public function jsonWhereNullDataProvider() 'nested key exists and null' => [true, 'nested->value', ['nested' => ['value' => null]]], 'nested key exists and "null"' => [false, 'nested->value', ['nested' => ['value' => 'null']]], 'nested key exists and not null' => [false, 'nested->value', ['nested' => ['value' => false]]], + 'array index not exists' => [false, '[0]', [1 => 'invalid']], + 'array index exists and null' => [true, '[0]', [null]], + 'array index exists and "null"' => [false, '[0]', ['null']], + 'array index exists and not null' => [false, '[0]', [false]], + 'nested array index not exists' => [false, 'nested[0]', ['nested' => [1 => 'nested->invalid']]], + 'nested array index exists and null' => [true, 'nested->value[1]', ['nested' => ['value' => [0, null]]]], + 'nested array index exists and "null"' => [false, 'nested->value[1]', ['nested' => ['value' => [0, 'null']]]], + 'nested array index exists and not null' => [false, 'nested->value[1]', ['nested' => ['value' => [0, false]]]], ]; } + + public function testJsonPathUpdate() + { + DB::table(self::TABLE)->insert([ + [self::JSON_COL => '{"foo":["bar"]}'], + [self::JSON_COL => '{"foo":["baz"]}'], + ]); + $updatedCount = DB::table(self::TABLE)->where(self::JSON_COL.'->foo[0]', 'baz')->update([ + self::JSON_COL.'->foo[0]' => 'updated', + ]); + $this->assertSame(1, $updatedCount); + } } From f409e0433fd1d9186dc6dfb32e277adb74e96fdc Mon Sep 17 00:00:00 2001 From: Saya Date: Fri, 20 Aug 2021 17:25:10 +0800 Subject: [PATCH 173/194] Update firstOrFail logic (#38470) --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/LazyCollection.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 595b54577ee6..7ff0133fbb5a 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1146,7 +1146,7 @@ public function firstOrFail($key = null, $operator = null, $value = null) ? $this->operatorForWhere(...func_get_args()) : $key; - $items = $this->when($filter)->filter($filter); + $items = $this->unless($filter == null)->filter($filter); if ($items->isEmpty()) { throw new ItemNotFoundException; diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 66f7f0310d1b..7c176c0ea06d 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1091,7 +1091,7 @@ public function firstOrFail($key = null, $operator = null, $value = null) : $key; return $this - ->when($filter) + ->unless($filter == null) ->filter($filter) ->take(1) ->collect() From 1f07d753ea08234e53837c181c2c500eaa6eac42 Mon Sep 17 00:00:00 2001 From: Saya Date: Fri, 20 Aug 2021 21:02:06 +0800 Subject: [PATCH 174/194] [9.x] Lazy load queue commands (#38479) * use class name for command registration * assign defaultName for lazy loading --- .../Foundation/Providers/ArtisanServiceProvider.php | 4 ++-- src/Illuminate/Queue/Console/MonitorCommand.php | 9 +++++++++ src/Illuminate/Queue/Console/PruneFailedJobsCommand.php | 9 +++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 85747c149ab8..58bc54e3e57f 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -681,7 +681,7 @@ protected function registerQueueListenCommand() */ protected function registerQueueMonitorCommand() { - $this->app->singleton('command.queue.monitor', function ($app) { + $this->app->singleton(QueueMonitorCommand::class, function ($app) { return new QueueMonitorCommand($app['queue'], $app['events']); }); } @@ -705,7 +705,7 @@ protected function registerQueuePruneBatchesCommand() */ protected function registerQueuePruneFailedJobsCommand() { - $this->app->singleton('command.queue.prune-failed-jobs', function () { + $this->app->singleton(QueuePruneFailedJobsCommand::class, function () { return new QueuePruneFailedJobsCommand; }); } diff --git a/src/Illuminate/Queue/Console/MonitorCommand.php b/src/Illuminate/Queue/Console/MonitorCommand.php index 1deb479ae698..2916f3ce7542 100644 --- a/src/Illuminate/Queue/Console/MonitorCommand.php +++ b/src/Illuminate/Queue/Console/MonitorCommand.php @@ -19,6 +19,15 @@ class MonitorCommand extends Command {queues : The names of the queues to monitor} {--max=1000 : The maximum number of jobs that can be on the queue before an event is dispatched}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:monitor'; + /** * The console command description. * diff --git a/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php b/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php index 64badcad2d28..6e61b51f54fc 100644 --- a/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php +++ b/src/Illuminate/Queue/Console/PruneFailedJobsCommand.php @@ -16,6 +16,15 @@ class PruneFailedJobsCommand extends Command protected $signature = 'queue:prune-failed {--hours=24 : The number of hours to retain failed jobs data}'; + /** + * The name of the console command. + * + * This name is used to identify the command during lazy loading. + * + * @var string|null + */ + protected static $defaultName = 'queue:prune-failed'; + /** * The console command description. * From 081f467ade3cea2edf7d581e20a3772c882029f5 Mon Sep 17 00:00:00 2001 From: Chrysanthos <48060191+chrysanthos@users.noreply.github.com> Date: Fri, 20 Aug 2021 16:50:23 +0300 Subject: [PATCH 175/194] Dump specific key of the response (#38468) --- src/Illuminate/Testing/TestResponse.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 90930a1d7464..3e46e7a17161 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -1349,9 +1349,10 @@ protected function session() /** * Dump the content from the response. * + * @param string|null $key * @return $this */ - public function dump() + public function dump($key = null) { $content = $this->getContent(); @@ -1361,7 +1362,11 @@ public function dump() $content = $json; } - dump($content); + if (! is_null($key)) { + dump(data_get($content, $key)); + } else { + dump($content); + } return $this; } From 078ae5c1037c2c1cc8974eeb8dfc7dba7b74d9c1 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 23 Aug 2021 10:56:05 +0200 Subject: [PATCH 176/194] Update namespaces in docblocks --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/Enumerable.php | 4 ++-- src/Illuminate/Collections/LazyCollection.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 7ff0133fbb5a..cbde79e64eb5 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1138,7 +1138,7 @@ public function sole($key = null, $operator = null, $value = null) * @param mixed $value * @return mixed * - * @throws \Illuminate\Collections\ItemNotFoundException + * @throws \Illuminate\Support\ItemNotFoundException */ public function firstOrFail($key = null, $operator = null, $value = null) { diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index a3e570ffe8db..59109e719e0f 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -816,8 +816,8 @@ public function split($numberOfGroups); * @param mixed $value * @return mixed * - * @throws \Illuminate\Collections\ItemNotFoundException - * @throws \Illuminate\Collections\MultipleItemsFoundException + * @throws \Illuminate\Support\ItemNotFoundException + * @throws \Illuminate\Support\MultipleItemsFoundException */ public function sole($key = null, $operator = null, $value = null); diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 7c176c0ea06d..8f66f0256de3 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1082,7 +1082,7 @@ public function sole($key = null, $operator = null, $value = null) * @param mixed $value * @return mixed * - * @throws \Illuminate\Collections\ItemNotFoundException + * @throws \Illuminate\Support\ItemNotFoundException */ public function firstOrFail($key = null, $operator = null, $value = null) { From 792e42caab685c20d137ce906a2f26e03ed66280 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Tue, 24 Aug 2021 09:06:17 -0400 Subject: [PATCH 177/194] [9.x] Split Conditionable into package (#38457) * [9.x] Split Conditionable into package * Fix issue with 8.x merge --- bin/split.sh | 2 ++ composer.json | 7 +++- src/Illuminate/Collections/composer.json | 1 + .../HigherOrderWhenProxy.php | 0 src/Illuminate/Conditionable/LICENSE.md | 21 ++++++++++++ .../Traits/Conditionable.php | 0 src/Illuminate/Conditionable/composer.json | 33 +++++++++++++++++++ src/Illuminate/Support/composer.json | 1 + 8 files changed, 64 insertions(+), 1 deletion(-) rename src/Illuminate/{Collections => Conditionable}/HigherOrderWhenProxy.php (100%) create mode 100644 src/Illuminate/Conditionable/LICENSE.md rename src/Illuminate/{Support => Conditionable}/Traits/Conditionable.php (100%) create mode 100644 src/Illuminate/Conditionable/composer.json diff --git a/bin/split.sh b/bin/split.sh index 1e2ea0e98e93..806fee08bf74 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -23,6 +23,7 @@ remote broadcasting git@github.com:illuminate/broadcasting.git remote bus git@github.com:illuminate/bus.git remote cache git@github.com:illuminate/cache.git remote collections git@github.com:illuminate/collections.git +remote conditionable git@github.com:illuminate/conditionable.git remote config git@github.com:illuminate/config.git remote console git@github.com:illuminate/console.git remote container git@github.com:illuminate/container.git @@ -55,6 +56,7 @@ split 'src/Illuminate/Broadcasting' broadcasting split 'src/Illuminate/Bus' bus split 'src/Illuminate/Cache' cache split 'src/Illuminate/Collections' collections +split 'src/Illuminate/Conditionable' conditionable split 'src/Illuminate/Config' config split 'src/Illuminate/Console' console split 'src/Illuminate/Container' container diff --git a/composer.json b/composer.json index 522d3dad721a..85f604fff096 100644 --- a/composer.json +++ b/composer.json @@ -49,6 +49,7 @@ "illuminate/bus": "self.version", "illuminate/cache": "self.version", "illuminate/collections": "self.version", + "illuminate/conditionable": "self.version", "illuminate/config": "self.version", "illuminate/console": "self.version", "illuminate/container": "self.version", @@ -106,7 +107,11 @@ ], "psr-4": { "Illuminate\\": "src/Illuminate/", - "Illuminate\\Support\\": ["src/Illuminate/Macroable/", "src/Illuminate/Collections/"] + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/" + ] } }, "autoload-dev": { diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index 1ec6a1b6827a..fa91e013a674 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -15,6 +15,7 @@ ], "require": { "php": "^7.4|^8.0", + "illuminate/conditionable": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0" }, diff --git a/src/Illuminate/Collections/HigherOrderWhenProxy.php b/src/Illuminate/Conditionable/HigherOrderWhenProxy.php similarity index 100% rename from src/Illuminate/Collections/HigherOrderWhenProxy.php rename to src/Illuminate/Conditionable/HigherOrderWhenProxy.php diff --git a/src/Illuminate/Conditionable/LICENSE.md b/src/Illuminate/Conditionable/LICENSE.md new file mode 100644 index 000000000000..79810c848f8b --- /dev/null +++ b/src/Illuminate/Conditionable/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Taylor Otwell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Illuminate/Support/Traits/Conditionable.php b/src/Illuminate/Conditionable/Traits/Conditionable.php similarity index 100% rename from src/Illuminate/Support/Traits/Conditionable.php rename to src/Illuminate/Conditionable/Traits/Conditionable.php diff --git a/src/Illuminate/Conditionable/composer.json b/src/Illuminate/Conditionable/composer.json new file mode 100644 index 000000000000..a623d8a9efc4 --- /dev/null +++ b/src/Illuminate/Conditionable/composer.json @@ -0,0 +1,33 @@ +{ + "name": "illuminate/conditionable", + "description": "The Illuminate Conditionable package.", + "license": "MIT", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "require": { + "php": "^7.4|^8.0" + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "config": { + "sort-packages": true + }, + "minimum-stability": "dev" +} diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index ebeb607d7083..951fbd15bfa6 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -19,6 +19,7 @@ "ext-mbstring": "*", "doctrine/inflector": "^2.0", "illuminate/collections": "^9.0", + "illuminate/conditionable": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "nesbot/carbon": "^2.31", From da9116ba1b3f3303a2b43d973a011975eeba3b00 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Tue, 24 Aug 2021 21:18:28 +0200 Subject: [PATCH 178/194] [9.x] Adjust PHP 8 and Symfony 6 constraints in all composer.json files (#38526) * Adjust missed places for the PHP 8 and Symfony 6 upgrade * Update PHP version to be in sync with the Symfony 6 min PHP version * Update PHP constraint --- composer.json | 2 +- src/Illuminate/Auth/composer.json | 2 +- src/Illuminate/Broadcasting/composer.json | 2 +- src/Illuminate/Bus/composer.json | 2 +- src/Illuminate/Cache/composer.json | 4 ++-- src/Illuminate/Collections/composer.json | 4 ++-- src/Illuminate/Conditionable/composer.json | 2 +- src/Illuminate/Config/composer.json | 2 +- src/Illuminate/Console/composer.json | 6 +++--- src/Illuminate/Container/composer.json | 2 +- src/Illuminate/Contracts/composer.json | 2 +- src/Illuminate/Cookie/composer.json | 6 +++--- src/Illuminate/Database/composer.json | 6 +++--- src/Illuminate/Encryption/composer.json | 2 +- src/Illuminate/Events/composer.json | 2 +- src/Illuminate/Filesystem/composer.json | 8 ++++---- src/Illuminate/Hashing/composer.json | 2 +- src/Illuminate/Http/composer.json | 8 ++++---- src/Illuminate/Log/composer.json | 2 +- src/Illuminate/Macroable/composer.json | 2 +- src/Illuminate/Mail/composer.json | 2 +- src/Illuminate/Notifications/composer.json | 2 +- src/Illuminate/Pagination/composer.json | 2 +- src/Illuminate/Pipeline/composer.json | 2 +- src/Illuminate/Queue/composer.json | 4 ++-- src/Illuminate/Redis/composer.json | 2 +- src/Illuminate/Routing/composer.json | 8 ++++---- src/Illuminate/Session/composer.json | 6 +++--- src/Illuminate/Support/composer.json | 6 +++--- src/Illuminate/Testing/composer.json | 2 +- src/Illuminate/Translation/composer.json | 2 +- src/Illuminate/Validation/composer.json | 6 +++--- src/Illuminate/View/composer.json | 2 +- 33 files changed, 57 insertions(+), 57 deletions(-) diff --git a/composer.json b/composer.json index 85f604fff096..6032d975078a 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^8.0", + "php": "^8.0.2", "ext-mbstring": "*", "ext-openssl": "*", "doctrine/inflector": "^2.0", diff --git a/src/Illuminate/Auth/composer.json b/src/Illuminate/Auth/composer.json index 4c25696b8495..ae928a33bb36 100644 --- a/src/Illuminate/Auth/composer.json +++ b/src/Illuminate/Auth/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/http": "^9.0", diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index ac9ee3f55aa6..90a2bc5363df 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "psr/log": "^1.0", "illuminate/bus": "^9.0", diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index 612a66bad68f..44e795a4d6b2 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/pipeline": "^9.0", diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index a41a791f5039..0f12a7404a96 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", @@ -35,7 +35,7 @@ "illuminate/database": "Required to use the database cache driver (^9.0).", "illuminate/filesystem": "Required to use the file cache driver (^9.0).", "illuminate/redis": "Required to use the redis cache driver (^9.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.3)." + "symfony/cache": "Required to PSR-6 cache bridge (^6.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index fa91e013a674..cc9aad3429bc 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/conditionable": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0" @@ -33,7 +33,7 @@ } }, "suggest": { - "symfony/var-dumper": "Required to use the dump method (^5.3)." + "symfony/var-dumper": "Required to use the dump method (^6.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Conditionable/composer.json b/src/Illuminate/Conditionable/composer.json index a623d8a9efc4..a423aad17b6b 100644 --- a/src/Illuminate/Conditionable/composer.json +++ b/src/Illuminate/Conditionable/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0" + "php": "^8.0.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Config/composer.json b/src/Illuminate/Config/composer.json index 112bed557786..bc2e8e5c9643 100755 --- a/src/Illuminate/Config/composer.json +++ b/src/Illuminate/Config/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0" }, diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 5115717e15c6..5a768863bc01 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -14,13 +14,13 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/console": "^5.3", - "symfony/process": "^5.3" + "symfony/console": "^6.0", + "symfony/process": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index 48b14c5136ad..023c891c10cd 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/contracts": "^9.0", "psr/container": "^1.0" }, diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index efd4563da3a1..a39250afd2fe 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "psr/container": "^1.0", "psr/simple-cache": "^1.0" }, diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 0a0519c1fcef..a7a444cc333a 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -14,13 +14,13 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.3", - "symfony/http-kernel": "^5.3" + "symfony/http-foundation": "^6.0", + "symfony/http-kernel": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 1baa558ba277..c38b17f299d1 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -15,14 +15,14 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/console": "^5.3" + "symfony/console": "^6.0" }, "autoload": { "psr-4": { @@ -41,7 +41,7 @@ "illuminate/events": "Required to use the observers with Eloquent (^9.0).", "illuminate/filesystem": "Required to use the migrations (^9.0).", "illuminate/pagination": "Required to paginate the result set (^9.0).", - "symfony/finder": "Required to use Eloquent model factories (^5.3)." + "symfony/finder": "Required to use Eloquent model factories (^6.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Encryption/composer.json b/src/Illuminate/Encryption/composer.json index c279db0aa233..333e57dfdfd0 100644 --- a/src/Illuminate/Encryption/composer.json +++ b/src/Illuminate/Encryption/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", diff --git a/src/Illuminate/Events/composer.json b/src/Illuminate/Events/composer.json index ddff05d3039b..d07421220ca5 100755 --- a/src/Illuminate/Events/composer.json +++ b/src/Illuminate/Events/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/bus": "^9.0", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index b0113cb9d294..cd6edfaf2b17 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -14,12 +14,12 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", - "symfony/finder": "^5.3" + "symfony/finder": "^6.0" }, "autoload": { "psr-4": { @@ -39,8 +39,8 @@ "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^2.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^2.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.3).", - "symfony/mime": "Required to enable support for guessing extensions (^5.3)." + "symfony/filesystem": "Required to enable support for relative symbolic links (^6.0).", + "symfony/mime": "Required to enable support for guessing extensions (^6.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Hashing/composer.json b/src/Illuminate/Hashing/composer.json index f3fcc65e1a3c..77f9280b8ea2 100755 --- a/src/Illuminate/Hashing/composer.json +++ b/src/Illuminate/Hashing/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0" }, diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index eb5ee847e2c0..6d0f3d634cf5 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -14,15 +14,15 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/macroable": "^9.0", "illuminate/session": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.3", - "symfony/http-kernel": "^5.3", - "symfony/mime": "^5.3" + "symfony/http-foundation": "^6.0", + "symfony/http-kernel": "^6.0", + "symfony/mime": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index 8374723510f2..f6bfd0e9dc5a 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0", "monolog/monolog": "^2.0" diff --git a/src/Illuminate/Macroable/composer.json b/src/Illuminate/Macroable/composer.json index 43f1528be714..0417dbe40dd4 100644 --- a/src/Illuminate/Macroable/composer.json +++ b/src/Illuminate/Macroable/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0" + "php": "^8.0.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 66a6361f4232..53e88e315bd3 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index 40af814f99e7..1fd402ef9764 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/broadcasting": "^9.0", "illuminate/bus": "^9.0", "illuminate/collections": "^9.0", diff --git a/src/Illuminate/Pagination/composer.json b/src/Illuminate/Pagination/composer.json index d1f78330da93..3edd0d73ff0e 100755 --- a/src/Illuminate/Pagination/composer.json +++ b/src/Illuminate/Pagination/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", diff --git a/src/Illuminate/Pipeline/composer.json b/src/Illuminate/Pipeline/composer.json index 38edca3ab3a9..7e640af36408 100644 --- a/src/Illuminate/Pipeline/composer.json +++ b/src/Illuminate/Pipeline/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0" }, diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index fef945d6c8f5..ee04af39a7e2 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/console": "^9.0", @@ -26,7 +26,7 @@ "illuminate/support": "^9.0", "opis/closure": "^3.6", "ramsey/uuid": "^4.0", - "symfony/process": "^5.3" + "symfony/process": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index d542af696cb1..20c3f65b2f8e 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 3eb2a654bf9d..2b3aa1a7a443 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", @@ -24,9 +24,9 @@ "illuminate/pipeline": "^9.0", "illuminate/session": "^9.0", "illuminate/support": "^9.0", - "symfony/http-foundation": "^5.3", - "symfony/http-kernel": "^5.3", - "symfony/routing": "^5.3" + "symfony/http-foundation": "^6.0", + "symfony/http-kernel": "^6.0", + "symfony/routing": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 13c56ea87fd4..f29d59d4d0f1 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -14,14 +14,14 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/filesystem": "^9.0", "illuminate/support": "^9.0", - "symfony/finder": "^5.3", - "symfony/http-foundation": "^5.3" + "symfony/finder": "^6.0", + "symfony/http-foundation": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 951fbd15bfa6..ccf59778fb9c 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "ext-mbstring": "*", "doctrine/inflector": "^2.0", @@ -45,8 +45,8 @@ "illuminate/filesystem": "Required to use the composer class (^9.0).", "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0).", "ramsey/uuid": "Required to use Str::uuid() (^4.0).", - "symfony/process": "Required to use the composer class (^5.3).", - "symfony/var-dumper": "Required to use the dd function (^5.3).", + "symfony/process": "Required to use the composer class (^6.0).", + "symfony/var-dumper": "Required to use the dd function (^6.0).", "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.3)." }, "config": { diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index c0e7102af2e7..5345344b65f2 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", "illuminate/macroable": "^9.0", diff --git a/src/Illuminate/Translation/composer.json b/src/Illuminate/Translation/composer.json index 0a58f23c47f3..fc6bd262d3d2 100755 --- a/src/Illuminate/Translation/composer.json +++ b/src/Illuminate/Translation/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/contracts": "^9.0", diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 47257824d4be..9547f0f7bbd5 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "egulias/email-validator": "^3.1", "illuminate/collections": "^9.0", @@ -23,8 +23,8 @@ "illuminate/macroable": "^9.0", "illuminate/support": "^9.0", "illuminate/translation": "^9.0", - "symfony/http-foundation": "^5.3", - "symfony/mime": "^5.3" + "symfony/http-foundation": "^6.0", + "symfony/mime": "^6.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index 9c4c1c1acfda..7487d55d7bf5 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0.2", "ext-json": "*", "illuminate/collections": "^9.0", "illuminate/container": "^9.0", From 14c2b252f28df7072a096786163bfe2e9e0587f5 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 24 Aug 2021 14:33:04 -0500 Subject: [PATCH 179/194] minor grammar fix (#38529) --- src/Illuminate/Cache/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index 0f12a7404a96..90cff94827e3 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -35,7 +35,7 @@ "illuminate/database": "Required to use the database cache driver (^9.0).", "illuminate/filesystem": "Required to use the file cache driver (^9.0).", "illuminate/redis": "Required to use the redis cache driver (^9.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^6.0)." + "symfony/cache": "Required to use PSR-6 cache bridge (^6.0)." }, "config": { "sort-packages": true From 89b68c784e8f29b7367f71c3080d1f2ed0d61c18 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 26 Aug 2021 17:23:29 +0200 Subject: [PATCH 180/194] Update constraint --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6032d975078a..878d980f4df3 100644 --- a/composer.json +++ b/composer.json @@ -90,7 +90,7 @@ "pda/pheanstalk": "^4.0", "phpunit/phpunit": "^9.4", "predis/predis": "^1.1.2", - "symfony/cache": "^5.3" + "symfony/cache": "^6.0" }, "provide": { "psr/container-implementation": "1.0" From 81527e7c2cf212f5e9a2616ef5b5c5debddf3bcf Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 26 Aug 2021 17:38:26 +0200 Subject: [PATCH 181/194] bump --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 878d980f4df3..44dfcb489fd5 100644 --- a/composer.json +++ b/composer.json @@ -151,8 +151,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 (^5.0|^6.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^5.3).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^5.3).", + "symfony/cache": "Required to PSR-6 cache bridge (^6.0).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^6.0).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, From b1de554157cf25ec59fa81774eb687e1692357d3 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 27 Aug 2021 15:01:13 +0100 Subject: [PATCH 182/194] [9.x] Improves `Support\Collection` and `Database\Eloquent\Collection` type definitions (#38538) * Adds CI workflow * Adds phpstan * Adds work in progress regarding generic collections * Fixes missing template * Renames template * Updates test * Apply fixes from StyleCI * Adds work in progress regarding generic collections * Adds work in progress regarding generic collections * Adds work in progress regarding generic collections * Adds work in progress regarding generic collections * Adds work in progress regarding generic collections * Styling * Apply fixes from StyleCI * Apply fixes from StyleCI * Adds work in progress regarding generic collections * Remove work on Models * Revert "Remove work on Models" This reverts commit d6c42910a032f1647f07d42dc800d8be22a77963. * Removes `prefer-lowest` * Removes non needed code on CI job Co-authored-by: Dries Vints * Fixes `Eloquent\Collection::load` types * Adds work in progress regarding generic collections * Fixes `Eloquent\Collection::load` related methods Co-authored-by: Taylor Otwell Co-authored-by: Dries Vints --- .github/workflows/types.yml | 43 + composer.json | 1 + phpstan.neon.dist | 4 + src/Illuminate/Collections/Collection.php | 329 ++++--- src/Illuminate/Collections/Enumerable.php | 461 ++++++---- .../Collections/Traits/EnumeratesValues.php | 210 +++-- src/Illuminate/Collections/helpers.php | 7 +- .../Conditionable/Traits/Conditionable.php | 20 +- .../Contracts/Queue/QueueableCollection.php | 4 +- .../Contracts/Support/Arrayable.php | 6 +- .../Database/Eloquent/Collection.php | 121 +-- src/Illuminate/Database/Eloquent/Model.php | 2 +- types/Database/Eloquent/Collection.php | 186 ++++ types/Support/Collection.php | 861 ++++++++++++++++++ 14 files changed, 1755 insertions(+), 500 deletions(-) create mode 100644 .github/workflows/types.yml create mode 100644 phpstan.neon.dist create mode 100644 types/Database/Eloquent/Collection.php create mode 100644 types/Support/Collection.php diff --git a/.github/workflows/types.yml b/.github/workflows/types.yml new file mode 100644 index 000000000000..31b13134caf6 --- /dev/null +++ b/.github/workflows/types.yml @@ -0,0 +1,43 @@ +name: types + +on: + push: + pull_request: + schedule: + - cron: '0 0 * * *' + +jobs: + linux_tests: + runs-on: ubuntu-20.04 + + strategy: + fail-fast: true + matrix: + php: ['8.0'] + include: + - php: '8.1' + flags: "--ignore-platform-req=php" + + name: PHP ${{ matrix.php }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: none + + - name: Install dependencies + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress ${{ matrix.flags }} + + - name: Execute type checking + continue-on-error: ${{ matrix.php > 8 }} + run: vendor/bin/phpstan diff --git a/composer.json b/composer.json index 44dfcb489fd5..acb30f7d6344 100644 --- a/composer.json +++ b/composer.json @@ -88,6 +88,7 @@ "mockery/mockery": "^1.4.3", "orchestra/testbench-core": "^7.0", "pda/pheanstalk": "^4.0", + "phpstan/phpstan": "^0.12.94", "phpunit/phpunit": "^9.4", "predis/predis": "^1.1.2", "symfony/cache": "^6.0" diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 000000000000..609d438c7593 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,4 @@ +parameters: + paths: + - types + level: max diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index cbde79e64eb5..c5cdf2381327 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -8,21 +8,31 @@ use Illuminate\Support\Traits\Macroable; use stdClass; +/** + * @template TKey of array-key + * @template TValue + * + * @implements \ArrayAccess + * @implements \Illuminate\Support\Enumerable + */ class Collection implements ArrayAccess, Enumerable { + /** + * @use \Illuminate\Support\Traits\EnumeratesValues + */ use EnumeratesValues, Macroable; /** * The items contained in the collection. * - * @var array + * @var array */ protected $items = []; /** * Create a new collection. * - * @param mixed $items + * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items * @return void */ public function __construct($items = []) @@ -35,7 +45,7 @@ public function __construct($items = []) * * @param int $from * @param int $to - * @return static + * @return static */ public static function range($from, $to) { @@ -45,7 +55,7 @@ public static function range($from, $to) /** * Get all of the items in the collection. * - * @return array + * @return array */ public function all() { @@ -65,8 +75,8 @@ public function lazy() /** * Get the average value of a given key. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue): float|int)|string|null $callback + * @return float|int|null */ public function avg($callback = null) { @@ -86,8 +96,8 @@ public function avg($callback = null) /** * Get the median of a given key. * - * @param string|array|null $key - * @return mixed + * @param string|array|null $key + * @return float|int|null */ public function median($key = null) { @@ -116,8 +126,8 @@ public function median($key = null) /** * Get the mode of a given key. * - * @param string|array|null $key - * @return array|null + * @param string|array|null $key + * @return array|null */ public function mode($key = null) { @@ -145,7 +155,7 @@ public function mode($key = null) /** * Collapse the collection of items into a single array. * - * @return static + * @return static */ public function collapse() { @@ -155,7 +165,7 @@ public function collapse() /** * Determine if an item exists in the collection. * - * @param mixed $key + * @param (callable(TValue): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -178,8 +188,11 @@ public function contains($key, $operator = null, $value = null) /** * Cross join with the given lists, returning all possible permutations. * - * @param mixed ...$lists - * @return static + * @template TCrossJoinKey + * @template TCrossJoinValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists + * @return static> */ public function crossJoin(...$lists) { @@ -191,8 +204,8 @@ public function crossJoin(...$lists) /** * Get the items in the collection that are not present in the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function diff($items) { @@ -202,9 +215,9 @@ public function diff($items) /** * Get the items in the collection that are not present in the given items, using the callback. * - * @param mixed $items - * @param callable $callback - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @param callable(TValue): int $callback + * @return static */ public function diffUsing($items, callable $callback) { @@ -214,8 +227,8 @@ public function diffUsing($items, callable $callback) /** * Get the items in the collection whose keys and values are not present in the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function diffAssoc($items) { @@ -225,9 +238,9 @@ public function diffAssoc($items) /** * Get the items in the collection whose keys and values are not present in the given items, using the callback. * - * @param mixed $items - * @param callable $callback - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @param callable(TKey): int $callback + * @return static */ public function diffAssocUsing($items, callable $callback) { @@ -237,8 +250,8 @@ public function diffAssocUsing($items, callable $callback) /** * Get the items in the collection whose keys are not present in the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function diffKeys($items) { @@ -248,9 +261,9 @@ public function diffKeys($items) /** * Get the items in the collection whose keys are not present in the given items, using the callback. * - * @param mixed $items - * @param callable $callback - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @param callable(TKey): int $callback + * @return static */ public function diffKeysUsing($items, callable $callback) { @@ -260,9 +273,9 @@ public function diffKeysUsing($items, callable $callback) /** * Retrieve duplicate items from the collection. * - * @param callable|string|null $callback + * @param (callable(TValue): bool)|string|null $callback * @param bool $strict - * @return static + * @return static */ public function duplicates($callback = null, $strict = false) { @@ -288,8 +301,8 @@ public function duplicates($callback = null, $strict = false) /** * Retrieve duplicate items from the collection using strict comparison. * - * @param callable|string|null $callback - * @return static + * @param (callable(TValue): bool)|string|null $callback + * @return static */ public function duplicatesStrict($callback = null) { @@ -300,7 +313,7 @@ public function duplicatesStrict($callback = null) * Get the comparison function to detect duplicates. * * @param bool $strict - * @return \Closure + * @return callable(TValue, TValue): bool */ protected function duplicateComparator($strict) { @@ -318,8 +331,8 @@ protected function duplicateComparator($strict) /** * Get all items except for those with the specified keys. * - * @param \Illuminate\Support\Collection|mixed $keys - * @return static + * @param \Illuminate\Support\Enumerable|array $keys + * @return static */ public function except($keys) { @@ -335,8 +348,8 @@ public function except($keys) /** * Run a filter over each of the items. * - * @param callable|null $callback - * @return static + * @param (callable(TValue): bool)|null $callback + * @return static */ public function filter(callable $callback = null) { @@ -350,9 +363,11 @@ public function filter(callable $callback = null) /** * Get the first item from the collection passing the given truth test. * - * @param callable|null $callback - * @param mixed $default - * @return mixed + * @template TFirstDefault + * + * @param (callable(TValue): bool)|null $callback + * @param TFirstDefault $default + * @return TValue|TFirstDefault */ public function first(callable $callback = null, $default = null) { @@ -363,7 +378,7 @@ public function first(callable $callback = null, $default = null) * Get a flattened array of the items in the collection. * * @param int $depth - * @return static + * @return static */ public function flatten($depth = INF) { @@ -373,7 +388,7 @@ public function flatten($depth = INF) /** * Flip the items in the collection. * - * @return static + * @return static */ public function flip() { @@ -383,7 +398,7 @@ public function flip() /** * Remove an item from the collection by key. * - * @param string|array $keys + * @param TKey|array $keys * @return $this */ public function forget($keys) @@ -398,9 +413,11 @@ public function forget($keys) /** * Get an item from the collection by key. * - * @param mixed $key - * @param mixed $default - * @return mixed + * @template TGetDefault + * + * @param TKey $key + * @param TGetDefault $default + * @return TValue|TGetDefault */ public function get($key, $default = null) { @@ -414,9 +431,9 @@ public function get($key, $default = null) /** * Group an associative array by a field or using a callback. * - * @param array|callable|string $groupBy + * @param (callable(TValue, TKey): array-key)|array|string $groupBy * @param bool $preserveKeys - * @return static + * @return static> */ public function groupBy($groupBy, $preserveKeys = false) { @@ -460,8 +477,8 @@ public function groupBy($groupBy, $preserveKeys = false) /** * Key an associative array by a field or using a callback. * - * @param callable|string $keyBy - * @return static + * @param (callable(TValue, TKey): array-key)|array|string $keyBy + * @return static> */ public function keyBy($keyBy) { @@ -485,7 +502,7 @@ public function keyBy($keyBy) /** * Determine if an item exists in the collection by key. * - * @param mixed $key + * @param TKey|array $key * @return bool */ public function has($key) @@ -522,8 +539,8 @@ public function implode($value, $glue = null) /** * Intersect the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function intersect($items) { @@ -533,8 +550,8 @@ public function intersect($items) /** * Intersect the collection with the given items by key. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function intersectByKeys($items) { @@ -596,7 +613,7 @@ public function join($glue, $finalGlue = '') /** * Get the keys of the collection items. * - * @return static + * @return static */ public function keys() { @@ -606,9 +623,11 @@ public function keys() /** * Get the last item from the collection. * - * @param callable|null $callback - * @param mixed $default - * @return mixed + * @template TLastDefault + * + * @param (callable(TValue, TKey): bool)|null $callback + * @param TLastDefault $default + * @return TValue|TLastDefault */ public function last(callable $callback = null, $default = null) { @@ -618,9 +637,9 @@ public function last(callable $callback = null, $default = null) /** * Get the values of a given key. * - * @param string|array|int|null $value + * @param string|array $value * @param string|null $key - * @return static + * @return static */ public function pluck($value, $key = null) { @@ -630,8 +649,10 @@ public function pluck($value, $key = null) /** * Run a map over each of the items. * - * @param callable $callback - * @return static + * @template TMapValue + * + * @param callable(TValue, TKey): TMapValue $callback + * @return static */ public function map(callable $callback) { @@ -647,8 +668,11 @@ public function map(callable $callback) * * The callback should return an associative array with a single key/value pair. * - * @param callable $callback - * @return static + * @template TMapToDictionaryKey of array-key + * @template TMapToDictionaryValue + * + * @param callable(TValue, TKey): array $callback + * @return static> */ public function mapToDictionary(callable $callback) { @@ -676,8 +700,11 @@ public function mapToDictionary(callable $callback) * * The callback should return an associative array with a single key/value pair. * - * @param callable $callback - * @return static + * @template TMapWithKeysKey of array-key + * @template TMapWithKeysValue + * + * @param callable(TValue, TKey): array $callback + * @return static */ public function mapWithKeys(callable $callback) { @@ -697,8 +724,8 @@ public function mapWithKeys(callable $callback) /** * Merge the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function merge($items) { @@ -708,8 +735,8 @@ public function merge($items) /** * Recursively merge the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static> */ public function mergeRecursive($items) { @@ -719,8 +746,10 @@ public function mergeRecursive($items) /** * Create a collection by using this collection for keys and another for its values. * - * @param mixed $values - * @return static + * @template TCombineValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function combine($values) { @@ -730,8 +759,8 @@ public function combine($values) /** * Union the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function union($items) { @@ -743,7 +772,7 @@ public function union($items) * * @param int $step * @param int $offset - * @return static + * @return static */ public function nth($step, $offset = 0) { @@ -765,8 +794,8 @@ public function nth($step, $offset = 0) /** * Get the items with the specified keys. * - * @param mixed $keys - * @return static + * @param \Illuminate\Support\Enumerable|array $keys + * @return static */ public function only($keys) { @@ -787,7 +816,7 @@ public function only($keys) * Get and remove the last N items from the collection. * * @param int $count - * @return mixed + * @return static|TValue|null */ public function pop($count = 1) { @@ -813,8 +842,8 @@ public function pop($count = 1) /** * Push an item onto the beginning of the collection. * - * @param mixed $value - * @param mixed $key + * @param TValue $value + * @param TKey $key * @return $this */ public function prepend($value, $key = null) @@ -827,7 +856,7 @@ public function prepend($value, $key = null) /** * Push one or more items onto the end of the collection. * - * @param mixed $values [optional] + * @param ...TValue $values * @return $this */ public function push(...$values) @@ -842,8 +871,8 @@ public function push(...$values) /** * Push all of the given items onto the collection. * - * @param iterable $source - * @return static + * @param iterable $source + * @return static */ public function concat($source) { @@ -859,9 +888,11 @@ public function concat($source) /** * Get and remove an item from the collection. * - * @param mixed $key - * @param mixed $default - * @return mixed + * @template TPullDefault + * + * @param TKey $key + * @param TPullDefault $default + * @return TValue|TPullDefault */ public function pull($key, $default = null) { @@ -871,8 +902,8 @@ public function pull($key, $default = null) /** * Put an item in the collection by key. * - * @param mixed $key - * @param mixed $value + * @param TKey $key + * @param TValue $value * @return $this */ public function put($key, $value) @@ -886,7 +917,7 @@ public function put($key, $value) * Get one or a specified number of items randomly from the collection. * * @param int|null $number - * @return static|mixed + * @return static|TValue * * @throws \InvalidArgumentException */ @@ -902,8 +933,8 @@ public function random($number = null) /** * Replace the collection items with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function replace($items) { @@ -913,8 +944,8 @@ public function replace($items) /** * Recursively replace the collection items with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function replaceRecursive($items) { @@ -924,7 +955,7 @@ public function replaceRecursive($items) /** * Reverse items order. * - * @return static + * @return static */ public function reverse() { @@ -934,9 +965,9 @@ public function reverse() /** * Search the collection for a given value and return the corresponding key if successful. * - * @param mixed $value + * @param TValue|(callable(TValue,TKey): bool) $value * @param bool $strict - * @return mixed + * @return TKey|bool */ public function search($value, $strict = false) { @@ -957,7 +988,7 @@ public function search($value, $strict = false) * Get and remove the first N items from the collection. * * @param int $count - * @return mixed + * @return static|TValue|null */ public function shift($count = 1) { @@ -984,7 +1015,7 @@ public function shift($count = 1) * Shuffle the items in the collection. * * @param int|null $seed - * @return static + * @return static */ public function shuffle($seed = null) { @@ -996,7 +1027,7 @@ public function shuffle($seed = null) * * @param int $size * @param int $step - * @return static + * @return static> */ public function sliding($size = 2, $step = 1) { @@ -1011,7 +1042,7 @@ public function sliding($size = 2, $step = 1) * Skip the first {$count} items. * * @param int $count - * @return static + * @return static */ public function skip($count) { @@ -1021,8 +1052,8 @@ public function skip($count) /** * Skip items in the collection until the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function skipUntil($value) { @@ -1032,8 +1063,8 @@ public function skipUntil($value) /** * Skip items in the collection while the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function skipWhile($value) { @@ -1045,7 +1076,7 @@ public function skipWhile($value) * * @param int $offset * @param int|null $length - * @return static + * @return static */ public function slice($offset, $length = null) { @@ -1056,7 +1087,7 @@ public function slice($offset, $length = null) * Split a collection into a certain number of groups. * * @param int $numberOfGroups - * @return static + * @return static> */ public function split($numberOfGroups) { @@ -1093,7 +1124,7 @@ public function split($numberOfGroups) * Split a collection into a certain number of groups, and fill the first groups completely. * * @param int $numberOfGroups - * @return static + * @return static> */ public function splitIn($numberOfGroups) { @@ -1103,10 +1134,10 @@ public function splitIn($numberOfGroups) /** * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. * - * @param mixed $key + * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value - * @return mixed + * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException * @throws \Illuminate\Support\MultipleItemsFoundException @@ -1159,7 +1190,7 @@ public function firstOrFail($key = null, $operator = null, $value = null) * Chunk the collection into chunks of the given size. * * @param int $size - * @return static + * @return static> */ public function chunk($size) { @@ -1179,8 +1210,8 @@ public function chunk($size) /** * Chunk the collection into chunks with a callback. * - * @param callable $callback - * @return static + * @param callable(TValue, TKey, static): bool $callback + * @return static> */ public function chunkWhile(callable $callback) { @@ -1192,8 +1223,8 @@ public function chunkWhile(callable $callback) /** * Sort through each item with a callback. * - * @param callable|int|null $callback - * @return static + * @param (callable(TValue, TValue): bool)|null|int $callback + * @return static */ public function sort($callback = null) { @@ -1210,7 +1241,7 @@ public function sort($callback = null) * Sort items in descending order. * * @param int $options - * @return static + * @return static */ public function sortDesc($options = SORT_REGULAR) { @@ -1224,10 +1255,10 @@ public function sortDesc($options = SORT_REGULAR) /** * Sort the collection using the given callback. * - * @param callable|array|string $callback + * @param (callable(TValue, TKey): mixed)|string $callback * @param int $options * @param bool $descending - * @return static + * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { @@ -1306,9 +1337,9 @@ protected function sortByMany(array $comparisons = []) /** * Sort the collection in descending order using the given callback. * - * @param callable|string $callback + * @param (callable(TValue, TKey): mixed)|string $callback * @param int $options - * @return static + * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR) { @@ -1320,7 +1351,7 @@ public function sortByDesc($callback, $options = SORT_REGULAR) * * @param int $options * @param bool $descending - * @return static + * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false) { @@ -1335,7 +1366,7 @@ public function sortKeys($options = SORT_REGULAR, $descending = false) * Sort the collection keys in descending order. * * @param int $options - * @return static + * @return static */ public function sortKeysDesc($options = SORT_REGULAR) { @@ -1347,8 +1378,8 @@ public function sortKeysDesc($options = SORT_REGULAR) * * @param int $offset * @param int|null $length - * @param mixed $replacement - * @return static + * @param array $replacement + * @return static */ public function splice($offset, $length = null, $replacement = []) { @@ -1363,7 +1394,7 @@ public function splice($offset, $length = null, $replacement = []) * Take the first or last {$limit} items. * * @param int $limit - * @return static + * @return static */ public function take($limit) { @@ -1377,8 +1408,8 @@ public function take($limit) /** * Take items in the collection until the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function takeUntil($value) { @@ -1388,8 +1419,8 @@ public function takeUntil($value) /** * Take items in the collection while the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function takeWhile($value) { @@ -1399,7 +1430,7 @@ public function takeWhile($value) /** * Transform each item in the collection using a callback. * - * @param callable $callback + * @param callable(TValue, TKey): TValue $callback * @return $this */ public function transform(callable $callback) @@ -1412,7 +1443,7 @@ public function transform(callable $callback) /** * Reset the keys on the underlying array. * - * @return static + * @return static */ public function values() { @@ -1425,8 +1456,10 @@ public function values() * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * - * @param mixed ...$items - * @return static + * @template TZipValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items + * @return static> */ public function zip($items) { @@ -1444,9 +1477,11 @@ public function zip($items) /** * Pad collection to the specified length with a value. * + * @template TPadValue + * * @param int $size - * @param mixed $value - * @return static + * @param TPadValue $value + * @return static */ public function pad($size, $value) { @@ -1456,7 +1491,7 @@ public function pad($size, $value) /** * Get an iterator for the items. * - * @return \ArrayIterator + * @return \ArrayIterator */ #[\ReturnTypeWillChange] public function getIterator() @@ -1478,8 +1513,8 @@ public function count() /** * Count the number of items in the collection by a field or using a callback. * - * @param callable|string $countBy - * @return static + * @param (callable(TValue, TKey): mixed)|string|null $countBy + * @return static */ public function countBy($countBy = null) { @@ -1489,7 +1524,7 @@ public function countBy($countBy = null) /** * Add an item to the collection. * - * @param mixed $item + * @param TValue $item * @return $this */ public function add($item) @@ -1502,7 +1537,7 @@ public function add($item) /** * Get a base Support collection instance from this collection. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function toBase() { @@ -1512,7 +1547,7 @@ public function toBase() /** * Determine if an item exists at an offset. * - * @param mixed $key + * @param TKey $key * @return bool */ #[\ReturnTypeWillChange] @@ -1524,8 +1559,8 @@ public function offsetExists($key) /** * Get an item at a given offset. * - * @param mixed $key - * @return mixed + * @param TKey $key + * @return TValue */ #[\ReturnTypeWillChange] public function offsetGet($key) @@ -1536,8 +1571,8 @@ public function offsetGet($key) /** * Set the item at a given offset. * - * @param mixed $key - * @param mixed $value + * @param TKey|null $key + * @param TValue $value * @return void */ #[\ReturnTypeWillChange] @@ -1553,7 +1588,7 @@ public function offsetSet($key, $value) /** * Unset the item at a given offset. * - * @param string $key + * @param TKey $key * @return void */ #[\ReturnTypeWillChange] diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 59109e719e0f..c16e23077a6b 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -8,13 +8,23 @@ use IteratorAggregate; use JsonSerializable; +/** + * @template TKey of array-key + * @template TValue + * + * @extends \Illuminate\Contracts\Support\Arrayable + * @extends \IteratorAggregate + */ interface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable { /** * Create a new collection instance if the value isn't one already. * - * @param mixed $items - * @return static + * @template TMakeKey of array-key + * @template TMakeValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items + * @return static */ public static function make($items = []); @@ -39,23 +49,29 @@ public static function range($from, $to); /** * Wrap the given value in a collection if applicable. * - * @param mixed $value - * @return static + * @template TWrapKey of array-key + * @template TWrapValue + * + * @param iterable $value + * @return static */ public static function wrap($value); /** * Get the underlying items from the given collection if applicable. * - * @param array|static $value - * @return array + * @template TUnwrapKey of array-key + * @template TUnwrapValue + * + * @param array|static $value + * @return array */ public static function unwrap($value); /** * Create a new instance with no items. * - * @return static + * @return static */ public static function empty(); @@ -69,38 +85,38 @@ public function all(); /** * Alias for the "avg" method. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue): float|int)|string|null $callback + * @return float|int|null */ public function average($callback = null); /** * Get the median of a given key. * - * @param string|array|null $key - * @return mixed + * @param string|array|null $key + * @return float|int|null */ public function median($key = null); /** * Get the mode of a given key. * - * @param string|array|null $key - * @return array|null + * @param string|array|null $key + * @return array|null */ public function mode($key = null); /** * Collapse the items into a single enumerable. * - * @return static + * @return static */ public function collapse(); /** * Alias for the "contains" method. * - * @param mixed $key + * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -110,8 +126,8 @@ public function some($key, $operator = null, $value = null); /** * Determine if an item exists, using strict comparison. * - * @param mixed $key - * @param mixed $value + * @param (callable(TValue): bool)|TValue|string $key + * @param TValue|null $value * @return bool */ public function containsStrict($key, $value = null); @@ -119,15 +135,15 @@ public function containsStrict($key, $value = null); /** * Get the average value of a given key. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue): float|int)|string|null $callback + * @return float|int|null */ public function avg($callback = null); /** * Determine if an item exists in the enumerable. * - * @param mixed $key + * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -137,8 +153,11 @@ public function contains($key, $operator = null, $value = null); /** * Cross join with the given lists, returning all possible permutations. * - * @param mixed ...$lists - * @return static + * @template TCrossJoinKey + * @template TCrossJoinValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists + * @return static> */ public function crossJoin(...$lists); @@ -146,7 +165,7 @@ public function crossJoin(...$lists); * Dump the collection and end the script. * * @param mixed ...$args - * @return void + * @return never */ public function dd(...$args); @@ -160,75 +179,75 @@ public function dump(); /** * Get the items that are not present in the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function diff($items); /** * Get the items that are not present in the given items, using the callback. * - * @param mixed $items - * @param callable $callback - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @param callable(TValue): int $callback + * @return static */ public function diffUsing($items, callable $callback); /** * Get the items whose keys and values are not present in the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function diffAssoc($items); /** * Get the items whose keys and values are not present in the given items, using the callback. * - * @param mixed $items - * @param callable $callback - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @param callable(TKey): int $callback + * @return static */ public function diffAssocUsing($items, callable $callback); /** * Get the items whose keys are not present in the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function diffKeys($items); /** * Get the items whose keys are not present in the given items, using the callback. * - * @param mixed $items - * @param callable $callback - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @param callable(TKey): int $callback + * @return static */ public function diffKeysUsing($items, callable $callback); /** * Retrieve duplicate items. * - * @param callable|string|null $callback + * @param (callable(TValue): bool)|string|null $callback * @param bool $strict - * @return static + * @return static */ public function duplicates($callback = null, $strict = false); /** * Retrieve duplicate items using strict comparison. * - * @param callable|string|null $callback - * @return static + * @param (callable(TValue): bool)|string|null $callback + * @return static */ public function duplicatesStrict($callback = null); /** * Execute a callback over each item. * - * @param callable $callback + * @param callable(TValue): mixed $callback * @return $this */ public function each(callable $callback); @@ -236,15 +255,15 @@ public function each(callable $callback); /** * Execute a callback over each nested chunk of items. * - * @param callable $callback - * @return static + * @param callable(...mixed): mixed $callback + * @return static */ public function eachSpread(callable $callback); /** * Determine if all items pass the given truth test. * - * @param string|callable $key + * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -254,72 +273,84 @@ public function every($key, $operator = null, $value = null); /** * Get all items except for those with the specified keys. * - * @param mixed $keys - * @return static + * @param \Illuminate\Support\Enumerable|array $keys + * @return static */ public function except($keys); /** * Run a filter over each of the items. * - * @param callable|null $callback - * @return static + * @param (callable(TValue): bool)|null $callback + * @return static */ public function filter(callable $callback = null); /** * Apply the callback if the given "value" is (or resolves to) truthy. * + * @template TWhenReturnType as null + * * @param bool $value - * @param callable|null $callback - * @param callable|null $default - * @return static|mixed + * @param (callable($this): TWhenReturnType)|null $callback + * @param (callable($this): TWhenReturnType)|null $default + * @return $this|TWhenReturnType */ public function when($value, callable $callback = null, callable $default = null); /** * Apply the callback if the collection is empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TWhenEmptyReturnType + * + * @param (callable($this): TWhenEmptyReturnType) $callback + * @param (callable($this): TWhenEmptyReturnType)|null $default + * @return $this|TWhenEmptyReturnType */ public function whenEmpty(callable $callback, callable $default = null); /** * Apply the callback if the collection is not empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TWhenNotEmptyReturnType + * + * @param callable($this): TWhenNotEmptyReturnType $callback + * @param (callable($this): TWhenNotEmptyReturnType)|null $default + * @return $this|TWhenNotEmptyReturnType */ public function whenNotEmpty(callable $callback, callable $default = null); /** * Apply the callback if the given "value" is (or resolves to) truthy. * + * @template TWhenReturnType + * * @param bool $value - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @param (callable($this): TUnlessReturnType) $callback + * @param (callable($this): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType */ public function unless($value, callable $callback, callable $default = null); /** * Apply the callback unless the collection is empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TUnlessEmptyReturnType + * + * @param callable($this): TUnlessEmptyReturnType $callback + * @param (callable($this): TUnlessEmptyReturnType)|null $default + * @return $this|TUnlessEmptyReturnType */ public function unlessEmpty(callable $callback, callable $default = null); /** * Apply the callback unless the collection is not empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TUnlessNotEmptyReturnType + * + * @param callable($this): TUnlessNotEmptyReturnType $callback + * @param (callable($this): TUnlessNotEmptyReturnType)|null $default + * @return $this|TUnlessNotEmptyReturnType */ public function unlessNotEmpty(callable $callback, callable $default = null); @@ -329,7 +360,7 @@ public function unlessNotEmpty(callable $callback, callable $default = null); * @param string $key * @param mixed $operator * @param mixed $value - * @return static + * @return static */ public function where($key, $operator = null, $value = null); @@ -337,7 +368,7 @@ public function where($key, $operator = null, $value = null); * Filter items where the value for the given key is null. * * @param string|null $key - * @return static + * @return static */ public function whereNull($key = null); @@ -345,7 +376,7 @@ public function whereNull($key = null); * Filter items where the value for the given key is not null. * * @param string|null $key - * @return static + * @return static */ public function whereNotNull($key = null); @@ -354,7 +385,7 @@ public function whereNotNull($key = null); * * @param string $key * @param mixed $value - * @return static + * @return static */ public function whereStrict($key, $value); @@ -362,9 +393,9 @@ public function whereStrict($key, $value); * Filter items by the given key value pair. * * @param string $key - * @param mixed $values + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict - * @return static + * @return static */ public function whereIn($key, $values, $strict = false); @@ -372,8 +403,8 @@ public function whereIn($key, $values, $strict = false); * Filter items by the given key value pair using strict comparison. * * @param string $key - * @param mixed $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereInStrict($key, $values); @@ -381,8 +412,8 @@ public function whereInStrict($key, $values); * Filter items such that the value of the given key is between the given values. * * @param string $key - * @param array $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereBetween($key, $values); @@ -390,8 +421,8 @@ public function whereBetween($key, $values); * Filter items such that the value of the given key is not between the given values. * * @param string $key - * @param array $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereNotBetween($key, $values); @@ -399,9 +430,9 @@ public function whereNotBetween($key, $values); * Filter items by the given key value pair. * * @param string $key - * @param mixed $values + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict - * @return static + * @return static */ public function whereNotIn($key, $values, $strict = false); @@ -409,25 +440,27 @@ public function whereNotIn($key, $values, $strict = false); * Filter items by the given key value pair using strict comparison. * * @param string $key - * @param mixed $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereNotInStrict($key, $values); /** * Filter the items, removing any items that don't match the given type(s). * - * @param string|string[] $type - * @return static + * @param class-string|array $type + * @return static */ public function whereInstanceOf($type); /** * Get the first item from the enumerable passing the given truth test. * - * @param callable|null $callback - * @param mixed $default - * @return mixed + * @template TFirstDefault + * + * @param (callable(TValue): bool)|null $callback + * @param TFirstDefault $default + * @return TValue|TFirstDefault */ public function first(callable $callback = null, $default = null); @@ -437,7 +470,7 @@ public function first(callable $callback = null, $default = null); * @param string $key * @param mixed $operator * @param mixed $value - * @return mixed + * @return TValue|null */ public function firstWhere($key, $operator = null, $value = null); @@ -445,47 +478,49 @@ public function firstWhere($key, $operator = null, $value = null); * Get a flattened array of the items in the collection. * * @param int $depth - * @return static + * @return static */ public function flatten($depth = INF); /** * Flip the values with their keys. * - * @return static + * @return static */ public function flip(); /** * Get an item from the collection by key. * - * @param mixed $key - * @param mixed $default - * @return mixed + * @template TGetDefault + * + * @param TKey $key + * @param TGetDefault $default + * @return TValue|TGetDefault */ public function get($key, $default = null); /** * Group an associative array by a field or using a callback. * - * @param array|callable|string $groupBy + * @param (callable(TValue, TKey): array-key)|array|string $groupBy * @param bool $preserveKeys - * @return static + * @return static> */ public function groupBy($groupBy, $preserveKeys = false); /** * Key an associative array by a field or using a callback. * - * @param callable|string $keyBy - * @return static + * @param (callable(TValue, TKey): array-key)|array|string $keyBy + * @return static> */ public function keyBy($keyBy); /** * Determine if an item exists in the collection by key. * - * @param mixed $key + * @param TKey|array $key * @return bool */ public function has($key); @@ -502,16 +537,16 @@ public function implode($value, $glue = null); /** * Intersect the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function intersect($items); /** * Intersect the collection with the given items by key. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function intersectByKeys($items); @@ -541,32 +576,38 @@ public function join($glue, $finalGlue = ''); /** * Get the keys of the collection items. * - * @return static + * @return static */ public function keys(); /** * Get the last item from the collection. * - * @param callable|null $callback - * @param mixed $default - * @return mixed + * @template TLastDefault + * + * @param (callable(TValue, TKey): bool)|null $callback + * @param TLastDefault $default + * @return TValue|TLastDefault */ public function last(callable $callback = null, $default = null); /** * Run a map over each of the items. * - * @param callable $callback - * @return static + * @template TMapValue + * + * @param callable(TValue, TKey): TMapValue $callback + * @return static */ public function map(callable $callback); /** * Run a map over each nested chunk of items. * - * @param callable $callback - * @return static + * @template TMapSpreadValue + * + * @param callable(...mixed): TMapSpreadValue $callback + * @return static */ public function mapSpread(callable $callback); @@ -575,8 +616,11 @@ public function mapSpread(callable $callback); * * The callback should return an associative array with a single key/value pair. * - * @param callable $callback - * @return static + * @template TMapToDictionaryKey of array-key + * @template TMapToDictionaryValue + * + * @param callable(TValue, TKey): array $callback + * @return static> */ public function mapToDictionary(callable $callback); @@ -585,8 +629,11 @@ public function mapToDictionary(callable $callback); * * The callback should return an associative array with a single key/value pair. * - * @param callable $callback - * @return static + * @template TMapToGroupsKey of array-key + * @template TMapToGroupsValue + * + * @param callable(TValue, TKey): array $callback + * @return static> */ public function mapToGroups(callable $callback); @@ -595,72 +642,77 @@ public function mapToGroups(callable $callback); * * The callback should return an associative array with a single key/value pair. * - * @param callable $callback - * @return static + * @template TMapWithKeysKey of array-key + * @template TMapWithKeysValue + * + * @param callable(TValue, TKey): array $callback + * @return static */ public function mapWithKeys(callable $callback); /** * Map a collection and flatten the result by a single level. * - * @param callable $callback - * @return static + * @param callable(TValue, TKey): mixed $callback + * @return static */ public function flatMap(callable $callback); /** * Map the values into a new class. * - * @param string $class - * @return static + * @param class-string $class + * @return static */ public function mapInto($class); /** * Merge the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function merge($items); /** * Recursively merge the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static> */ public function mergeRecursive($items); /** * Create a collection by using this collection for keys and another for its values. * - * @param mixed $values - * @return static + * @template TCombineValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function combine($values); /** * Union the collection with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function union($items); /** * Get the min value of a given key. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue):mixed)|string|null $callback + * @return TValue */ public function min($callback = null); /** * Get the max value of a given key. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue):mixed)|string|null $callback + * @return TValue */ public function max($callback = null); @@ -669,15 +721,15 @@ public function max($callback = null); * * @param int $step * @param int $offset - * @return static + * @return static */ public function nth($step, $offset = 0); /** * Get the items with the specified keys. * - * @param mixed $keys - * @return static + * @param \Illuminate\Support\Enumerable|array $keys + * @return static */ public function only($keys); @@ -686,25 +738,25 @@ public function only($keys); * * @param int $page * @param int $perPage - * @return static + * @return static */ public function forPage($page, $perPage); /** * Partition the collection into two arrays using the given callback or key. * - * @param callable|string $key + * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value - * @return static + * @return array> */ public function partition($key, $operator = null, $value = null); /** * Push all of the given items onto the collection. * - * @param iterable $source - * @return static + * @param iterable $source + * @return static */ public function concat($source); @@ -712,7 +764,7 @@ public function concat($source); * Get one or a specified number of items randomly from the collection. * * @param int|null $number - * @return static|mixed + * @return static|TValue * * @throws \InvalidArgumentException */ @@ -721,41 +773,44 @@ public function random($number = null); /** * Reduce the collection to a single value. * - * @param callable $callback - * @param mixed $initial - * @return mixed + * @template TReduceInitial + * @template TReduceReturnType + * + * @param callable(TReduceInitial|TReduceReturnType, TValue): TReduceReturnType $callback + * @param TReduceInitial $initial + * @return TReduceReturnType */ public function reduce(callable $callback, $initial = null); /** * Replace the collection items with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function replace($items); /** * Recursively replace the collection items with the given items. * - * @param mixed $items - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $items + * @return static */ public function replaceRecursive($items); /** * Reverse items order. * - * @return static + * @return static */ public function reverse(); /** * Search the collection for a given value and return the corresponding key if successful. * - * @param mixed $value + * @param TValue|callable(TValue,TKey): bool $value * @param bool $strict - * @return mixed + * @return TKey|bool */ public function search($value, $strict = false); @@ -763,7 +818,7 @@ public function search($value, $strict = false); * Shuffle the items in the collection. * * @param int|null $seed - * @return static + * @return static */ public function shuffle($seed = null); @@ -771,23 +826,23 @@ public function shuffle($seed = null); * Skip the first {$count} items. * * @param int $count - * @return static + * @return static */ public function skip($count); /** * Skip items in the collection until the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function skipUntil($value); /** * Skip items in the collection while the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function skipWhile($value); @@ -796,7 +851,7 @@ public function skipWhile($value); * * @param int $offset * @param int|null $length - * @return static + * @return static */ public function slice($offset, $length = null); @@ -804,17 +859,17 @@ public function slice($offset, $length = null); * Split a collection into a certain number of groups. * * @param int $numberOfGroups - * @return static + * @return static> */ public function split($numberOfGroups); /** * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. * - * @param mixed $key + * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value - * @return mixed + * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException * @throws \Illuminate\Support\MultipleItemsFoundException @@ -825,23 +880,23 @@ public function sole($key = null, $operator = null, $value = null); * Chunk the collection into chunks of the given size. * * @param int $size - * @return static + * @return static> */ public function chunk($size); /** * Chunk the collection into chunks with a callback. * - * @param callable $callback - * @return static + * @param callable(TValue, TKey, static): bool $callback + * @return static> */ public function chunkWhile(callable $callback); /** * Sort through each item with a callback. * - * @param callable|null|int $callback - * @return static + * @param (callable(TValue, TValue): bool)|null|int $callback + * @return static */ public function sort($callback = null); @@ -849,26 +904,26 @@ public function sort($callback = null); * Sort items in descending order. * * @param int $options - * @return static + * @return static */ public function sortDesc($options = SORT_REGULAR); /** * Sort the collection using the given callback. * - * @param callable|string $callback + * @param (callable(TValue, TKey): mixed)|string $callback * @param int $options * @param bool $descending - * @return static + * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false); /** * Sort the collection in descending order using the given callback. * - * @param callable|string $callback + * @param (callable(TValue, TKey): mixed)|string $callback * @param int $options - * @return static + * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR); @@ -877,7 +932,7 @@ public function sortByDesc($callback, $options = SORT_REGULAR); * * @param int $options * @param bool $descending - * @return static + * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false); @@ -885,14 +940,14 @@ public function sortKeys($options = SORT_REGULAR, $descending = false); * Sort the collection keys in descending order. * * @param int $options - * @return static + * @return static */ public function sortKeysDesc($options = SORT_REGULAR); /** * Get the sum of the given values. * - * @param callable|string|null $callback + * @param (callable(TValue): mixed)|string|null $callback * @return mixed */ public function sum($callback = null); @@ -901,30 +956,30 @@ public function sum($callback = null); * Take the first or last {$limit} items. * * @param int $limit - * @return static + * @return static */ public function take($limit); /** * Take items in the collection until the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function takeUntil($value); /** * Take items in the collection while the given condition is met. * - * @param mixed $value - * @return static + * @param TValue|callable(TValue,TKey): bool $value + * @return static */ public function takeWhile($value); /** * Pass the collection to the given callback and then return it. * - * @param callable $callback + * @param callable(TValue): mixed $callback * @return $this */ public function tap(callable $callback); @@ -932,66 +987,70 @@ public function tap(callable $callback); /** * Pass the enumerable to the given callback and return the result. * - * @param callable $callback - * @return mixed + * @template TPipeReturnType + * + * @param callable($this): TPipeReturnType $callback + * @return TPipeReturnType */ public function pipe(callable $callback); /** * Get the values of a given key. * - * @param string|array $value + * @param string|array $value * @param string|null $key - * @return static + * @return static */ public function pluck($value, $key = null); /** * Create a collection of all elements that do not pass a given truth test. * - * @param callable|mixed $callback - * @return static + * @param (callable(TValue): bool)|bool $callback + * @return static */ public function reject($callback = true); /** * Return only unique items from the collection array. * - * @param string|callable|null $key + * @param (callable(TValue, TKey): bool)|string|null $key * @param bool $strict - * @return static + * @return static */ public function unique($key = null, $strict = false); /** * Return only unique items from the collection array using strict comparison. * - * @param string|callable|null $key - * @return static + * @param (callable(TValue, TKey): bool)|string|null $key + * @return static */ public function uniqueStrict($key = null); /** * Reset the keys on the underlying array. * - * @return static + * @return static */ public function values(); /** * Pad collection to the specified length with a value. * + * @template TPadValue + * * @param int $size - * @param mixed $value - * @return static + * @param TPadValue $value + * @return static */ public function pad($size, $value); /** * Count the number of items in the collection using a given truth test. * - * @param callable|null $callback - * @return static + * @param (callable(TValue, TKey): mixed)|string|null $callback + * @return static */ public function countBy($callback = null); @@ -1001,15 +1060,17 @@ public function countBy($callback = null); * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * - * @param mixed ...$items - * @return static + * @template TZipValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items + * @return static> */ public function zip($items); /** * Collect the values into a collection. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function collect(); diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 530bfe3bd321..09487fd2ad0d 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -16,6 +16,9 @@ use Traversable; /** + * @template TKey of array-key + * @template TValue + * * @property-read HigherOrderCollectionProxy $average * @property-read HigherOrderCollectionProxy $avg * @property-read HigherOrderCollectionProxy $contains @@ -51,7 +54,7 @@ trait EnumeratesValues /** * The methods that can be proxied. * - * @var string[] + * @var array */ protected static $proxies = [ 'average', @@ -86,8 +89,11 @@ trait EnumeratesValues /** * Create a new collection instance if the value isn't one already. * - * @param mixed $items - * @return static + * @template TMakeKey of array-key + * @template TMakeValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items + * @return static */ public static function make($items = []) { @@ -97,8 +103,11 @@ public static function make($items = []) /** * Wrap the given value in a collection if applicable. * - * @param mixed $value - * @return static + * @template TWrapKey of array-key + * @template TWrapValue + * + * @param iterable $value + * @return static */ public static function wrap($value) { @@ -110,8 +119,11 @@ public static function wrap($value) /** * Get the underlying items from the given collection if applicable. * - * @param array|static $value - * @return array + * @template TUnwrapKey of array-key + * @template TUnwrapValue + * + * @param array|static $value + * @return array */ public static function unwrap($value) { @@ -121,7 +133,7 @@ public static function unwrap($value) /** * Create a new instance with no items. * - * @return static + * @return static */ public static function empty() { @@ -131,9 +143,11 @@ public static function empty() /** * Create a new collection by invoking the callback a given amount of times. * + * @template TTimesValue + * * @param int $number - * @param callable|null $callback - * @return static + * @param (callable(int): TTimesValue)|null $callback + * @return static */ public static function times($number, callable $callback = null) { @@ -149,8 +163,8 @@ public static function times($number, callable $callback = null) /** * Alias for the "avg" method. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue): float|int)|string|null $callback + * @return float|int|null */ public function average($callback = null) { @@ -160,7 +174,7 @@ public function average($callback = null) /** * Alias for the "contains" method. * - * @param mixed $key + * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -173,8 +187,8 @@ public function some($key, $operator = null, $value = null) /** * Determine if an item exists, using strict comparison. * - * @param mixed $key - * @param mixed $value + * @param (callable(TValue): bool)|TValue|string $key + * @param TValue|null $value * @return bool */ public function containsStrict($key, $value = null) @@ -202,7 +216,7 @@ public function containsStrict($key, $value = null) * Dump the items and end the script. * * @param mixed ...$args - * @return void + * @return never */ public function dd(...$args) { @@ -230,7 +244,7 @@ public function dump() /** * Execute a callback over each item. * - * @param callable $callback + * @param callable(TValue): mixed $callback * @return $this */ public function each(callable $callback) @@ -247,8 +261,8 @@ public function each(callable $callback) /** * Execute a callback over each nested chunk of items. * - * @param callable $callback - * @return static + * @param callable(...mixed): mixed $callback + * @return static */ public function eachSpread(callable $callback) { @@ -262,7 +276,7 @@ public function eachSpread(callable $callback) /** * Determine if all items pass the given truth test. * - * @param string|callable $key + * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -290,7 +304,7 @@ public function every($key, $operator = null, $value = null) * @param string $key * @param mixed $operator * @param mixed $value - * @return mixed + * @return TValue|null */ public function firstWhere($key, $operator = null, $value = null) { @@ -310,8 +324,10 @@ public function isNotEmpty() /** * Run a map over each nested chunk of items. * - * @param callable $callback - * @return static + * @template TMapSpreadValue + * + * @param callable(mixed): TMapSpreadValue $callback + * @return static */ public function mapSpread(callable $callback) { @@ -327,8 +343,11 @@ public function mapSpread(callable $callback) * * The callback should return an associative array with a single key/value pair. * - * @param callable $callback - * @return static + * @template TMapToGroupsKey of array-key + * @template TMapToGroupsValue + * + * @param callable(TValue, TKey): array $callback + * @return static> */ public function mapToGroups(callable $callback) { @@ -340,8 +359,8 @@ public function mapToGroups(callable $callback) /** * Map a collection and flatten the result by a single level. * - * @param callable $callback - * @return static + * @param callable(TValue, TKey): mixed $callback + * @return static */ public function flatMap(callable $callback) { @@ -351,8 +370,8 @@ public function flatMap(callable $callback) /** * Map the values into a new class. * - * @param string $class - * @return static + * @param class-string $class + * @return static */ public function mapInto($class) { @@ -364,8 +383,8 @@ public function mapInto($class) /** * Get the min value of a given key. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue):mixed)|string|null $callback + * @return TValue */ public function min($callback = null) { @@ -383,8 +402,8 @@ public function min($callback = null) /** * Get the max value of a given key. * - * @param callable|string|null $callback - * @return mixed + * @param (callable(TValue):mixed)|string|null $callback + * @return TValue */ public function max($callback = null) { @@ -416,10 +435,10 @@ public function forPage($page, $perPage) /** * Partition the collection into two arrays using the given callback or key. * - * @param callable|string $key - * @param mixed $operator - * @param mixed $value - * @return static + * @param (callable(TValue, TKey): bool)|TValue|string $key + * @param TValue|string|null $operator + * @param TValue|null $value + * @return array> */ public function partition($key, $operator = null, $value = null) { @@ -444,7 +463,7 @@ public function partition($key, $operator = null, $value = null) /** * Get the sum of the given values. * - * @param callable|string|null $callback + * @param (callable(TValue): mixed)|string|null $callback * @return mixed */ public function sum($callback = null) @@ -461,9 +480,11 @@ public function sum($callback = null) /** * Apply the callback if the collection is empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TWhenEmptyReturnType + * + * @param (callable($this): TWhenEmptyReturnType) $callback + * @param (callable($this): TWhenEmptyReturnType)|null $default + * @return $this|TWhenEmptyReturnType */ public function whenEmpty(callable $callback, callable $default = null) { @@ -473,9 +494,11 @@ public function whenEmpty(callable $callback, callable $default = null) /** * Apply the callback if the collection is not empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TWhenNotEmptyReturnType + * + * @param callable($this): TWhenNotEmptyReturnType $callback + * @param (callable($this): TWhenNotEmptyReturnType)|null $default + * @return $this|TWhenNotEmptyReturnType */ public function whenNotEmpty(callable $callback, callable $default = null) { @@ -485,9 +508,11 @@ public function whenNotEmpty(callable $callback, callable $default = null) /** * Apply the callback unless the collection is empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TUnlessEmptyReturnType + * + * @param callable($this): TUnlessEmptyReturnType $callback + * @param (callable($this): TUnlessEmptyReturnType)|null $default + * @return $this|TUnlessEmptyReturnType */ public function unlessEmpty(callable $callback, callable $default = null) { @@ -497,9 +522,11 @@ public function unlessEmpty(callable $callback, callable $default = null) /** * Apply the callback unless the collection is not empty. * - * @param callable $callback - * @param callable|null $default - * @return static|mixed + * @template TUnlessNotEmptyReturnType + * + * @param callable($this): TUnlessNotEmptyReturnType $callback + * @param (callable($this): TUnlessNotEmptyReturnType)|null $default + * @return $this|TUnlessNotEmptyReturnType */ public function unlessNotEmpty(callable $callback, callable $default = null) { @@ -512,7 +539,7 @@ public function unlessNotEmpty(callable $callback, callable $default = null) * @param string $key * @param mixed $operator * @param mixed $value - * @return static + * @return static */ public function where($key, $operator = null, $value = null) { @@ -523,7 +550,7 @@ public function where($key, $operator = null, $value = null) * Filter items where the value for the given key is null. * * @param string|null $key - * @return static + * @return static */ public function whereNull($key = null) { @@ -534,7 +561,7 @@ public function whereNull($key = null) * Filter items where the value for the given key is not null. * * @param string|null $key - * @return static + * @return static */ public function whereNotNull($key = null) { @@ -546,7 +573,8 @@ public function whereNotNull($key = null) * * @param string $key * @param mixed $value - * @return static + * @param bool $strict + * @return static */ public function whereStrict($key, $value) { @@ -557,9 +585,9 @@ public function whereStrict($key, $value) * Filter items by the given key value pair. * * @param string $key - * @param mixed $values + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict - * @return static + * @return static */ public function whereIn($key, $values, $strict = false) { @@ -574,8 +602,8 @@ public function whereIn($key, $values, $strict = false) * Filter items by the given key value pair using strict comparison. * * @param string $key - * @param mixed $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereInStrict($key, $values) { @@ -586,8 +614,8 @@ public function whereInStrict($key, $values) * Filter items such that the value of the given key is between the given values. * * @param string $key - * @param array $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereBetween($key, $values) { @@ -598,8 +626,8 @@ public function whereBetween($key, $values) * Filter items such that the value of the given key is not between the given values. * * @param string $key - * @param array $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereNotBetween($key, $values) { @@ -612,9 +640,9 @@ public function whereNotBetween($key, $values) * Filter items by the given key value pair. * * @param string $key - * @param mixed $values + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict - * @return static + * @return static */ public function whereNotIn($key, $values, $strict = false) { @@ -629,8 +657,8 @@ public function whereNotIn($key, $values, $strict = false) * Filter items by the given key value pair using strict comparison. * * @param string $key - * @param mixed $values - * @return static + * @param \Illuminate\Contracts\Support\Arrayable|iterable $values + * @return static */ public function whereNotInStrict($key, $values) { @@ -640,8 +668,8 @@ public function whereNotInStrict($key, $values) /** * Filter the items, removing any items that don't match the given type(s). * - * @param string|string[] $type - * @return static + * @param class-string|array $type + * @return static */ public function whereInstanceOf($type) { @@ -663,8 +691,10 @@ public function whereInstanceOf($type) /** * Pass the collection to the given callback and return the result. * - * @param callable $callback - * @return mixed + * @template TPipeReturnType + * + * @param callable($this): TPipeReturnType $callback + * @return TPipeReturnType */ public function pipe(callable $callback) { @@ -674,7 +704,7 @@ public function pipe(callable $callback) /** * Pass the collection into a new class. * - * @param string $class + * @param string-class $class * @return mixed */ public function pipeInto($class) @@ -685,9 +715,12 @@ public function pipeInto($class) /** * Reduce the collection to a single value. * - * @param callable $callback - * @param mixed $initial - * @return mixed + * @template TReduceInitial + * @template TReduceReturnType + * + * @param callable(TReduceInitial|TReduceReturnType, TValue): TReduceReturnType $callback + * @param TReduceInitial $initial + * @return TReduceReturnType */ public function reduce(callable $callback, $initial = null) { @@ -703,9 +736,12 @@ public function reduce(callable $callback, $initial = null) /** * Reduce an associative collection to a single value. * - * @param callable $callback - * @param mixed $initial - * @return mixed + * @template TReduceWithKeysInitial + * @template TReduceWithKeysReturnType + * + * @param callable(TReduceWithKeysInitial|TReduceWithKeysReturnType, TValue): TReduceWithKeysReturnType $callback + * @param TReduceWithKeysInitial $initial + * @return TReduceWithKeysReturnType */ public function reduceWithKeys(callable $callback, $initial = null) { @@ -715,8 +751,8 @@ public function reduceWithKeys(callable $callback, $initial = null) /** * Create a collection of all elements that do not pass a given truth test. * - * @param callable|mixed $callback - * @return static + * @param (callable(TValue): bool)|bool $callback + * @return static */ public function reject($callback = true) { @@ -732,7 +768,7 @@ public function reject($callback = true) /** * Pass the collection to the given callback and then return it. * - * @param callable $callback + * @param callable(TValue): mixed $callback * @return $this */ public function tap(callable $callback) @@ -745,9 +781,9 @@ public function tap(callable $callback) /** * Return only unique items from the collection array. * - * @param string|callable|null $key + * @param (callable(TValue, TKey): bool)|string|null $key * @param bool $strict - * @return static + * @return static */ public function unique($key = null, $strict = false) { @@ -767,8 +803,8 @@ public function unique($key = null, $strict = false) /** * Return only unique items from the collection array using strict comparison. * - * @param string|callable|null $key - * @return static + * @param (callable(TValue, TKey): bool)|string|null $key + * @return static */ public function uniqueStrict($key = null) { @@ -778,7 +814,7 @@ public function uniqueStrict($key = null) /** * Collect the values into a collection. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function collect() { @@ -788,7 +824,7 @@ public function collect() /** * Get the collection of items as a plain array. * - * @return array + * @return array */ public function toArray() { @@ -800,7 +836,7 @@ public function toArray() /** * Convert the object into something JSON serializable. * - * @return array + * @return array */ #[\ReturnTypeWillChange] public function jsonSerialize() diff --git a/src/Illuminate/Collections/helpers.php b/src/Illuminate/Collections/helpers.php index 5138b2cd1a12..45fc6d40510d 100644 --- a/src/Illuminate/Collections/helpers.php +++ b/src/Illuminate/Collections/helpers.php @@ -7,8 +7,11 @@ /** * Create a collection from the given value. * - * @param mixed $value - * @return \Illuminate\Support\Collection + * @template TKey of array-key + * @template TValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $value + * @return \Illuminate\Support\Collection */ function collect($value = null) { diff --git a/src/Illuminate/Conditionable/Traits/Conditionable.php b/src/Illuminate/Conditionable/Traits/Conditionable.php index 924051fb7260..aa77df52759b 100644 --- a/src/Illuminate/Conditionable/Traits/Conditionable.php +++ b/src/Illuminate/Conditionable/Traits/Conditionable.php @@ -10,10 +10,12 @@ trait Conditionable /** * Apply the callback if the given "value" is (or resolves to) truthy. * - * @param mixed $value - * @param callable|null $callback - * @param callable|null $default - * @return $this|mixed + * @template TWhenReturnType + * + * @param bool $value + * @param (callable($this): TWhenReturnType)|null $callback + * @param (callable($this): TWhenReturnType)|null $default + * @return $this|TWhenReturnType */ public function when($value, callable $callback = null, callable $default = null) { @@ -35,10 +37,12 @@ public function when($value, callable $callback = null, callable $default = null /** * Apply the callback if the given "value" is (or resolves to) falsy. * - * @param mixed $value - * @param callable|null $callback - * @param callable|null $default - * @return $this|mixed + * @template TUnlessReturnType + * + * @param bool $value + * @param (callable($this): TUnlessReturnType) $callback + * @param (callable($this): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType */ public function unless($value, callable $callback = null, callable $default = null) { diff --git a/src/Illuminate/Contracts/Queue/QueueableCollection.php b/src/Illuminate/Contracts/Queue/QueueableCollection.php index 7f1ea19c5436..750d10d4b088 100644 --- a/src/Illuminate/Contracts/Queue/QueueableCollection.php +++ b/src/Illuminate/Contracts/Queue/QueueableCollection.php @@ -14,14 +14,14 @@ public function getQueueableClass(); /** * Get the identifiers for all of the entities. * - * @return array + * @return array */ public function getQueueableIds(); /** * Get the relationships of the entities being queued. * - * @return array + * @return array */ public function getQueueableRelations(); diff --git a/src/Illuminate/Contracts/Support/Arrayable.php b/src/Illuminate/Contracts/Support/Arrayable.php index 5ad93b70bd3b..3194bd1163e0 100755 --- a/src/Illuminate/Contracts/Support/Arrayable.php +++ b/src/Illuminate/Contracts/Support/Arrayable.php @@ -2,12 +2,16 @@ namespace Illuminate\Contracts\Support; +/** + * @template TKey of array-key + * @template TValue + */ interface Arrayable { /** * Get the instance as an array. * - * @return array + * @return array */ public function toArray(); } diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index ff9b2747fe3e..be2fcc60c688 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -10,14 +10,22 @@ use Illuminate\Support\Str; use LogicException; +/** + * @template TKey of array-key + * @template TModel of \Illuminate\Database\Eloquent\Model + * + * @extends \Illuminate\Support\Collection + */ class Collection extends BaseCollection implements QueueableCollection { /** * Find a model in the collection by key. * + * @template TFindDefault + * * @param mixed $key - * @param mixed $default - * @return \Illuminate\Database\Eloquent\Model|static|null + * @param TFindDefault $default + * @return static|TModel|TFindDefault */ public function find($key, $default = null) { @@ -45,7 +53,7 @@ public function find($key, $default = null) /** * Load a set of relationships onto the collection. * - * @param array|string $relations + * @param array|string $relations * @return $this */ public function load($relations) @@ -66,9 +74,9 @@ public function load($relations) /** * Load a set of aggregations over relationship's column onto the collection. * - * @param array|string $relations + * @param array|string $relations * @param string $column - * @param string $function + * @param string|null $function * @return $this */ public function loadAggregate($relations, $column, $function = null) @@ -101,7 +109,7 @@ public function loadAggregate($relations, $column, $function = null) /** * Load a set of relationship counts onto the collection. * - * @param array|string $relations + * @param array|string $relations * @return $this */ public function loadCount($relations) @@ -112,7 +120,7 @@ public function loadCount($relations) /** * Load a set of relationship's max column values onto the collection. * - * @param array|string $relations + * @param array|string $relations * @param string $column * @return $this */ @@ -124,7 +132,7 @@ public function loadMax($relations, $column) /** * Load a set of relationship's min column values onto the collection. * - * @param array|string $relations + * @param array|string $relations * @param string $column * @return $this */ @@ -136,7 +144,7 @@ public function loadMin($relations, $column) /** * Load a set of relationship's column summations onto the collection. * - * @param array|string $relations + * @param array|string $relations * @param string $column * @return $this */ @@ -148,7 +156,7 @@ public function loadSum($relations, $column) /** * Load a set of relationship's average column values onto the collection. * - * @param array|string $relations + * @param array|string $relations * @param string $column * @return $this */ @@ -160,7 +168,7 @@ public function loadAvg($relations, $column) /** * Load a set of related existences onto the collection. * - * @param array|string $relations + * @param array|string $relations * @return $this */ public function loadExists($relations) @@ -171,7 +179,7 @@ public function loadExists($relations) /** * Load a set of relationships onto the collection if they are not already eager loaded. * - * @param array|string $relations + * @param array|string $relations * @return $this */ public function loadMissing($relations) @@ -245,7 +253,7 @@ protected function loadMissingRelation(self $models, array $path) * Load a set of relationships onto the mixed relationship collection. * * @param string $relation - * @param array $relations + * @param array $relations * @return $this */ public function loadMorph($relation, $relations) @@ -266,7 +274,7 @@ public function loadMorph($relation, $relations) * Load a set of relationship counts onto the mixed relationship collection. * * @param string $relation - * @param array $relations + * @param array $relations * @return $this */ public function loadMorphCount($relation, $relations) @@ -286,7 +294,7 @@ public function loadMorphCount($relation, $relations) /** * Determine if a key exists in the collection. * - * @param mixed $key + * @param (callable(TModel, TKey): bool)|TModel|string $key * @param mixed $operator * @param mixed $value * @return bool @@ -311,7 +319,7 @@ public function contains($key, $operator = null, $value = null) /** * Get the array of primary keys. * - * @return array + * @return array */ public function modelKeys() { @@ -323,8 +331,8 @@ public function modelKeys() /** * Merge the collection with the given items. * - * @param \ArrayAccess|array $items - * @return static + * @param iterable $items + * @return static */ public function merge($items) { @@ -340,8 +348,10 @@ public function merge($items) /** * Run a map over each of the items. * - * @param callable $callback - * @return \Illuminate\Support\Collection|static + * @template TMapValue + * + * @param callable(TModel, TKey): TMapValue $callback + * @return \Illuminate\Support\Collection|static */ public function map(callable $callback) { @@ -357,8 +367,11 @@ public function map(callable $callback) * * The callback should return an associative array with a single key / value pair. * - * @param callable $callback - * @return \Illuminate\Support\Collection|static + * @template TMapWithKeysKey of array-key + * @template TMapWithKeysValue + * + * @param callable(TModel, TKey): array $callback + * @return \Illuminate\Support\Collection|static */ public function mapWithKeys(callable $callback) { @@ -372,8 +385,8 @@ public function mapWithKeys(callable $callback) /** * Reload a fresh model instance from the database for all the entities. * - * @param array|string $with - * @return static + * @param array|string $with + * @return static */ public function fresh($with = []) { @@ -400,8 +413,8 @@ public function fresh($with = []) /** * Diff the collection with the given items. * - * @param \ArrayAccess|array $items - * @return static + * @param iterable $items + * @return static */ public function diff($items) { @@ -421,8 +434,8 @@ public function diff($items) /** * Intersect the collection with the given items. * - * @param \ArrayAccess|array $items - * @return static + * @param iterable $items + * @return static */ public function intersect($items) { @@ -446,9 +459,9 @@ public function intersect($items) /** * Return only unique items from the collection. * - * @param string|callable|null $key + * @param (callable(TModel, TKey): bool)|string|null $key * @param bool $strict - * @return static + * @return static */ public function unique($key = null, $strict = false) { @@ -462,8 +475,8 @@ public function unique($key = null, $strict = false) /** * Returns only the models from the collection with the specified keys. * - * @param mixed $keys - * @return static + * @param array|null $keys + * @return static */ public function only($keys) { @@ -479,8 +492,8 @@ public function only($keys) /** * Returns all models in the collection except the models with specified keys. * - * @param mixed $keys - * @return static + * @param array|null $keys + * @return static */ public function except($keys) { @@ -492,7 +505,7 @@ public function except($keys) /** * Make the given, typically visible, attributes hidden across the entire collection. * - * @param array|string $attributes + * @param array|string $attributes * @return $this */ public function makeHidden($attributes) @@ -503,7 +516,7 @@ public function makeHidden($attributes) /** * Make the given, typically hidden, attributes visible across the entire collection. * - * @param array|string $attributes + * @param array|string $attributes * @return $this */ public function makeVisible($attributes) @@ -514,7 +527,7 @@ public function makeVisible($attributes) /** * Append an attribute across the entire collection. * - * @param array|string $attributes + * @param array|string $attributes * @return $this */ public function append($attributes) @@ -525,8 +538,8 @@ public function append($attributes) /** * Get a dictionary keyed by primary keys. * - * @param \ArrayAccess|array|null $items - * @return array + * @param iterable|null $items + * @return array */ public function getDictionary($items = null) { @@ -548,9 +561,9 @@ public function getDictionary($items = null) /** * Get an array with the values of a given key. * - * @param string|array $value + * @param string|array $value * @param string|null $key - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function pluck($value, $key = null) { @@ -560,7 +573,7 @@ public function pluck($value, $key = null) /** * Get the keys of the collection items. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function keys() { @@ -570,8 +583,10 @@ public function keys() /** * Zip the collection together with one or more arrays. * - * @param mixed ...$items - * @return \Illuminate\Support\Collection + * @template TZipValue + * + * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items + * @return \Illuminate\Support\Collection> */ public function zip($items) { @@ -581,7 +596,7 @@ public function zip($items) /** * Collapse the collection of items into a single array. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function collapse() { @@ -592,7 +607,7 @@ public function collapse() * Get a flattened array of the items in the collection. * * @param int $depth - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function flatten($depth = INF) { @@ -602,7 +617,7 @@ public function flatten($depth = INF) /** * Flip the items in the collection. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ public function flip() { @@ -612,9 +627,11 @@ public function flip() /** * Pad collection to the specified length with a value. * + * @template TPadValue + * * @param int $size - * @param mixed $value - * @return \Illuminate\Support\Collection + * @param TPadValue $value + * @return \Illuminate\Support\Collection */ public function pad($size, $value) { @@ -625,7 +642,7 @@ public function pad($size, $value) * Get the comparison function to detect duplicates. * * @param bool $strict - * @return \Closure + * @return callable(TValue, TValue): bool */ protected function duplicateComparator($strict) { @@ -661,7 +678,7 @@ public function getQueueableClass() /** * Get the identifiers for all of the entities. * - * @return array + * @return array */ public function getQueueableIds() { @@ -677,7 +694,7 @@ public function getQueueableIds() /** * Get the relationships of the entities being queued. * - * @return array + * @return array */ public function getQueueableRelations() { diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 2222ffe1a46e..8fee029b5357 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -526,7 +526,7 @@ public static function onWriteConnection() * Get all of the models from the database. * * @param array|mixed $columns - * @return \Illuminate\Database\Eloquent\Collection|static[] + * @return \Illuminate\Database\Eloquent\Collection */ public static function all($columns = ['*']) { diff --git a/types/Database/Eloquent/Collection.php b/types/Database/Eloquent/Collection.php new file mode 100644 index 000000000000..f1b3527005ad --- /dev/null +++ b/types/Database/Eloquent/Collection.php @@ -0,0 +1,186 @@ +', $collection); + +assertType('Illuminate\Database\Eloquent\Collection|User|null', $collection->find(1)); +assertType('Illuminate\Database\Eloquent\Collection|string|User', $collection->find(1, 'string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->load('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->load(['string'])); +assertType('Illuminate\Database\Eloquent\Collection', $collection->load(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAggregate('string', 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAggregate(['string'], 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAggregate(['string'], 'string', 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAggregate(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}], 'string', 'string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadCount('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadCount(['string'])); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadCount(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMax('string', 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMax(['string'], 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMax(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}], 'string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMin('string', 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMin(['string'], 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMin(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}], 'string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadSum('string', 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadSum(['string'], 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadSum(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}], 'string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAvg('string', 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAvg(['string'], 'string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadAvg(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}], 'string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadExists('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadExists(['string'])); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadExists(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMissing('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMissing(['string'])); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMissing(['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMorph('string', ['string'])); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMorph('string', ['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMorphCount('string', ['string'])); +assertType('Illuminate\Database\Eloquent\Collection', $collection->loadMorphCount('string', ['string' => function ($query) { + // assertType('\Illuminate\Database\Query\Builder', $query); +}])); + +assertType('bool', $collection->contains(function ($user) { + assertType('User', $user); + + return true; +})); +assertType('bool', $collection->contains('string', '=', 'string')); + +assertType('array', $collection->modelKeys()); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->merge($collection)); +assertType('Illuminate\Database\Eloquent\Collection', $collection->merge([new User])); + +assertType( + 'Illuminate\Support\Collection', + $collection->map(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return new User; + }) +); + +assertType( + 'Illuminate\Support\Collection', + $collection->mapWithKeys(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return [new User]; + }) +); +assertType( + 'Illuminate\Support\Collection', + $collection->mapWithKeys(function ($user, $int) { + return ['string' => new User]; + }) +); + +assertType( + 'Illuminate\Database\Eloquent\Collection', + $collection->fresh() +); +assertType( + 'Illuminate\Database\Eloquent\Collection', + $collection->fresh('string') +); +assertType( + 'Illuminate\Database\Eloquent\Collection', + $collection->fresh(['string']) +); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->diff($collection)); +assertType('Illuminate\Database\Eloquent\Collection', $collection->diff([new User])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->intersect($collection)); +assertType('Illuminate\Database\Eloquent\Collection', $collection->intersect([new User])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->unique()); +assertType('Illuminate\Database\Eloquent\Collection', $collection->unique(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); +assertType('Illuminate\Database\Eloquent\Collection', $collection->unique('string')); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->only(null)); +assertType('Illuminate\Database\Eloquent\Collection', $collection->only(['string'])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->except(null)); +assertType('Illuminate\Database\Eloquent\Collection', $collection->except(['string'])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->makeHidden('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->makeHidden(['string'])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->makeVisible('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->makeVisible(['string'])); + +assertType('Illuminate\Database\Eloquent\Collection', $collection->append('string')); +assertType('Illuminate\Database\Eloquent\Collection', $collection->append(['string'])); + +assertType('array', $collection->getDictionary()); +assertType('array', $collection->getDictionary($collection)); +assertType('array', $collection->getDictionary([new User])); + +assertType('Illuminate\Support\Collection', $collection->pluck('string')); +assertType('Illuminate\Support\Collection', $collection->pluck(['string'])); + +assertType('Illuminate\Support\Collection', $collection->keys()); + +assertType('Illuminate\Support\Collection>', $collection->zip([1])); +assertType('Illuminate\Support\Collection>', $collection->zip(['string'])); + +assertType('Illuminate\Support\Collection', $collection->collapse()); + +assertType('Illuminate\Support\Collection', $collection->flatten()); +assertType('Illuminate\Support\Collection', $collection->flatten(4)); + +assertType('Illuminate\Support\Collection', $collection->flip()); + +assertType('Illuminate\Support\Collection', $collection->pad(2, 0)); +assertType('Illuminate\Support\Collection', $collection->pad(2, 'string')); + +assertType('array', $collection->getQueueableIds()); + +assertType('array', $collection->getQueueableRelations()); diff --git a/types/Support/Collection.php b/types/Support/Collection.php new file mode 100644 index 000000000000..c11e5f40c6b0 --- /dev/null +++ b/types/Support/Collection.php @@ -0,0 +1,861 @@ + $arrayable */ +$arrayable = []; +/** @var iterable $iterable */ +$iterable = []; +/** @var Traversable $traversable */ +$traversable = []; + +assertType('Illuminate\Support\Collection', $collection); + +assertType('Illuminate\Support\Collection', collect(['string'])); +assertType('Illuminate\Support\Collection', collect(['string' => new User])); +assertType('Illuminate\Support\Collection', collect($arrayable)); +assertType('Illuminate\Support\Collection', collect($collection)); +assertType('Illuminate\Support\Collection', collect($collection)); +assertType('Illuminate\Support\Collection', collect($iterable)); +assertType('Illuminate\Support\Collection', collect($traversable)); + +assertType('Illuminate\Support\Collection', $collection::make(['string'])); +assertType('Illuminate\Support\Collection', $collection::make(['string' => new User])); +assertType('Illuminate\Support\Collection', $collection::make($arrayable)); +assertType('Illuminate\Support\Collection', $collection::make($collection)); +assertType('Illuminate\Support\Collection', $collection::make($collection)); +assertType('Illuminate\Support\Collection', $collection::make($iterable)); +assertType('Illuminate\Support\Collection', $collection::make($traversable)); + +assertType('Illuminate\Support\Collection', $collection::times(10, function ($int) { + // assertType('int', $int); + + return new User; +})); + +assertType('Illuminate\Support\Collection', $collection::times(10, function () { + return new User; +})); + +assertType('Illuminate\Support\Collection', $collection->each(function ($user) { + assertType('User', $user); +})); + +assertType('Illuminate\Support\Collection', $collection->range(1, 100)); + +assertType('Illuminate\Support\Collection', $collection->wrap(['string'])); +assertType('Illuminate\Support\Collection', $collection->wrap(['string' => new User])); + +assertType('array', $collection->unwrap(['string'])); +assertType('array', $collection->unwrap( + $collection +)); + +assertType('Illuminate\Support\Collection', $collection::empty()); + +assertType('float|int|null', $collection->average()); +assertType('float|int|null', $collection->average('string')); +assertType('float|int|null', $collection->average(function ($user) { + assertType('User', $user); + + return 1; +})); +assertType('float|int|null', $collection->average(function ($user) { + assertType('User', $user); + + return 0.1; +})); + +assertType('float|int|null', $collection->median()); +assertType('float|int|null', $collection->median('string')); +assertType('float|int|null', $collection->median(['string'])); + +assertType('array|null', $collection->mode()); +assertType('array|null', $collection->mode('string')); +assertType('array|null', $collection->mode(['string'])); + +assertType('Illuminate\Support\Collection', $collection->collapse()); + +assertType('bool', $collection->some(function ($user) { + assertType('User', $user); + + return true; +})); +assertType('bool', $collection::make(['string'])->some('string', '=', 'string')); + +assertType('bool', $collection->containsStrict(function ($user) { + assertType('User', $user); + + return true; +})); +assertType('bool', $collection::make(['string'])->containsStrict('string', 'string')); + +assertType('float|int|null', $collection->avg()); +assertType('float|int|null', $collection->avg('string')); +assertType('float|int|null', $collection->avg(function ($user) { + assertType('User', $user); + + return 1; +})); +assertType('float|int|null', $collection->avg(function ($user) { + assertType('User', $user); + + return 0.1; +})); + +assertType('bool', $collection->contains(function ($user) { + assertType('User', $user); + + return true; +})); +assertType('bool', $collection::make(['string'])->contains('string', '=', 'string')); + +assertType('Illuminate\Support\Collection>', $collection->crossJoin($collection::make(['string']))); +assertType('Illuminate\Support\Collection>', $collection->crossJoin([1, 2])); + +assertType('Illuminate\Support\Collection', $collection::make([3, 4])->diff([1, 2])); +assertType('Illuminate\Support\Collection', $collection::make(['string-1'])->diff(['string-2'])); + +assertType('Illuminate\Support\Collection', $collection::make([3, 4])->diffUsing([1, 2], function ($int) { + assertType('int', $int); + + return -1; +})); +assertType('Illuminate\Support\Collection', $collection::make(['string-1'])->diffUsing(['string-2'], function ($string) { + assertType('string', $string); + + return -1; +})); + +assertType('Illuminate\Support\Collection', $collection::make([3, 4])->diffAssoc([1, 2])); +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string'])->diffAssoc(['string' => 'string'])); + +assertType('Illuminate\Support\Collection', $collection::make([3, 4])->diffAssocUsing([1, 2], function ($int) { + assertType('int', $int); + + return -1; +})); +assertType('Illuminate\Support\Collection', $collection::make(['string-1'])->diffAssocUsing(['string-2'], function ($int) { + assertType('int', $int); + + return -1; +})); + +assertType('Illuminate\Support\Collection', $collection::make([3, 4])->diffKeys([1, 2])); +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string'])->diffKeys(['string' => 'string'])); + +assertType('Illuminate\Support\Collection', $collection::make([3, 4])->diffKeysUsing([1, 2], function ($int) { + assertType('int', $int); + + return -1; +})); +assertType('Illuminate\Support\Collection', $collection::make(['string-1'])->diffKeysUsing(['string-2'], function ($int) { + assertType('int', $int); + + return -1; +})); + +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string']) + ->duplicates()); +assertType('Illuminate\Support\Collection', $collection->duplicates('name', true)); +assertType('Illuminate\Support\Collection', $collection::make([3, 'string']) + ->duplicates(function ($intOrString) { + assertType('int|string', $intOrString); + + return true; + })); + +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string']) + ->duplicatesStrict()); +assertType('Illuminate\Support\Collection', $collection->duplicatesStrict('name')); +assertType('Illuminate\Support\Collection', $collection::make([3, 'string']) + ->duplicatesStrict(function ($intOrString) { + assertType('int|string', $intOrString); + + return true; + })); + +assertType('Illuminate\Support\Collection', $collection->each(function ($user) { + assertType('User', $user); + + return null; +})); +assertType('Illuminate\Support\Collection', $collection->each(function ($user) { + assertType('User', $user); +})); + +assertType('Illuminate\Support\Collection', $collection::make([['string']]) + ->eachSpread(function ($int, $string) { + // assertType('int', $int); + // assertType('int', $string); + + return null; + })); +assertType('Illuminate\Support\Collection', $collection::make([[1, 'string']]) + ->eachSpread(function ($int, $string) { + // assertType('int', $int); + // assertType('int', $string); + })); + +assertType('bool', $collection->every(function ($user, $int) { + assertType('int', $int); + assertType('User', $user); + + return true; +})); +assertType('bool', $collection::make(['string'])->every('string', '=', 'string')); + +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string'])->except(['string'])); +assertType('Illuminate\Support\Collection', $collection->except([1])); +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->except($collection->keys()->toArray())); + +assertType('Illuminate\Support\Collection', $collection->filter()); +assertType('Illuminate\Support\Collection', $collection->filter(function ($user) { + assertType('User', $user); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->filter()); +assertType('Illuminate\Support\Collection', $collection->filter(function ($user) { + assertType('User', $user); + + return true; +})); + +assertType('bool|Illuminate\Support\Collection', $collection->when(true, function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); +assertType('Illuminate\Support\Collection|void', $collection->when(true, function ($collection) { + assertType('Illuminate\Support\Collection', $collection); +})); +assertType('Illuminate\Support\Collection|string', $collection->when(true, function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 'string'; +})); + +assertType('bool|Illuminate\Support\Collection', $collection->whenEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); +assertType('Illuminate\Support\Collection|void', $collection->whenEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); +})); +assertType('Illuminate\Support\Collection|string', $collection->whenEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 'string'; +})); + +assertType('bool|Illuminate\Support\Collection', $collection->whenNotEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); +assertType('Illuminate\Support\Collection|void', $collection->whenNotEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); +})); +assertType('Illuminate\Support\Collection|string', $collection->whenNotEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 'string'; +})); + +assertType('bool|Illuminate\Support\Collection', $collection->unless(true, function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); +assertType('Illuminate\Support\Collection|void', $collection->unless(true, function ($collection) { + assertType('Illuminate\Support\Collection', $collection); +})); +assertType('Illuminate\Support\Collection|string', $collection->unless(true, function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 'string'; +})); + +assertType('bool|Illuminate\Support\Collection', $collection->unlessEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); +assertType('Illuminate\Support\Collection|void', $collection->unlessEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); +})); +assertType('Illuminate\Support\Collection|string', $collection->unlessEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 'string'; +})); + +assertType('bool|Illuminate\Support\Collection', $collection->unlessNotEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); +assertType('Illuminate\Support\Collection|void', $collection->unlessNotEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); +})); +assertType('Illuminate\Support\Collection|string', $collection->unlessNotEmpty(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 'string'; +})); + +assertType("Illuminate\Support\Collection string)>", $collection::make([['string' => 'string']]) + ->where('string')); +assertType("Illuminate\Support\Collection string)>", $collection::make([['string' => 'string']]) + ->where('string', '=', 'string')); +assertType("Illuminate\Support\Collection string)>", $collection::make([['string' => 'string']]) + ->where('string', 'string')); + +assertType('Illuminate\Support\Collection', $collection->whereNull()); +assertType('Illuminate\Support\Collection', $collection->whereNull('foo')); + +assertType('Illuminate\Support\Collection', $collection->whereNotNull()); +assertType('Illuminate\Support\Collection', $collection->whereNotNull('foo')); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereStrict('string', 2)); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereIn('string', [2])); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereInStrict('string', [2])); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereBetween('string', [1, 3])); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereNotBetween('string', [1, 3])); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereNotIn('string', [2])); + +assertType("Illuminate\Support\Collection int)>", $collection::make([['string' => 2]]) + ->whereNotInStrict('string', [2])); + +assertType('Illuminate\Support\Collection', $collection::make([new User, 1]) + ->whereInstanceOf(User::class)); + +assertType('Illuminate\Support\Collection', $collection::make([new User, 1]) + ->whereInstanceOf([User::class, User::class])); + +assertType('User|null', $collection->first()); +assertType('User|null', $collection->first(function ($user) { + assertType('User', $user); + + return true; +})); +assertType('string|User', $collection->first(function ($user) { + assertType('User', $user); + + return false; +}, 'string')); + +assertType('Illuminate\Support\Collection', $collection->flatten()); +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string'])->flatten(4)); + +assertType('User|null', $collection->firstWhere('string', 'string')); +assertType('User|null', $collection->firstWhere('string', 'string', 'string')); + +assertType('Illuminate\Support\Collection', $collection::make(['string'])->flip()); + +assertType('Illuminate\Support\Collection<(int|string), array>', $collection->groupBy('name')); +assertType('Illuminate\Support\Collection<(int|string), array>', $collection->groupBy('name', true)); +assertType('Illuminate\Support\Collection<(int|string), array>', $collection->groupBy(function ($user, $int) { + // assertType('User', $user); + // assertType('int', $int); + + return 'foo'; +})); +assertType('Illuminate\Support\Collection<(int|string), array>', $collection->groupBy(function ($user) { + return 'foo'; +})); + +assertType('Illuminate\Support\Collection<(int|string), array>', $collection->keyBy('name')); +assertType('Illuminate\Support\Collection<(int|string), array>', $collection->keyBy(function ($user, $int) { + // assertType('User', $user); + // assertType('int', $int); + + return 'foo'; +})); + +assertType('bool', $collection->has(0)); +assertType('bool', $collection->has([0, 1])); + +assertType('Illuminate\Support\Collection', $collection->intersect([new User])); + +assertType('Illuminate\Support\Collection', $collection->intersectByKeys([new User])); + +assertType('Illuminate\Support\Collection', $collection->keys()); + +assertType('User|null', $collection->last()); +assertType('User|null', $collection->last(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); +assertType('string|User', $collection->last(function () { + return true; +}, 'string')); + +assertType('Illuminate\Support\Collection', $collection->map(function () { + return 1; +})); +assertType('Illuminate\Support\Collection', $collection->map(function () { + return 'string'; +})); + +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->map(function ($string, $int) { + assertType('string', $string); + assertType('int', $int); + + return (string) $string; + })); + +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->mapSpread(function () { + return 'string'; + })); + +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->mapSpread(function () { + return 1; + })); + +assertType('Illuminate\Support\Collection>', $collection::make(['string', 'string']) + ->mapToDictionary(function ($stringValue, $stringKey) { + assertType('string', $stringValue); + assertType('int', $stringKey); + + return ['string' => 1]; + })); + +assertType('Illuminate\Support\Collection>', $collection::make(['string', 'string']) + ->mapToGroups(function ($stringValue, $stringKey) { + assertType('string', $stringValue); + assertType('int', $stringKey); + + return ['string' => 1]; + })); + +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->mapWithKeys(function ($string, $int) { + assertType('string', $string); + assertType('int', $int); + + return ['string' => 1]; + })); + +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->flatMap(function ($string, $int) { + assertType('string', $string); + assertType('int', $int); + + return 1; + })); + +assertType('Illuminate\Support\Collection', $collection->mapInto(User::class)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->merge([2])); +assertType('Illuminate\Support\Collection', $collection->make(['string'])->merge(['string'])); + +assertType('Illuminate\Support\Collection>', $collection->make([1])->mergeRecursive([2])); +assertType('Illuminate\Support\Collection>', $collection->make(['string'])->mergeRecursive(['string'])); + +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->combine([2])); +assertType('Illuminate\Support\Collection', $collection->make([1])->combine([1])); + +assertType('Illuminate\Support\Collection', $collection->make([1])->union([1])); +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->union(['string' => 'string'])); + +assertType('int', $collection->make([1])->min()); +assertType('int', $collection->make([1])->min('string')); +assertType('int', $collection->make([1])->min(function ($int) { + assertType('int', $int); + + return 1; +})); + +assertType('int', $collection->make([1])->max()); +assertType('int', $collection->make([1])->max('string')); +assertType('int', $collection->make([1])->max(function ($int) { + assertType('int', $int); + + return 1; +})); + +assertType('Illuminate\Support\Collection', $collection->nth(1, 2)); + +assertType('Illuminate\Support\Collection', $collection::make(['string' => 'string'])->only(['string'])); +assertType('Illuminate\Support\Collection', $collection->only([1])); +assertType('Illuminate\Support\Collection', $collection::make(['string']) + ->only($collection->keys()->toArray())); + +assertType('Illuminate\Support\Collection', $collection->forPage(1, 2)); + +assertType('array>', $collection->partition(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); +assertType('array>', $collection::make(['string'])->partition('string', '=', 'string')); +assertType('array>', $collection::make(['string'])->partition('string', 'string')); +assertType('array>', $collection::make(['string'])->partition('string', )); + +assertType('Illuminate\Support\Collection', $collection->make([1])->concat([2])); +assertType('Illuminate\Support\Collection', $collection->make(['string'])->concat(['string'])); + +assertType('Illuminate\Support\Collection|int', $collection->make([1])->random(2)); +assertType('Illuminate\Support\Collection|string', $collection->make(['string'])->random()); + +assertType('int', $collection + ->reduce(function ($null, $user) { + assertType('User', $user); + assertType('int|null', $null); + + return 1; + })); +assertType('int', $collection + ->reduce(function ($int, $user) { + assertType('User', $user); + assertType('int', $int); + + return 1; + }, 0)); + +assertType('int', $collection + ->reduceWithKeys(function ($null, $user) { + assertType('User', $user); + assertType('int|null', $null); + + return 1; + })); +assertType('int', $collection + ->reduceWithKeys(function ($int, $user) { + assertType('User', $user); + assertType('int', $int); + + return 1; + }, 0)); + +assertType('Illuminate\Support\Collection', $collection::make([1])->replace([1])); +assertType('Illuminate\Support\Collection', $collection->replace([new User])); + +assertType('Illuminate\Support\Collection', $collection::make([1])->replaceRecursive([1])); +assertType('Illuminate\Support\Collection', $collection->replaceRecursive([new User])); + +assertType('Illuminate\Support\Collection', $collection->reverse()); + +// assertType('int|bool', $collection->make([1])->search(2)); +// assertType('string|bool', $collection->make(['string' => 'string'])->search('string')); +// assertType('int|bool', $collection->search(function ($user, $int) { +// assertType('User', $user); +// assertType('int', $int); +// +// return true; +// })); + +assertType('Illuminate\Support\Collection', $collection->make([1])->shuffle()); +assertType('Illuminate\Support\Collection', $collection->shuffle()); + +assertType('Illuminate\Support\Collection', $collection->make([1])->skip(1)); +assertType('Illuminate\Support\Collection', $collection->skip(1)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->skipUntil(1)); +assertType('Illuminate\Support\Collection', $collection->skipUntil(new User)); +assertType('Illuminate\Support\Collection', $collection->skipUntil(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->make([1])->skipWhile(1)); +assertType('Illuminate\Support\Collection', $collection->skipWhile(new User)); +assertType('Illuminate\Support\Collection', $collection->skipWhile(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->make([1])->slice(1)); +assertType('Illuminate\Support\Collection', $collection->slice(1, 2)); + +assertType('Illuminate\Support\Collection>', $collection->split(3)); +assertType('Illuminate\Support\Collection>', $collection->make([1])->split(3)); + +assertType('string', $collection->make(['string' => 'string'])->sole('string', 'string')); +assertType('string', $collection->make(['string' => 'string'])->sole('string', '=', 'string')); +assertType('User', $collection->sole(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); + +assertType('Illuminate\Support\Collection>', $collection::make(['string'])->chunk(1)); +assertType('Illuminate\Support\Collection>', $collection->chunk(2)); + +assertType('Illuminate\Support\Collection>', $collection->chunkWhile(function ($user, $int, $collection) { + assertType('User', $user); + assertType('int', $int); + assertType('Illuminate\Support\Collection', $collection); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->sort(function ($userA, $userB) { + assertType('User', $userA); + assertType('User', $userB); + + return true; +})); +assertType('Illuminate\Support\Collection', $collection->sort()); + +assertType('Illuminate\Support\Collection', $collection->sortDesc()); +assertType('Illuminate\Support\Collection', $collection->sortDesc(2)); + +assertType('Illuminate\Support\Collection', $collection->sortBy(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return 1; +})); +assertType('Illuminate\Support\Collection', $collection->sortBy('string')); +assertType('Illuminate\Support\Collection', $collection->sortBy('string', 1, false)); + +assertType('Illuminate\Support\Collection', $collection->sortByDesc(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return 1; +})); + +assertType('Illuminate\Support\Collection', $collection->make([1])->sortKeys()); +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->sortKeys(1, true)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->sortKeysDesc()); +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->sortKeysDesc(1)); + +assertType('mixed', $collection->make([1])->sum('string')); +assertType('mixed', $collection->make(['string'])->sum(function ($string) { + assertType('string', $string); + + return 1; +})); + +assertType('Illuminate\Support\Collection', $collection->make([1])->take(1)); +assertType('Illuminate\Support\Collection', $collection->take(1)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->takeUntil(1)); +assertType('Illuminate\Support\Collection', $collection->takeUntil(new User)); +assertType('Illuminate\Support\Collection', $collection->takeUntil(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->make([1])->takeWhile(1)); +assertType('Illuminate\Support\Collection', $collection->takeWhile(new User)); +assertType('Illuminate\Support\Collection', $collection->takeWhile(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->tap(function ($user) { + assertType('User', $user); +})); + +assertType('Illuminate\Support\Collection', $collection->pipe(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return collect([1]); +})); +assertType('int', $collection->make([1])->pipe(function ($collection) { + assertType('Illuminate\Support\Collection', $collection); + + return 1; +})); + +assertType('mixed', $collection->pipeInto(User::class)); + +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->pluck('string')); +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->pluck('string', 'string')); + +assertType('Illuminate\Support\Collection', $collection->reject()); +assertType('Illuminate\Support\Collection', $collection->reject(function ($user) { + assertType('User', $user); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->unique()); +assertType('Illuminate\Support\Collection', $collection->unique(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->unique(function ($stringA, $stringB) { + assertType('string', $stringA); + assertType('string', $stringA); + + return false; +}, true)); + +assertType('Illuminate\Support\Collection', $collection->uniqueStrict()); +assertType('Illuminate\Support\Collection', $collection->uniqueStrict(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return true; +})); + +assertType('Illuminate\Support\Collection', $collection->values()); +assertType('Illuminate\Support\Collection', $collection::make(['string', 'string'])->values()); +assertType('Illuminate\Support\Collection', $collection::make(['string', 1])->values()); + +assertType('Illuminate\Support\Collection', $collection->make([1])->pad(2, 0)); +assertType('Illuminate\Support\Collection', $collection->make([1])->pad(2, 'string')); +assertType('Illuminate\Support\Collection', $collection->pad(2, 0)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->countBy()); +assertType('Illuminate\Support\Collection', $collection->make(['string' => 'string'])->countBy('string')); +assertType('Illuminate\Support\Collection', $collection->make(['string'])->countBy(function ($string, $int) { + assertType('string', $string); + assertType('int', $int); + + return false; +})); + +assertType('Illuminate\Support\Collection>', $collection->zip([1])); +assertType('Illuminate\Support\Collection>', $collection->zip(['string'])); +assertType('Illuminate\Support\Collection>', $collection::make(['string' => 'string'])->zip(['string'])); + +assertType('Illuminate\Support\Collection', $collection->collect()); +assertType('Illuminate\Support\Collection', $collection->make([1])->collect()); + +assertType('Illuminate\Support\Collection', $collection->make([1])->push(2)); + +assertType('array', $collection->all()); + +assertType('User|null', $collection->get(0)); +assertType('string|User', $collection->get(0, 'string')); + +assertType('Illuminate\Support\Collection', $collection->forget(1)); +assertType('Illuminate\Support\Collection', $collection->forget([1, 2])); + +assertType('Illuminate\Support\Collection|User|null', $collection->pop(1)); +assertType('Illuminate\Support\Collection|string|null', $collection::make([ + 'string-key-1' => 'string-value-1', + 'string-key-2' => 'string-value-2', +])->pop(2)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->prepend(2)); +assertType('Illuminate\Support\Collection', $collection->prepend(new User, 2)); + +assertType('Illuminate\Support\Collection', $collection->make([1])->push(2)); +assertType('Illuminate\Support\Collection', $collection->push(new User, new User)); + +assertType('User|null', $collection->pull(1)); +assertType('string|User', $collection->pull(1, 'string')); + +assertType('Illuminate\Support\Collection', $collection->put(1, new User)); +assertType('Illuminate\Support\Collection', $collection::make([ + 'string-key-1' => 'string-value-1', +])->put('string-key-2', 'string-value-2')); + +assertType('Illuminate\Support\Collection|User|null', $collection->shift(1)); +assertType('Illuminate\Support\Collection|string|null', $collection::make([ + 'string-key-1' => 'string-value-1', + 'string-key-2' => 'string-value-2', +])->shift(2)); + +assertType( + 'Illuminate\Support\Collection>', + $collection->sliding(2) +); + +assertType( + 'Illuminate\Support\Collection>', + $collection::make(['string' => 'string'])->sliding(2, 1) +); + +assertType( + 'Illuminate\Support\Collection>', + $collection->splitIn(2) +); + +assertType( + 'Illuminate\Support\Collection>', + $collection::make(['string' => 'string'])->splitIn(1) +); + +assertType('Illuminate\Support\Collection', $collection->splice(1)); +assertType('Illuminate\Support\Collection', $collection->splice(1, 1, [new User])); + +assertType('Illuminate\Support\Collection', $collection->transform(function ($user, $int) { + assertType('User', $user); + assertType('int', $int); + + return new User; +})); + +assertType('Illuminate\Support\Collection', $collection->add(new User)); + +/** + * @template TKey of array-key + * @template TValue + * + * @extends \Illuminate\Support\Collection + */ +class CustomCollection extends Collection +{ +} + +// assertType('CustomCollection', CustomCollection::make([new User])); +assertType('Illuminate\Support\Collection', CustomCollection::make([new User])->toBase()); + +assertType('bool', $collection->offsetExists(0)); +assertType('bool', isset($collection[0])); + +$collection->offsetSet(0, new User); +$collection->offsetSet(null, new User); +assertType('User', $collection[0] = new User); + +$collection->offsetUnset(0); +unset($collection[0]); + +assertType('array', $collection->toArray()); +assertType('array', collect(['string' => 'string'])->toArray()); +assertType('array', collect([1, 2])->toArray()); + +assertType('ArrayIterator', $collection->getIterator()); +foreach ($collection as $int => $user) { + assertType('int', $int); + assertType('User', $user); +} From 932e601d1e8063a51cbce95136d54367d6f3ece4 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Fri, 27 Aug 2021 16:03:39 +0200 Subject: [PATCH 183/194] [9.x] Allow for null handling in custom casts (#38039) * Pass null to custom cast set method when value is null * Add integration test for custom casts on Eloquent Model * Rename Address class to AddressCast in EloquentModelCustomCastingTest Prevents a duplicate naming conflict * Allow for proper null value handling in custom CastsAttributes implementations * Fix codestyle issue in EloquentModelCustomCastingTest.php --- .../Eloquent/Concerns/HasAttributes.php | 22 +- .../EloquentModelCustomCastingTest.php | 263 ++++++++++++++++++ 2 files changed, 269 insertions(+), 16 deletions(-) create mode 100644 tests/Integration/Database/EloquentModelCustomCastingTest.php diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index ddbe121cd1cd..fcf26bb61527 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -859,22 +859,12 @@ protected function setClassCastableAttribute($key, $value) { $caster = $this->resolveCasterClass($key); - if (is_null($value)) { - $this->attributes = array_merge($this->attributes, array_map( - function () { - }, - $this->normalizeCastClassResponse($key, $caster->set( - $this, $key, $this->{$key}, $this->attributes - )) - )); - } else { - $this->attributes = array_merge( - $this->attributes, - $this->normalizeCastClassResponse($key, $caster->set( - $this, $key, $value, $this->attributes - )) - ); - } + $this->attributes = array_merge( + $this->attributes, + $this->normalizeCastClassResponse($key, $caster->set( + $this, $key, $value, $this->attributes + )) + ); if ($caster instanceof CastsInboundAttributes || ! is_object($value)) { unset($this->classCastCache[$key]); diff --git a/tests/Integration/Database/EloquentModelCustomCastingTest.php b/tests/Integration/Database/EloquentModelCustomCastingTest.php new file mode 100644 index 000000000000..39cf55454fff --- /dev/null +++ b/tests/Integration/Database/EloquentModelCustomCastingTest.php @@ -0,0 +1,263 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + /** + * Setup the database schema. + * + * @return void + */ + public function createSchema() + { + $this->schema()->create('casting_table', function (Blueprint $table) { + $table->increments('id'); + $table->string('address_line_one'); + $table->string('address_line_two'); + $table->string('string_field'); + $table->timestamps(); + }); + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + $this->schema()->drop('casting_table'); + } + + /** + * Tests... + */ + public function testSavingCastedAttributesToDatabase() + { + /** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */ + $model = CustomCasts::create([ + 'address' => new AddressModel('address_line_one_value', 'address_line_two_value'), + 'string_field' => null, + ]); + + $this->assertSame('address_line_one_value', $model->getOriginal('address_line_one')); + $this->assertSame('address_line_one_value', $model->getAttribute('address_line_one')); + + $this->assertSame('address_line_two_value', $model->getOriginal('address_line_two')); + $this->assertSame('address_line_two_value', $model->getAttribute('address_line_two')); + + $this->assertSame(null, $model->getOriginal('string_field')); + $this->assertSame(null, $model->getAttribute('string_field')); + $this->assertSame('', $model->getRawOriginal('string_field')); + + /** @var \Illuminate\Tests\Integration\Database\CustomCasts $another_model */ + $another_model = CustomCasts::create([ + 'address_line_one' => 'address_line_one_value', + 'address_line_two' => 'address_line_two_value', + 'string_field' => 'string_value', + ]); + + $this->assertInstanceOf(AddressModel::class, $another_model->address); + + $this->assertSame('address_line_one_value', $model->address->lineOne); + $this->assertSame('address_line_two_value', $model->address->lineTwo); + } + + public function testInvalidArgumentExceptionOnInvalidValue() + { + /** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */ + $model = CustomCasts::create([ + 'address' => new AddressModel('address_line_one_value', 'address_line_two_value'), + 'string_field' => 'string_value', + ]); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The given value is not an Address instance.'); + $model->address = 'single_string'; + + // Ensure model values remain unchanged + $this->assertSame('address_line_one_value', $model->address->lineOne); + $this->assertSame('address_line_two_value', $model->address->lineTwo); + } + + public function testInvalidArgumentExceptionOnNull() + { + /** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */ + $model = CustomCasts::create([ + 'address' => new AddressModel('address_line_one_value', 'address_line_two_value'), + 'string_field' => 'string_value', + ]); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The given value is not an Address instance.'); + $model->address = null; + + // Ensure model values remain unchanged + $this->assertSame('address_line_one_value', $model->address->lineOne); + $this->assertSame('address_line_two_value', $model->address->lineTwo); + } + + /** + * Get a database connection instance. + * + * @return \Illuminate\Database\Connection + */ + protected function connection() + { + return Eloquent::getConnectionResolver()->connection(); + } + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema() + { + return $this->connection()->getSchemaBuilder(); + } +} + +/** + * Eloquent Casts... + */ +class AddressCast implements CastsAttributes +{ + /** + * Cast the given value. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @param mixed $value + * @param array $attributes + * @return AddressModel + */ + public function get($model, $key, $value, $attributes) + { + return new AddressModel( + $attributes['address_line_one'], + $attributes['address_line_two'], + ); + } + + /** + * Prepare the given value for storage. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @param AddressModel $value + * @param array $attributes + * @return array + */ + public function set($model, $key, $value, $attributes) + { + if (! $value instanceof AddressModel) { + throw new InvalidArgumentException('The given value is not an Address instance.'); + } + + return [ + 'address_line_one' => $value->lineOne, + 'address_line_two' => $value->lineTwo, + ]; + } +} + +class NonNullableString implements CastsAttributes +{ + /** + * Cast the given value. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @param string $value + * @param array $attributes + * @return string|null + */ + public function get($model, $key, $value, $attributes) + { + return ($value != '') ? $value : null; + } + + /** + * Prepare the given value for storage. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @param string|null $value + * @param array $attributes + * @return string + */ + public function set($model, $key, $value, $attributes) + { + return $value ?? ''; + } +} + +/** + * Eloquent Models... + */ +class CustomCasts extends Eloquent +{ + /** + * @var string + */ + protected $table = 'casting_table'; + + /** + * @var string[] + */ + protected $guarded = []; + + /** + * @var array + */ + protected $casts = [ + 'address' => AddressCast::class, + 'string_field' => NonNullableString::class, + ]; +} + +class AddressModel +{ + /** + * @var string + */ + public $lineOne; + + /** + * @var string + */ + public $lineTwo; + + public function __construct($address_line_one, $address_line_two) + { + $this->lineOne = $address_line_one; + $this->lineTwo = $address_line_two; + } +} From bd7a519d50ff4c3350b0bd42debbe54c9fa05f56 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 6 Sep 2021 19:41:08 +0100 Subject: [PATCH 184/194] [9.x] Support the latest psr/container versions (#38692) * Support the latest psr/container versions * Added types --- composer.json | 2 +- src/Illuminate/Container/Container.php | 4 ++-- src/Illuminate/Container/composer.json | 2 +- src/Illuminate/Contracts/composer.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index acb30f7d6344..ca1e555fde81 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "monolog/monolog": "^2.0", "nesbot/carbon": "^2.31", "opis/closure": "^3.6", - "psr/container": "^1.0", + "psr/container": "^1.1.1|^2.0.1", "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", "swiftmailer/swiftmailer": "^6.2.7", diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 3fd72d2d3fb1..10b83404c152 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -189,7 +189,7 @@ public function bound($abstract) /** * {@inheritdoc} */ - public function has($id) + public function has(string $id): bool { return $this->bound($id); } @@ -695,7 +695,7 @@ public function make($abstract, array $parameters = []) /** * {@inheritdoc} */ - public function get($id) + public function get(string $id) { try { return $this->resolve($id); diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index 023c891c10cd..2e7248d7f48d 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -16,7 +16,7 @@ "require": { "php": "^8.0.2", "illuminate/contracts": "^9.0", - "psr/container": "^1.0" + "psr/container": "^1.1.1|^2.0.1" }, "provide": { "psr/container-implementation": "1.0" diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index a39250afd2fe..4abec41b24ee 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": "^8.0.2", - "psr/container": "^1.0", + "psr/container": "^1.1.1|^2.0.1", "psr/simple-cache": "^1.0" }, "autoload": { From 9ee0a4b895bc9e63823d8b67d56151b20437f56f Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 8 Sep 2021 13:51:47 +0100 Subject: [PATCH 185/194] CS fixes --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/Enumerable.php | 2 +- .../Collections/Traits/EnumeratesValues.php | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index b0e0fcb51829..3d98b050e16f 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -794,7 +794,7 @@ public function nth($step, $offset = 0) /** * Get the items with the specified keys. * - * @param \Illuminate\Support\Enumerable|array $keys + * @param \Illuminate\Support\Enumerable|array $keys * @return static */ public function only($keys) diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index c16e23077a6b..df98aa53856f 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -661,7 +661,7 @@ public function flatMap(callable $callback); /** * Map the values into a new class. * - * @param class-string $class + * @param class-string $class * @return static */ public function mapInto($class); diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 09487fd2ad0d..abbfbaaa097d 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -122,7 +122,7 @@ public static function wrap($value) * @template TUnwrapKey of array-key * @template TUnwrapValue * - * @param array|static $value + * @param array|static $value * @return array */ public static function unwrap($value) @@ -346,7 +346,7 @@ public function mapSpread(callable $callback) * @template TMapToGroupsKey of array-key * @template TMapToGroupsValue * - * @param callable(TValue, TKey): array $callback + * @param callable(TValue, TKey): array $callback * @return static> */ public function mapToGroups(callable $callback) @@ -359,7 +359,7 @@ public function mapToGroups(callable $callback) /** * Map a collection and flatten the result by a single level. * - * @param callable(TValue, TKey): mixed $callback + * @param callable(TValue, TKey): mixed $callback * @return static */ public function flatMap(callable $callback) @@ -370,7 +370,7 @@ public function flatMap(callable $callback) /** * Map the values into a new class. * - * @param class-string $class + * @param class-string $class * @return static */ public function mapInto($class) @@ -436,8 +436,8 @@ public function forPage($page, $perPage) * Partition the collection into two arrays using the given callback or key. * * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param TValue|string|null $operator - * @param TValue|null $value + * @param TValue|string|null $operator + * @param TValue|null $value * @return array> */ public function partition($key, $operator = null, $value = null) @@ -718,7 +718,7 @@ public function pipeInto($class) * @template TReduceInitial * @template TReduceReturnType * - * @param callable(TReduceInitial|TReduceReturnType, TValue): TReduceReturnType $callback + * @param callable(TReduceInitial|TReduceReturnType, TValue): TReduceReturnType $callback * @param TReduceInitial $initial * @return TReduceReturnType */ @@ -739,8 +739,8 @@ public function reduce(callable $callback, $initial = null) * @template TReduceWithKeysInitial * @template TReduceWithKeysReturnType * - * @param callable(TReduceWithKeysInitial|TReduceWithKeysReturnType, TValue): TReduceWithKeysReturnType $callback - * @param TReduceWithKeysInitial $initial + * @param callable(TReduceWithKeysInitial|TReduceWithKeysReturnType, TValue): TReduceWithKeysReturnType $callback + * @param TReduceWithKeysInitial $initial * @return TReduceWithKeysReturnType */ public function reduceWithKeys(callable $callback, $initial = null) From 73ac59546ed326cfecba45a8674fc678b5197950 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 8 Sep 2021 14:18:11 +0100 Subject: [PATCH 186/194] Fixed phpdoc --- src/Illuminate/Collections/Traits/EnumeratesValues.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index abbfbaaa097d..67ea68675b68 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -719,7 +719,7 @@ public function pipeInto($class) * @template TReduceReturnType * * @param callable(TReduceInitial|TReduceReturnType, TValue): TReduceReturnType $callback - * @param TReduceInitial $initial + * @param TReduceInitial $initial * @return TReduceReturnType */ public function reduce(callable $callback, $initial = null) From 75969f7cc113a014d911c73b6a9f2e5743890c00 Mon Sep 17 00:00:00 2001 From: Filip Ganyicz Date: Wed, 8 Sep 2021 15:52:57 +0200 Subject: [PATCH 187/194] Add firstOr methods to relationship classes (#38694) --- .../Eloquent/Relations/BelongsToMany.php | 23 +++++++++++++++++++ .../Eloquent/Relations/HasManyThrough.php | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 18fa14517bbf..407390e209e4 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -2,6 +2,7 @@ namespace Illuminate\Database\Eloquent\Relations; +use Closure; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; @@ -754,6 +755,28 @@ public function firstOrFail($columns = ['*']) throw (new ModelNotFoundException)->setModel(get_class($this->related)); } + /** + * Execute the query and get the first result or call a callback. + * + * @param \Closure|array $columns + * @param \Closure|null $callback + * @return \Illuminate\Database\Eloquent\Model|static|mixed + */ + public function firstOr($columns = ['*'], Closure $callback = null) + { + if ($columns instanceof Closure) { + $callback = $columns; + + $columns = ['*']; + } + + if (! is_null($model = $this->first($columns))) { + return $model; + } + + return $callback(); + } + /** * Get the results of the relationship. * diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 9ea307562ca1..71fa08d23ed8 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -2,6 +2,7 @@ namespace Illuminate\Database\Eloquent\Relations; +use Closure; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; @@ -301,6 +302,28 @@ public function firstOrFail($columns = ['*']) throw (new ModelNotFoundException)->setModel(get_class($this->related)); } + /** + * Execute the query and get the first result or call a callback. + * + * @param \Closure|array $columns + * @param \Closure|null $callback + * @return \Illuminate\Database\Eloquent\Model|static|mixed + */ + public function firstOr($columns = ['*'], Closure $callback = null) + { + if ($columns instanceof Closure) { + $callback = $columns; + + $columns = ['*']; + } + + if (! is_null($model = $this->first($columns))) { + return $model; + } + + return $callback(); + } + /** * Find a related model by its primary key. * From c1b38eaf84f72ec0e8e836566df96bc01d00b6ac Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 9 Sep 2021 15:17:39 +0100 Subject: [PATCH 188/194] CS fixes --- .../Contracts/Database/Query/Builder.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Contracts/Database/Query/Builder.php b/src/Illuminate/Contracts/Database/Query/Builder.php index c2f0a8e637a5..08f6d1570acf 100644 --- a/src/Illuminate/Contracts/Database/Query/Builder.php +++ b/src/Illuminate/Contracts/Database/Query/Builder.php @@ -214,7 +214,7 @@ public function mergeWheres($wheres, $bindings); /** * Add a basic where clause to the query. * - * @param \Closure|Builder|string|array $column + * @param \Closure|\Illuminate\Contracts\Database\Query\Builder|string|array $column * @param mixed $operator * @param mixed $value * @param string $boolean @@ -235,7 +235,7 @@ public function prepareValueAndOperator($value, $operator, $useDefault = false); /** * Add an "or where" clause to the query. * - * @param \Closure|Builder|string|array $column + * @param \Closure|\Illuminate\Contracts\Database\Query\Builder|string|array $column * @param mixed $operator * @param mixed $value * @return static @@ -819,7 +819,7 @@ public function orHavingRaw($sql, array $bindings = []); /** * Add an "order by" clause to the query. * - * @param \Closure|\Illuminate\Database\Query\Expression|Builder|string $column + * @param \Closure|\Illuminate\Database\Query\Expression|\Illuminate\Contracts\Database\Query\Builder|string $column * @param string $direction * @return static */ @@ -828,7 +828,7 @@ public function orderBy($column, $direction = 'asc'); /** * Add a descending "order by" clause to the query. * - * @param \Closure|\Illuminate\Database\Query\Expression|Builder|string $column + * @param \Closure|\Illuminate\Database\Query\Expression|\Illuminate\Contracts\Database\Query\Builder|string $column * @return static */ public function orderByDesc($column); @@ -836,7 +836,7 @@ public function orderByDesc($column); /** * Add an "order by" clause for a timestamp to the query. * - * @param \Closure|\Illuminate\Database\Query\Expression|Builder|string $column + * @param \Closure|\Illuminate\Database\Query\Expression|\Illuminate\Contracts\Database\Query\Builder|string $column * @return static */ public function latest($column = 'created_at'); @@ -844,7 +844,7 @@ public function latest($column = 'created_at'); /** * Add an "order by" clause for a timestamp to the query. * - * @param \Closure|\Illuminate\Database\Query\Expression|Builder|string $column + * @param \Closure|\Illuminate\Database\Query\Expression|\Illuminate\Contracts\Database\Query\Builder|string $column * @return static */ public function oldest($column = 'created_at'); @@ -963,18 +963,21 @@ public function lock($value = true); /** * Lock the selected rows in the table for updating. + * * @return static */ public function lockForUpdate(); /** * Share lock the selected rows in the table. + * * @return static */ public function sharedLock(); /** * Get a new instance of the query builder. + * * @return static */ public function newQuery(); @@ -989,12 +992,14 @@ public function raw($value); /** * Get the current query value bindings in a flattened array. + * * @return array */ public function getBindings(); /** * Get the raw array of bindings. + * * @return array */ public function getRawBindings(); @@ -1020,7 +1025,7 @@ public function addBinding($value, $type = 'where'); /** * Merge an array of bindings into our bindings. * - * @param Builder $query + * @param \Illuminate\Contracts\Database\Query\Builder $query * @return static */ public function mergeBindings(Builder $query); From 4e6e23593951085731600cb95cb8e3c039f4e0a3 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 9 Sep 2021 15:29:14 +0100 Subject: [PATCH 189/194] CS fixes --- src/Illuminate/Contracts/Database/Query/Builder.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Illuminate/Contracts/Database/Query/Builder.php b/src/Illuminate/Contracts/Database/Query/Builder.php index 08f6d1570acf..dd499cfa34f0 100644 --- a/src/Illuminate/Contracts/Database/Query/Builder.php +++ b/src/Illuminate/Contracts/Database/Query/Builder.php @@ -1040,30 +1040,35 @@ public function cleanBindings(array $bindings); /** * Get the database connection instance. + * * @return \Illuminate\Database\ConnectionInterface */ public function getConnection(); /** * Get the database query processor instance. + * * @return \Illuminate\Database\Query\Processors\Processor */ public function getProcessor(); /** * Get the query grammar instance. + * * @return \Illuminate\Database\Query\Grammars\Grammar */ public function getGrammar(); /** * Use the write pdo for query. + * * @return static */ public function useWritePdo(); /** * Clone the query. + * * @return static */ public function clone(); From 097107ab50ce754c709313fc75a6f1f4a9389bfc Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 14 Sep 2021 15:57:25 +0200 Subject: [PATCH 190/194] [9.x] Implement Symfony Mailer (#38481) * Implement Symfony Mailer * Apply fixes from StyleCI * Update src/Illuminate/Mail/Message.php Co-authored-by: michael-rubel * Update src/Illuminate/Mail/Message.php Co-authored-by: michael-rubel * Update src/Illuminate/Mail/Message.php Co-authored-by: michael-rubel * Update src/Illuminate/Mail/Message.php Co-authored-by: michael-rubel * Update src/Illuminate/Mail/Message.php Co-authored-by: michael-rubel * Update Array and Log transports * Apply fixes from StyleCI * Fix interface implementation * Update Mailer * Apply fixes from StyleCI * Rename * Remove method * Fix tests * Apply fixes from StyleCI * Work on Mailer tests * type-hint * Fix Mailer tests * Fix more tests * Apply fixes from StyleCI * Migrate Mailgun transport * Migrate Postmark transport * Replace SesTransport * Remove transports from dev dependencies * Allow setting options on esmtp transport * Fix Postmark transport * Fix embedding files * Clarify API transports * Apply fixes from StyleCI * Fix SES transport setup * Add MessageStreamId to Postmark Transport again (#38748) * Update symfony mailer docblocks (#38773) * Update docblocks from Swift Mailer to Symfony Mailer * Make TransportInterface more specific * Add Session Token to SES Transport (#38797) * Update src/Illuminate/Mail/Transport/ArrayTransport.php Co-authored-by: Julius Kiekbusch * fix docblock * Add Wrapper for Symfony SentMessage (#38803) * Create SentMessage wrapper for Symfony's SentMessage * Wrap Symfony SentMessage * Update Docblocks to Illuminate\Mail\SentMessage * Fix sendMailable * Update SentMessage.php Co-authored-by: Dries Vints Co-authored-by: Taylor Otwell Co-authored-by: michael-rubel Co-authored-by: Julius Kiekbusch Co-authored-by: Taylor Otwell Co-authored-by: Taylor Otwell --- composer.json | 13 +- src/Illuminate/Contracts/Mail/Mailer.php | 7 - src/Illuminate/Mail/Events/MessageSending.php | 10 +- src/Illuminate/Mail/Events/MessageSent.php | 14 +- src/Illuminate/Mail/MailManager.php | 211 +++++-------- src/Illuminate/Mail/Mailable.php | 10 +- src/Illuminate/Mail/Mailer.php | 121 +++----- src/Illuminate/Mail/Message.php | 144 ++++----- src/Illuminate/Mail/SentMessage.php | 54 ++++ .../Mail/Transport/ArrayTransport.php | 27 +- .../Mail/Transport/LogTransport.php | 41 +-- .../Mail/Transport/MailgunTransport.php | 216 ------------- .../Mail/Transport/SesTransport.php | 94 ------ src/Illuminate/Mail/Transport/Transport.php | 108 ------- src/Illuminate/Mail/composer.json | 9 +- .../Notifications/Channels/MailChannel.php | 2 +- .../Notifications/Messages/MailMessage.php | 4 +- src/Illuminate/Support/Facades/Mail.php | 8 +- .../Mail/SendingMailWithLocaleTest.php | 22 +- .../SendingNotificationsWithLocaleTest.php | 29 +- tests/Mail/MailFailoverTransportTest.php | 22 +- tests/Mail/MailLogTransportTest.php | 7 +- tests/Mail/MailMailerTest.php | 288 +++++++----------- tests/Mail/MailMessageTest.php | 84 ++--- tests/Mail/MailSesTransportTest.php | 140 --------- tests/Mail/MailableQueuedTest.php | 4 +- .../NotificationMailMessageTest.php | 2 +- 27 files changed, 489 insertions(+), 1202 deletions(-) create mode 100644 src/Illuminate/Mail/SentMessage.php delete mode 100644 src/Illuminate/Mail/Transport/MailgunTransport.php delete mode 100644 src/Illuminate/Mail/Transport/SesTransport.php delete mode 100644 src/Illuminate/Mail/Transport/Transport.php delete mode 100644 tests/Mail/MailSesTransportTest.php diff --git a/composer.json b/composer.json index e8c8079d535f..716c37d35290 100644 --- a/composer.json +++ b/composer.json @@ -29,12 +29,12 @@ "psr/container": "^1.1.1|^2.0.1", "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", - "swiftmailer/swiftmailer": "^6.2.7", "symfony/console": "^6.0", "symfony/error-handler": "^6.0", "symfony/finder": "^6.0", "symfony/http-foundation": "^6.0", "symfony/http-kernel": "^6.0", + "symfony/mailer": "^6.0", "symfony/mime": "^6.0", "symfony/process": "^6.0", "symfony/routing": "^6.0", @@ -136,12 +136,12 @@ "ext-pcntl": "Required to use all features of the queue worker.", "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).", - "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 and DynamoDb failed job storage (^3.189.0).", "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.12|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", - "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^7.2).", + "guzzlehttp/guzzle": "Required to use the HTTP Client and the ping methods on schedules (^7.2).", "laravel/tinker": "Required to use the tinker console command (^2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^2.0).", "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^2.0).", @@ -153,10 +153,13 @@ "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 (^5.0|^6.0).", + "symfony/amazon-mailer": "Required to enable support for the SES mail transport (^6.0).", "symfony/cache": "Required to PSR-6 cache bridge (^6.0).", "symfony/filesystem": "Required to enable support for relative symbolic links (^6.0).", - "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", - "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^6.0).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^6.0).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^6.0).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Contracts/Mail/Mailer.php b/src/Illuminate/Contracts/Mail/Mailer.php index 255b6789da82..38f9e3b56cc1 100644 --- a/src/Illuminate/Contracts/Mail/Mailer.php +++ b/src/Illuminate/Contracts/Mail/Mailer.php @@ -38,11 +38,4 @@ public function raw($text, $callback); * @return void */ public function send($view, array $data = [], $callback = null); - - /** - * Get the array of failed recipients. - * - * @return array - */ - public function failures(); } diff --git a/src/Illuminate/Mail/Events/MessageSending.php b/src/Illuminate/Mail/Events/MessageSending.php index bf5bccfdf2df..31435fb6e0e7 100644 --- a/src/Illuminate/Mail/Events/MessageSending.php +++ b/src/Illuminate/Mail/Events/MessageSending.php @@ -2,12 +2,14 @@ namespace Illuminate\Mail\Events; +use Symfony\Component\Mime\Email; + class MessageSending { /** - * The Swift message instance. + * The Symfony Email instance. * - * @var \Swift_Message + * @var \Symfony\Component\Mime\Email */ public $message; @@ -21,11 +23,11 @@ class MessageSending /** * Create a new event instance. * - * @param \Swift_Message $message + * @param \Symfony\Component\Mime\Email $message * @param array $data * @return void */ - public function __construct($message, $data = []) + public function __construct(Email $message, array $data = []) { $this->data = $data; $this->message = $message; diff --git a/src/Illuminate/Mail/Events/MessageSent.php b/src/Illuminate/Mail/Events/MessageSent.php index 64aef94312b6..a95148fcc285 100644 --- a/src/Illuminate/Mail/Events/MessageSent.php +++ b/src/Illuminate/Mail/Events/MessageSent.php @@ -2,14 +2,14 @@ namespace Illuminate\Mail\Events; -use Swift_Attachment; +use Symfony\Component\Mime\Email; class MessageSent { /** - * The Swift message instance. + * The Symfony Email instance. * - * @var \Swift_Message + * @var \Symfony\Component\Mime\Email */ public $message; @@ -23,11 +23,11 @@ class MessageSent /** * Create a new event instance. * - * @param \Swift_Message $message + * @param \Symfony\Component\Mime\Email $message * @param array $data * @return void */ - public function __construct($message, $data = []) + public function __construct(Email $message, array $data = []) { $this->data = $data; $this->message = $message; @@ -40,9 +40,7 @@ public function __construct($message, $data = []) */ public function __serialize() { - $hasAttachments = collect($this->message->getChildren()) - ->whereInstanceOf(Swift_Attachment::class) - ->isNotEmpty(); + $hasAttachments = collect($this->message->getAttachments())->isNotEmpty(); return $hasAttachments ? [ 'message' => base64_encode(serialize($this->message)), diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index aef832ccef23..5b546738365d 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -2,26 +2,24 @@ namespace Illuminate\Mail; -use Aws\SesV2\SesV2Client; use Closure; -use GuzzleHttp\Client as HttpClient; use Illuminate\Contracts\Mail\Factory as FactoryContract; use Illuminate\Log\LogManager; use Illuminate\Mail\Transport\ArrayTransport; use Illuminate\Mail\Transport\LogTransport; -use Illuminate\Mail\Transport\MailgunTransport; -use Illuminate\Mail\Transport\SesTransport; use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; -use Postmark\ThrowExceptionOnFailurePlugin; -use Postmark\Transport as PostmarkTransport; use Psr\Log\LoggerInterface; -use Swift_DependencyContainer; -use Swift_FailoverTransport as FailoverTransport; -use Swift_Mailer; -use Swift_SendmailTransport as SendmailTransport; -use Swift_SmtpTransport as SmtpTransport; +use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory; +use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\FailoverTransport; +use Symfony\Component\Mailer\Transport\SendmailTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; /** * @mixin \Illuminate\Mail\Mailer @@ -117,7 +115,7 @@ protected function resolve($name) $mailer = new Mailer( $name, $this->app['view'], - $this->createSwiftMailer($config), + $this->createSymfonyTransport($config), $this->app['events'] ); @@ -135,32 +133,15 @@ protected function resolve($name) return $mailer; } - /** - * Create the SwiftMailer instance for the given configuration. - * - * @param array $config - * @return \Swift_Mailer - */ - protected function createSwiftMailer(array $config) - { - if ($config['domain'] ?? false) { - Swift_DependencyContainer::getInstance() - ->register('mime.idgenerator.idright') - ->asValue($config['domain']); - } - - return new Swift_Mailer($this->createTransport($config)); - } - /** * Create a new transport instance. * * @param array $config - * @return \Swift_Transport + * @return \Symfony\Component\Mailer\Transport\TransportInterface * * @throws \InvalidArgumentException */ - public function createTransport(array $config) + public function createSymfonyTransport(array $config) { // Here we will check if the "transport" key exists and if it doesn't we will // assume an application is still using the legacy mail configuration file @@ -179,33 +160,23 @@ public function createTransport(array $config) } /** - * Create an instance of the SMTP Swift Transport driver. + * Create an instance of the Symfony SMTP Transport driver. * * @param array $config - * @return \Swift_SmtpTransport + * @return \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport */ protected function createSmtpTransport(array $config) { - // The Swift SMTP transport instance will allow us to use any SMTP backend - // for delivering mail such as Sendgrid, Amazon SES, or a custom server - // a developer has available. We will just pass this configured host. - $transport = new SmtpTransport( - $config['host'], - $config['port'] - ); - - if (! empty($config['encryption'])) { - $transport->setEncryption($config['encryption']); - } + $factory = new EsmtpTransportFactory; - // Once we have the transport we will check for the presence of a username - // and password. If we have it we will set the credentials on the Swift - // transporter instance so that we'll properly authenticate delivery. - if (isset($config['username'])) { - $transport->setUsername($config['username']); - - $transport->setPassword($config['password']); - } + $transport = $factory->create(new Dsn( + ! empty($config['encryption']) && $config['encryption'] === 'tls' ? 'smtps' : '', + $config['host'], + $config['username'] ?? null, + $config['password'] ?? null, + $config['port'] ?? null, + $config + )); return $this->configureSmtpTransport($transport, $config); } @@ -213,40 +184,32 @@ protected function createSmtpTransport(array $config) /** * Configure the additional SMTP driver options. * - * @param \Swift_SmtpTransport $transport + * @param \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport $transport * @param array $config - * @return \Swift_SmtpTransport + * @return \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport */ - protected function configureSmtpTransport($transport, array $config) + protected function configureSmtpTransport(EsmtpTransport $transport, array $config) { - if (isset($config['stream'])) { - $transport->setStreamOptions($config['stream']); - } + $stream = $transport->getStream(); - if (isset($config['source_ip'])) { - $transport->setSourceIp($config['source_ip']); - } - - if (isset($config['local_domain'])) { - $transport->setLocalDomain($config['local_domain']); - } - - if (isset($config['timeout'])) { - $transport->setTimeout($config['timeout']); - } + if ($stream instanceof SocketStream) { + if (isset($config['source_ip'])) { + $stream->setSourceIp($config['source_ip']); + } - if (isset($config['auth_mode'])) { - $transport->setAuthMode($config['auth_mode']); + if (isset($config['timeout'])) { + $stream->setTimeout($config['timeout']); + } } return $transport; } /** - * Create an instance of the Sendmail Swift Transport driver. + * Create an instance of the Symfony Sendmail Transport driver. * * @param array $config - * @return \Swift_SendmailTransport + * @return \Symfony\Component\Mailer\Transport\SendmailTransport */ protected function createSendmailTransport(array $config) { @@ -256,10 +219,10 @@ protected function createSendmailTransport(array $config) } /** - * Create an instance of the Amazon SES Swift Transport driver. + * Create an instance of the Symfony Amazon SES Transport driver. * * @param array $config - * @return \Illuminate\Mail\Transport\SesTransport + * @return \Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiAsyncAwsTransport */ protected function createSesTransport(array $config) { @@ -271,31 +234,26 @@ protected function createSesTransport(array $config) $config = Arr::except($config, ['transport']); - return new SesTransport( - new SesV2Client($this->addSesCredentials($config)), - $config['options'] ?? [] - ); - } + $factory = new SesTransportFactory(); - /** - * Add the SES credentials to the configuration array. - * - * @param array $config - * @return array - */ - protected function addSesCredentials(array $config) - { - if (! empty($config['key']) && ! empty($config['secret'])) { - $config['credentials'] = Arr::only($config, ['key', 'secret', 'token']); + if (! isset($config['session_token']) && isset($config['token'])) { + $config['session_token'] = $config['token']; } - return $config; + return $factory->create(new Dsn( + 'ses+api', + 'default', + $config['key'], + $config['secret'], + $config['port'] ?? null, + $config + )); } /** - * Create an instance of the Mail Swift Transport driver. + * Create an instance of the Symfony Mail Transport driver. * - * @return \Swift_SendmailTransport + * @return \Symfony\Component\Mailer\Transport\SendmailTransport */ protected function createMailTransport() { @@ -303,50 +261,56 @@ protected function createMailTransport() } /** - * Create an instance of the Mailgun Swift Transport driver. + * Create an instance of the Symfony Mailgun Transport driver. * * @param array $config - * @return \Illuminate\Mail\Transport\MailgunTransport + * @return \Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunApiTransport */ protected function createMailgunTransport(array $config) { + $factory = new MailgunTransportFactory(); + if (! isset($config['secret'])) { $config = $this->app['config']->get('services.mailgun', []); } - return new MailgunTransport( - $this->guzzle($config), + return $factory->create(new Dsn( + 'mailgun+api', + $config['endpoint'] ?? 'default', $config['secret'], - $config['domain'], - $config['endpoint'] ?? null - ); + $config['domain'] + )); } /** - * Create an instance of the Postmark Swift Transport driver. + * Create an instance of the Symfony Postmark Transport driver. * * @param array $config - * @return \Swift_Transport + * @return \Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkApiTransport */ protected function createPostmarkTransport(array $config) { - $headers = isset($config['message_stream_id']) ? [ - 'X-PM-Message-Stream' => $config['message_stream_id'], - ] : []; + $factory = new PostmarkTransportFactory(); + + $options = isset($config['message_stream_id']) + ? ['message_stream' => $config['message_stream_id']] + : []; - return tap(new PostmarkTransport( + return $factory->create(new Dsn( + 'postmark+api', + 'default', $config['token'] ?? $this->app['config']->get('services.postmark.token'), - $headers - ), function ($transport) { - $transport->registerPlugin(new ThrowExceptionOnFailurePlugin); - }); + null, + null, + $options + )); } /** - * Create an instance of the Failover Swift Transport driver. + * Create an instance of the Symfony Failover Transport driver. * * @param array $config - * @return \Swift_FailoverTransport + * @return \Symfony\Component\Mailer\Transport\FailoverTransport */ protected function createFailoverTransport(array $config) { @@ -363,15 +327,15 @@ protected function createFailoverTransport(array $config) // the transport configuration parameter in order to offer compatibility // with any Laravel <= 6.x application style mail configuration files. $transports[] = $this->app['config']['mail.driver'] - ? $this->createTransport(array_merge($config, ['transport' => $name])) - : $this->createTransport($config); + ? $this->createSymfonyTransport(array_merge($config, ['transport' => $name])) + : $this->createSymfonyTransport($config); } return new FailoverTransport($transports); } /** - * Create an instance of the Log Swift Transport driver. + * Create an instance of the Log Transport driver. * * @param array $config * @return \Illuminate\Mail\Transport\LogTransport @@ -390,7 +354,7 @@ protected function createLogTransport(array $config) } /** - * Create an instance of the Array Swift Transport Driver. + * Create an instance of the Array Transport Driver. * * @return \Illuminate\Mail\Transport\ArrayTransport */ @@ -399,21 +363,6 @@ protected function createArrayTransport() return new ArrayTransport; } - /** - * Get a fresh Guzzle HTTP client instance. - * - * @param array $config - * @return \GuzzleHttp\Client - */ - protected function guzzle(array $config) - { - return new HttpClient(Arr::add( - $config['guzzle'] ?? [], - 'connect_timeout', - 60 - )); - } - /** * Set a global address on the mailer by type. * diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 30cf75030aec..b37d47531559 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -167,11 +167,11 @@ class Mailable implements MailableContract, Renderable * Send the message using the given mailer. * * @param \Illuminate\Contracts\Mail\Factory|\Illuminate\Contracts\Mail\Mailer $mailer - * @return void + * @return \Illuminate\Mail\SentMessage|null */ public function send($mailer) { - $this->withLocale($this->locale, function () use ($mailer) { + return $this->withLocale($this->locale, function () use ($mailer) { Container::getInstance()->call([$this, 'build']); $mailer = $mailer instanceof MailFactory @@ -450,7 +450,7 @@ protected function buildDiskAttachments($message) protected function runCallbacks($message) { foreach ($this->callbacks as $callback) { - $callback($message->getSwiftMessage()); + $callback($message->getSymfonyMessage()); } return $this; @@ -972,12 +972,12 @@ public function mailer($mailer) } /** - * Register a callback to be called with the Swift message instance. + * Register a callback to be called with the Symfony message instance. * * @param callable $callback * @return $this */ - public function withSwiftMessage($callback) + public function withSymfonyMessage($callback) { $this->callbacks[] = $callback; diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index 128f211f7651..7ca202c3ae79 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -15,7 +15,9 @@ use Illuminate\Support\HtmlString; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; -use Swift_Mailer; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\Email; class Mailer implements MailerContract, MailQueueContract { @@ -36,11 +38,11 @@ class Mailer implements MailerContract, MailQueueContract protected $views; /** - * The Swift Mailer instance. + * The Symfony Transport instance. * - * @var \Swift_Mailer + * @var \Symfony\Component\Mailer\Transport\TransportInterface */ - protected $swift; + protected $transport; /** * The event dispatcher instance. @@ -84,28 +86,21 @@ class Mailer implements MailerContract, MailQueueContract */ protected $queue; - /** - * Array of failed recipients. - * - * @var array - */ - protected $failedRecipients = []; - /** * Create a new Mailer instance. * * @param string $name * @param \Illuminate\Contracts\View\Factory $views - * @param \Swift_Mailer $swift + * @param \Symfony\Component\Mailer\Transport\TransportInterface $transport * @param \Illuminate\Contracts\Events\Dispatcher|null $events * @return void */ - public function __construct(string $name, Factory $views, Swift_Mailer $swift, Dispatcher $events = null) + public function __construct(string $name, Factory $views, TransportInterface $transport, Dispatcher $events = null) { $this->name = $name; $this->views = $views; - $this->swift = $swift; $this->events = $events; + $this->transport = $transport; } /** @@ -193,11 +188,11 @@ public function bcc($users) * * @param string $html * @param mixed $callback - * @return void + * @return \Illuminate\Mail\SentMessage|null */ public function html($html, $callback) { - $this->send(['html' => new HtmlString($html)], [], $callback); + return $this->send(['html' => new HtmlString($html)], [], $callback); } /** @@ -205,11 +200,11 @@ public function html($html, $callback) * * @param string $text * @param mixed $callback - * @return void + * @return \Illuminate\Mail\SentMessage|null */ public function raw($text, $callback) { - $this->send(['raw' => $text], [], $callback); + return $this->send(['raw' => $text], [], $callback); } /** @@ -218,11 +213,11 @@ public function raw($text, $callback) * @param string $view * @param array $data * @param mixed $callback - * @return void + * @return \Illuminate\Mail\SentMessage|null */ public function plain($view, array $data, $callback) { - $this->send(['text' => $view], $data, $callback); + return $this->send(['text' => $view], $data, $callback); } /** @@ -250,7 +245,7 @@ public function render($view, array $data = []) * @param \Illuminate\Contracts\Mail\Mailable|string|array $view * @param array $data * @param \Closure|string|null $callback - * @return void + * @return \Illuminate\Mail\SentMessage|null */ public function send($view, array $data = [], $callback = null) { @@ -268,7 +263,9 @@ public function send($view, array $data = [], $callback = null) // Once we have retrieved the view content for the e-mail we will set the body // of this message using the HTML type, which will provide a simple wrapper // to creating view based emails that are able to receive arrays of data. - $callback($message); + if (! is_null($callback)) { + $callback($message); + } $this->addContent($message, $view, $plain, $raw, $data); @@ -282,12 +279,14 @@ public function send($view, array $data = [], $callback = null) // Next we will determine if the message should be sent. We give the developer // one final chance to stop this message and then we will send it to all of // its recipients. We will then fire the sent event for the sent message. - $swiftMessage = $message->getSwiftMessage(); + $symfonyMessage = $message->getSymfonyMessage(); - if ($this->shouldSendMessage($swiftMessage, $data)) { - $this->sendSwiftMessage($swiftMessage); + if ($this->shouldSendMessage($symfonyMessage, $data)) { + $sentMessage = $this->sendSymfonyMessage($symfonyMessage); $this->dispatchSentEvent($message, $data); + + return $sentMessage === null ? null : new SentMessage($sentMessage); } } @@ -295,7 +294,7 @@ public function send($view, array $data = [], $callback = null) * Send the given mailable. * * @param \Illuminate\Contracts\Mail\Mailable $mailable - * @return mixed + * @return \Illuminate\Mail\SentMessage|null */ protected function sendMailable(MailableContract $mailable) { @@ -352,19 +351,15 @@ protected function parseView($view) protected function addContent($message, $view, $plain, $raw, $data) { if (isset($view)) { - $message->setBody($this->renderView($view, $data) ?: ' ', 'text/html'); + $message->html($this->renderView($view, $data) ?: ' '); } if (isset($plain)) { - $method = isset($view) ? 'addPart' : 'setBody'; - - $message->$method($this->renderView($plain, $data) ?: ' ', 'text/plain'); + $message->text($this->renderView($plain, $data) ?: ' '); } if (isset($raw)) { - $method = (isset($view) || isset($plain)) ? 'addPart' : 'setBody'; - - $message->$method($raw, 'text/plain'); + $message->text($raw); } } @@ -484,7 +479,7 @@ public function laterOn($queue, $delay, $view) */ protected function createMessage() { - $message = new Message($this->swift->createMessage('message')); + $message = new Message(new Email()); // If a global from address has been specified we will set it on every message // instance so the developer does not have to repeat themselves every time @@ -508,26 +503,24 @@ protected function createMessage() } /** - * Send a Swift Message instance. + * Send a Symfony Email instance. * - * @param \Swift_Message $message - * @return int|null + * @param \Symfony\Component\Mime\Email $message + * @return \Symfony\Component\Mailer\SentMessage|null */ - protected function sendSwiftMessage($message) + protected function sendSymfonyMessage(Email $message) { - $this->failedRecipients = []; - try { - return $this->swift->send($message, $this->failedRecipients); + return $this->transport->send($message, Envelope::create($message)); } finally { - $this->forceReconnection(); + // } } /** - * Determines if the message can be sent. + * Determines if the email can be sent. * - * @param \Swift_Message $message + * @param \Symfony\Component\Mime\Email $message * @param array $data * @return bool */ @@ -553,41 +546,19 @@ protected function dispatchSentEvent($message, $data = []) { if ($this->events) { $this->events->dispatch( - new MessageSent($message->getSwiftMessage(), $data) + new MessageSent($message->getSymfonyMessage(), $data) ); } } /** - * Force the transport to re-connect. - * - * This will prevent errors in daemon queue situations. - * - * @return void - */ - protected function forceReconnection() - { - $this->getSwiftMailer()->getTransport()->stop(); - } - - /** - * Get the array of failed recipients. - * - * @return array - */ - public function failures() - { - return $this->failedRecipients; - } - - /** - * Get the Swift Mailer instance. + * Get the Symfony Transport instance. * - * @return \Swift_Mailer + * @return \Symfony\Component\Mailer\Transport\TransportInterface */ - public function getSwiftMailer() + public function getSymfonyTransport() { - return $this->swift; + return $this->transport; } /** @@ -601,14 +572,14 @@ public function getViewFactory() } /** - * Set the Swift Mailer instance. + * Set the Symfony Transport instance. * - * @param \Swift_Mailer $swift + * @param \Symfony\Component\Mailer\Transport\TransportInterface $transport * @return void */ - public function setSwiftMailer($swift) + public function setSymfonyTransport(TransportInterface $transport) { - $this->swift = $swift; + $this->transport = $transport; } /** diff --git a/src/Illuminate/Mail/Message.php b/src/Illuminate/Mail/Message.php index cab6c026d9fe..e225da983963 100755 --- a/src/Illuminate/Mail/Message.php +++ b/src/Illuminate/Mail/Message.php @@ -2,23 +2,24 @@ namespace Illuminate\Mail; +use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; -use Swift_Attachment; -use Swift_Image; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; /** - * @mixin \Swift_Message + * @mixin \Symfony\Component\Mime\Email */ class Message { use ForwardsCalls; /** - * The Swift Message instance. + * The Symfony Email instance. * - * @var \Swift_Message + * @var \Symfony\Component\Mime\Email */ - protected $swift; + protected $message; /** * CIDs of files embedded in the message. @@ -30,12 +31,12 @@ class Message /** * Create a new message instance. * - * @param \Swift_Message $swift + * @param \Symfony\Component\Mime\Email $message * @return void */ - public function __construct($swift) + public function __construct(Email $message) { - $this->swift = $swift; + $this->message = $message; } /** @@ -47,7 +48,9 @@ public function __construct($swift) */ public function from($address, $name = null) { - $this->swift->setFrom($address, $name); + is_array($address) + ? $this->message->from(...$address) + : $this->message->from(new Address($address, (string) $name)); return $this; } @@ -61,7 +64,9 @@ public function from($address, $name = null) */ public function sender($address, $name = null) { - $this->swift->setSender($address, $name); + is_array($address) + ? $this->message->sender(...$address) + : $this->message->sender(new Address($address, (string) $name)); return $this; } @@ -74,7 +79,7 @@ public function sender($address, $name = null) */ public function returnPath($address) { - $this->swift->setReturnPath($address); + $this->message->returnPath($address); return $this; } @@ -90,7 +95,9 @@ public function returnPath($address) public function to($address, $name = null, $override = false) { if ($override) { - $this->swift->setTo($address, $name); + is_array($address) + ? $this->message->to(...$address) + : $this->message->to(new Address($address, (string) $name)); return $this; } @@ -109,7 +116,9 @@ public function to($address, $name = null, $override = false) public function cc($address, $name = null, $override = false) { if ($override) { - $this->swift->setCc($address, $name); + is_array($address) + ? $this->message->cc(...$address) + : $this->message->cc(new Address($address, (string) $name)); return $this; } @@ -128,7 +137,9 @@ public function cc($address, $name = null, $override = false) public function bcc($address, $name = null, $override = false) { if ($override) { - $this->swift->setBcc($address, $name); + is_array($address) + ? $this->message->bcc(...$address) + : $this->message->bcc(new Address($address, (string) $name)); return $this; } @@ -159,9 +170,19 @@ public function replyTo($address, $name = null) protected function addAddresses($address, $name, $type) { if (is_array($address)) { - $this->swift->{"set{$type}"}($address, $name); + $type = lcfirst($type); + + $addresses = collect($address)->map(function (string|array $address) { + if (is_array($address)) { + return new Address($address['email'] ?? $address['address'], $address['name'] ?? null); + } + + return $address; + })->all(); + + $this->message->{"{$type}"}(...$addresses); } else { - $this->swift->{"add{$type}"}($address, $name); + $this->message->{"add{$type}"}(new Address($address, (string) $name)); } return $this; @@ -175,7 +196,7 @@ protected function addAddresses($address, $name, $type) */ public function subject($subject) { - $this->swift->setSubject($subject); + $this->message->subject($subject); return $this; } @@ -188,7 +209,7 @@ public function subject($subject) */ public function priority($level) { - $this->swift->setPriority($level); + $this->message->priority($level); return $this; } @@ -202,20 +223,9 @@ public function priority($level) */ public function attach($file, array $options = []) { - $attachment = $this->createAttachmentFromPath($file); - - return $this->prepAttachment($attachment, $options); - } + $this->message->attachFromPath($file, $options['as'] ?? null, $options['mime'] ?? null); - /** - * Create a Swift Attachment instance. - * - * @param string $file - * @return \Swift_Mime_Attachment - */ - protected function createAttachmentFromPath($file) - { - return Swift_Attachment::fromPath($file); + return $this; } /** @@ -228,21 +238,9 @@ protected function createAttachmentFromPath($file) */ public function attachData($data, $name, array $options = []) { - $attachment = $this->createAttachmentFromData($data, $name); + $this->message->attach($data, $name, $options['mime'] ?? null); - return $this->prepAttachment($attachment, $options); - } - - /** - * Create a Swift Attachment instance from data. - * - * @param string $data - * @param string $name - * @return \Swift_Attachment - */ - protected function createAttachmentFromData($data, $name) - { - return new Swift_Attachment($data, $name); + return $this; } /** @@ -253,13 +251,11 @@ protected function createAttachmentFromData($data, $name) */ public function embed($file) { - if (isset($this->embeddedFiles[$file])) { - return $this->embeddedFiles[$file]; - } + $cid = Str::random(10); - return $this->embeddedFiles[$file] = $this->swift->embed( - Swift_Image::fromPath($file) - ); + $this->message->embedFromPath($file, $cid); + + return "cid:$cid"; } /** @@ -272,51 +268,23 @@ public function embed($file) */ public function embedData($data, $name, $contentType = null) { - $image = new Swift_Image($data, $name, $contentType); - - return $this->swift->embed($image); - } - - /** - * Prepare and attach the given attachment. - * - * @param \Swift_Attachment $attachment - * @param array $options - * @return $this - */ - protected function prepAttachment($attachment, $options = []) - { - // First we will check for a MIME type on the message, which instructs the - // mail client on what type of attachment the file is so that it may be - // downloaded correctly by the user. The MIME option is not required. - if (isset($options['mime'])) { - $attachment->setContentType($options['mime']); - } + $this->message->embed($data, $name, $contentType); - // If an alternative name was given as an option, we will set that on this - // attachment so that it will be downloaded with the desired names from - // the developer, otherwise the default file names will get assigned. - if (isset($options['as'])) { - $attachment->setFilename($options['as']); - } - - $this->swift->attach($attachment); - - return $this; + return "cid:$name"; } /** - * Get the underlying Swift Message instance. + * Get the underlying Symfony Email instance. * - * @return \Swift_Message + * @return \Symfony\Component\Mime\Email */ - public function getSwiftMessage() + public function getSymfonyMessage() { - return $this->swift; + return $this->message; } /** - * Dynamically pass missing methods to the Swift instance. + * Dynamically pass missing methods to the Symfony instance. * * @param string $method * @param array $parameters @@ -324,6 +292,6 @@ public function getSwiftMessage() */ public function __call($method, $parameters) { - return $this->forwardCallTo($this->swift, $method, $parameters); + return $this->forwardCallTo($this->message, $method, $parameters); } } diff --git a/src/Illuminate/Mail/SentMessage.php b/src/Illuminate/Mail/SentMessage.php new file mode 100644 index 000000000000..cce42dbd009f --- /dev/null +++ b/src/Illuminate/Mail/SentMessage.php @@ -0,0 +1,54 @@ +sentMessage = $sentMessage; + } + + /** + * Get the underlying Symfony Email instance. + * + * @return \Symfony\Component\Mailer\SentMessage + */ + public function getSymfonySentMessage() + { + return $this->sentMessage; + } + + /** + * Dynamically pass missing methods to the Symfony instance. + * + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + return $this->forwardCallTo($this->sentMessage, $method, $parameters); + } +} diff --git a/src/Illuminate/Mail/Transport/ArrayTransport.php b/src/Illuminate/Mail/Transport/ArrayTransport.php index fbedec9560aa..dc26ed69d90b 100644 --- a/src/Illuminate/Mail/Transport/ArrayTransport.php +++ b/src/Illuminate/Mail/Transport/ArrayTransport.php @@ -3,12 +3,15 @@ namespace Illuminate\Mail\Transport; use Illuminate\Support\Collection; -use Swift_Mime_SimpleMessage; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\RawMessage; -class ArrayTransport extends Transport +class ArrayTransport implements TransportInterface { /** - * The collection of Swift Messages. + * The collection of Symfony Messages. * * @var \Illuminate\Support\Collection */ @@ -27,13 +30,9 @@ public function __construct() /** * {@inheritdoc} */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage { - $this->beforeSendPerformed($message); - - $this->messages[] = $message; - - return $this->numberOfRecipients($message); + return $this->messages[] = new SentMessage($message, $envelope ?? Envelope::create($message)); } /** @@ -55,4 +54,14 @@ public function flush() { return $this->messages = new Collection; } + + /** + * Get the string representation of the transport. + * + * @return string + */ + public function __toString(): string + { + return 'array'; + } } diff --git a/src/Illuminate/Mail/Transport/LogTransport.php b/src/Illuminate/Mail/Transport/LogTransport.php index 43a2faa204ce..d9ec8ac09d7e 100644 --- a/src/Illuminate/Mail/Transport/LogTransport.php +++ b/src/Illuminate/Mail/Transport/LogTransport.php @@ -3,10 +3,12 @@ namespace Illuminate\Mail\Transport; use Psr\Log\LoggerInterface; -use Swift_Mime_SimpleMessage; -use Swift_Mime_SimpleMimeEntity; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\RawMessage; -class LogTransport extends Transport +class LogTransport implements TransportInterface { /** * The Logger instance. @@ -29,41 +31,30 @@ public function __construct(LoggerInterface $logger) /** * {@inheritdoc} */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage { - $this->beforeSendPerformed($message); + $this->logger->debug($message->toString()); - $this->logger->debug($this->getMimeEntityString($message)); - - $this->sendPerformed($message); - - return $this->numberOfRecipients($message); + return new SentMessage($message, $envelope ?? Envelope::create($message)); } /** - * Get a loggable string out of a Swiftmailer entity. + * Get the logger for the LogTransport instance. * - * @param \Swift_Mime_SimpleMimeEntity $entity - * @return string + * @return \Psr\Log\LoggerInterface */ - protected function getMimeEntityString(Swift_Mime_SimpleMimeEntity $entity) + public function logger() { - $string = (string) $entity->getHeaders().PHP_EOL.$entity->getBody(); - - foreach ($entity->getChildren() as $children) { - $string .= PHP_EOL.PHP_EOL.$this->getMimeEntityString($children); - } - - return $string; + return $this->logger; } /** - * Get the logger for the LogTransport instance. + * Get the string representation of the transport. * - * @return \Psr\Log\LoggerInterface + * @return string */ - public function logger() + public function __toString(): string { - return $this->logger; + return 'log'; } } diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php deleted file mode 100644 index 1c862b1a7f30..000000000000 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ /dev/null @@ -1,216 +0,0 @@ -key = $key; - $this->client = $client; - $this->endpoint = $endpoint ?? 'api.mailgun.net'; - - $this->setDomain($domain); - } - - /** - * {@inheritdoc} - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - $this->beforeSendPerformed($message); - - $to = $this->getTo($message); - - $bcc = $message->getBcc(); - - $message->setBcc([]); - - $response = $this->client->request( - 'POST', - "https://{$this->endpoint}/v3/{$this->domain}/messages.mime", - $this->payload($message, $to) - ); - - $messageId = $this->getMessageId($response); - - $message->getHeaders()->addTextHeader('X-Message-ID', $messageId); - $message->getHeaders()->addTextHeader('X-Mailgun-Message-ID', $messageId); - - $message->setBcc($bcc); - - $this->sendPerformed($message); - - return $this->numberOfRecipients($message); - } - - /** - * Get the HTTP payload for sending the Mailgun message. - * - * @param \Swift_Mime_SimpleMessage $message - * @param string $to - * @return array - */ - protected function payload(Swift_Mime_SimpleMessage $message, $to) - { - return [ - 'auth' => [ - 'api', - $this->key, - ], - 'multipart' => [ - [ - 'name' => 'to', - 'contents' => $to, - ], - [ - 'name' => 'message', - 'contents' => $message->toString(), - 'filename' => 'message.mime', - ], - ], - ]; - } - - /** - * Get the "to" payload field for the API request. - * - * @param \Swift_Mime_SimpleMessage $message - * @return string - */ - protected function getTo(Swift_Mime_SimpleMessage $message) - { - return collect($this->allContacts($message))->map(function ($display, $address) { - return $display ? $display." <{$address}>" : $address; - })->values()->implode(','); - } - - /** - * Get all of the contacts for the message. - * - * @param \Swift_Mime_SimpleMessage $message - * @return array - */ - protected function allContacts(Swift_Mime_SimpleMessage $message) - { - return array_merge( - (array) $message->getTo(), (array) $message->getCc(), (array) $message->getBcc() - ); - } - - /** - * Get the message ID from the response. - * - * @param \Psr\Http\Message\ResponseInterface $response - * @return string - */ - protected function getMessageId($response) - { - return object_get( - json_decode($response->getBody()->getContents()), 'id' - ); - } - - /** - * Get the API key being used by the transport. - * - * @return string - */ - public function getKey() - { - return $this->key; - } - - /** - * Set the API key being used by the transport. - * - * @param string $key - * @return string - */ - public function setKey($key) - { - return $this->key = $key; - } - - /** - * Get the domain being used by the transport. - * - * @return string - */ - public function getDomain() - { - return $this->domain; - } - - /** - * Set the domain being used by the transport. - * - * @param string $domain - * @return string - */ - public function setDomain($domain) - { - return $this->domain = $domain; - } - - /** - * Get the API endpoint being used by the transport. - * - * @return string - */ - public function getEndpoint() - { - return $this->endpoint; - } - - /** - * Set the API endpoint being used by the transport. - * - * @param string $endpoint - * @return string - */ - public function setEndpoint($endpoint) - { - return $this->endpoint = $endpoint; - } -} diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php deleted file mode 100644 index cae80810fd20..000000000000 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ /dev/null @@ -1,94 +0,0 @@ -ses = $ses; - $this->options = $options; - } - - /** - * {@inheritdoc} - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - $this->beforeSendPerformed($message); - - $result = $this->ses->sendEmail( - array_merge( - $this->options, [ - 'Content' => [ - 'Raw' => ['Data' => $message->toString()], - ], - ] - ) - ); - - $messageId = $result->get('MessageId'); - - $message->getHeaders()->addTextHeader('X-Message-ID', $messageId); - $message->getHeaders()->addTextHeader('X-SES-Message-ID', $messageId); - - $this->sendPerformed($message); - - return $this->numberOfRecipients($message); - } - - /** - * Get the Amazon SES client for the SesTransport instance. - * - * @return \Aws\SesV2\SesV2Client - */ - public function ses() - { - return $this->ses; - } - - /** - * Get the transmission options being used by the transport. - * - * @return array - */ - public function getOptions() - { - return $this->options; - } - - /** - * Set the transmission options being used by the transport. - * - * @param array $options - * @return array - */ - public function setOptions(array $options) - { - return $this->options = $options; - } -} diff --git a/src/Illuminate/Mail/Transport/Transport.php b/src/Illuminate/Mail/Transport/Transport.php deleted file mode 100644 index b26bff3ff57d..000000000000 --- a/src/Illuminate/Mail/Transport/Transport.php +++ /dev/null @@ -1,108 +0,0 @@ -plugins, $plugin); - } - - /** - * Iterate through registered plugins and execute plugins' methods. - * - * @param \Swift_Mime_SimpleMessage $message - * @return void - */ - protected function beforeSendPerformed(Swift_Mime_SimpleMessage $message) - { - $event = new Swift_Events_SendEvent($this, $message); - - foreach ($this->plugins as $plugin) { - if (method_exists($plugin, 'beforeSendPerformed')) { - $plugin->beforeSendPerformed($event); - } - } - } - - /** - * Iterate through registered plugins and execute plugins' methods. - * - * @param \Swift_Mime_SimpleMessage $message - * @return void - */ - protected function sendPerformed(Swift_Mime_SimpleMessage $message) - { - $event = new Swift_Events_SendEvent($this, $message); - - foreach ($this->plugins as $plugin) { - if (method_exists($plugin, 'sendPerformed')) { - $plugin->sendPerformed($event); - } - } - } - - /** - * Get the number of recipients. - * - * @param \Swift_Mime_SimpleMessage $message - * @return int - */ - protected function numberOfRecipients(Swift_Mime_SimpleMessage $message) - { - return count(array_merge( - (array) $message->getTo(), (array) $message->getCc(), (array) $message->getBcc() - )); - } -} diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 53e88e315bd3..a5de844a8a33 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -23,7 +23,7 @@ "illuminate/support": "^9.0", "league/commonmark": "^2.0", "psr/log": "^1.0", - "swiftmailer/swiftmailer": "^6.2.7", + "symfony/mailer": "^6.0", "tijsverkoyen/css-to-inline-styles": "^2.2.2" }, "autoload": { @@ -37,9 +37,10 @@ } }, "suggest": { - "aws/aws-sdk-php": "Required to use the SES mail driver (^3.189.0).", - "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^7.2).", - "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." + "symfony/amazon-mailer": "Required to enable support for the SES mail transport (^6.0).", + "symfony/http-client": "Required to use the Symfony API mail transports (^6.0).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^6.0).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^6.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Notifications/Channels/MailChannel.php b/src/Illuminate/Notifications/Channels/MailChannel.php index 2a30bcdacc84..77885b87a88e 100644 --- a/src/Illuminate/Notifications/Channels/MailChannel.php +++ b/src/Illuminate/Notifications/Channels/MailChannel.php @@ -244,7 +244,7 @@ protected function addAttachments($mailMessage, $message) protected function runCallbacks($mailMessage, $message) { foreach ($message->callbacks as $callback) { - $callback($mailMessage->getSwiftMessage()); + $callback($mailMessage->getSymfonyMessage()); } return $this; diff --git a/src/Illuminate/Notifications/Messages/MailMessage.php b/src/Illuminate/Notifications/Messages/MailMessage.php index 94342f30b2bc..24c2515ca52c 100644 --- a/src/Illuminate/Notifications/Messages/MailMessage.php +++ b/src/Illuminate/Notifications/Messages/MailMessage.php @@ -322,12 +322,12 @@ public function render() } /** - * Register a callback to be called with the Swift message instance. + * Register a callback to be called with the Symfony message instance. * * @param callable $callback * @return $this */ - public function withSwiftMessage($callback) + public function withSymfonyMessage($callback) { $this->callbacks[] = $callback; diff --git a/src/Illuminate/Support/Facades/Mail.php b/src/Illuminate/Support/Facades/Mail.php index 36796e752e55..1408480d7768 100755 --- a/src/Illuminate/Support/Facades/Mail.php +++ b/src/Illuminate/Support/Facades/Mail.php @@ -10,6 +10,10 @@ * @method static \Illuminate\Mail\PendingMail to($users) * @method static \Illuminate\Support\Collection queued(string $mailable, \Closure|string $callback = null) * @method static \Illuminate\Support\Collection sent(string $mailable, \Closure|string $callback = null) + * @method static \Illuminate\Mail\SentMessage|null raw(string $text, $callback) + * @method static \Illuminate\Mail\SentMessage|null plain(string $view, array $data, $callback) + * @method static \Illuminate\Mail\SentMessage|null html(string $html, $callback) + * @method static \Illuminate\Mail\SentMessage|null send(\Illuminate\Contracts\Mail\Mailable|string|array $view, array $data = [], \Closure|string $callback = null) * @method static array failures() * @method static bool hasQueued(string $mailable) * @method static bool hasSent(string $mailable) @@ -23,10 +27,6 @@ * @method static void assertNothingSent() * @method static void assertQueued(string|\Closure $mailable, callable|int $callback = null) * @method static void assertSent(string|\Closure $mailable, callable|int $callback = null) - * @method static void raw(string $text, $callback) - * @method static void plain(string $view, array $data, $callback) - * @method static void html(string $html, $callback) - * @method static void send(\Illuminate\Contracts\Mail\Mailable|string|array $view, array $data = [], \Closure|string $callback = null) * * @see \Illuminate\Mail\Mailer * @see \Illuminate\Support\Testing\Fakes\MailFake diff --git a/tests/Integration/Mail/SendingMailWithLocaleTest.php b/tests/Integration/Mail/SendingMailWithLocaleTest.php index 5421e308d460..0031461f2e96 100644 --- a/tests/Integration/Mail/SendingMailWithLocaleTest.php +++ b/tests/Integration/Mail/SendingMailWithLocaleTest.php @@ -44,7 +44,7 @@ public function testMailIsSentWithDefaultLocale() Mail::to('test@mail.com')->send(new TestMail); $this->assertStringContainsString('name', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -53,7 +53,7 @@ public function testMailIsSentWithSelectedLocale() Mail::to('test@mail.com')->locale('ar')->send(new TestMail); $this->assertStringContainsString('esm', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -65,7 +65,7 @@ public function testMailIsSentWithLocaleFromMailable() Mail::to('test@mail.com')->send($mailable); $this->assertStringContainsString('esm', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -79,8 +79,8 @@ public function testMailIsSentWithLocaleUpdatedListenersCalled() Mail::to('test@mail.com')->locale('es')->send(new TimestampTestMail); - Assert::assertMatchesRegularExpression('/nombre (en|dentro de) (un|1) día/', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + Assert::assertMatchesRegularExpression('/nombre (en|dentro de) (un|1) d=C3=ADa/', + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); $this->assertSame('en', Carbon::getLocale()); @@ -96,7 +96,7 @@ public function testLocaleIsSentWithModelPreferredLocale() Mail::to($recipient)->send(new TestMail); $this->assertStringContainsString('esm', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -110,7 +110,7 @@ public function testLocaleIsSentWithSelectedLocaleOverridingModelPreferredLocale Mail::to($recipient)->locale('ar')->send(new TestMail); $this->assertStringContainsString('esm', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -129,7 +129,7 @@ public function testLocaleIsSentWithModelPreferredLocaleWillIgnorePreferredLocal Mail::to($toRecipient)->cc($ccRecipient)->send(new TestMail); $this->assertStringContainsString('esm', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -149,7 +149,7 @@ public function testLocaleIsNotSentWithModelPreferredLocaleWhenThereAreMultipleR Mail::to($recipients)->send(new TestMail); $this->assertStringContainsString('name', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -161,11 +161,11 @@ public function testLocaleIsSetBackToDefaultAfterMailSent() $this->assertSame('en', app('translator')->getLocale()); $this->assertStringContainsString('esm', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); $this->assertStringContainsString('name', - app('mailer')->getSwiftMailer()->getTransport()->messages()[1]->getBody() + app('mailer')->getSymfonyTransport()->messages()[1]->toString() ); } } diff --git a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php index c474742c3538..f309390f0d5a 100644 --- a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php +++ b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php @@ -76,7 +76,7 @@ public function testMailIsSentWithDefaultLocale() NotificationFacade::send($user, new GreetingMailNotification); $this->assertStringContainsString('hello', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -90,7 +90,7 @@ public function testMailIsSentWithFacadeSelectedLocale() NotificationFacade::locale('fr')->send($user, new GreetingMailNotification); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -110,11 +110,11 @@ public function testMailIsSentWithNotificationSelectedLocale() NotificationFacade::send($users, (new GreetingMailNotification)->locale('fr')); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[1]->getBody() + app('mailer')->getSymfonyTransport()->messages()[1]->toString() ); } @@ -128,7 +128,7 @@ public function testMailableIsSentWithSelectedLocale() NotificationFacade::locale('fr')->send($user, new GreetingMailNotificationWithMailable); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -148,11 +148,11 @@ public function testMailIsSentWithLocaleUpdatedListenersCalled() $user->notify((new GreetingMailNotification)->locale('fr')); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); Assert::assertMatchesRegularExpression('/dans (1|un) jour/', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); $this->assertTrue($this->app->isLocale('en')); @@ -170,7 +170,7 @@ public function testLocaleIsSentWithNotifiablePreferredLocale() $recipient->notify(new GreetingMailNotification); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -195,13 +195,13 @@ public function testLocaleIsSentWithNotifiablePreferredLocaleForMultipleRecipien ); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); $this->assertStringContainsString('hola', - app('mailer')->getSwiftMailer()->getTransport()->messages()[1]->getBody() + app('mailer')->getSymfonyTransport()->messages()[1]->toString() ); $this->assertStringContainsString('hello', - app('mailer')->getSwiftMailer()->getTransport()->messages()[2]->getBody() + app('mailer')->getSymfonyTransport()->messages()[2]->toString() ); } @@ -217,7 +217,7 @@ public function testLocaleIsSentWithNotificationSelectedLocaleOverridingNotifiab ); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } @@ -233,7 +233,7 @@ public function testLocaleIsSentWithFacadeSelectedLocaleOverridingNotifiablePref ); $this->assertStringContainsString('bonjour', - app('mailer')->getSwiftMailer()->getTransport()->messages()[0]->getBody() + app('mailer')->getSymfonyTransport()->messages()[0]->toString() ); } } @@ -285,7 +285,8 @@ public function via($notifiable) public function toMail($notifiable) { - return new GreetingMailable; + return (new GreetingMailable) + ->to($notifiable->email); } } diff --git a/tests/Mail/MailFailoverTransportTest.php b/tests/Mail/MailFailoverTransportTest.php index 6d8c8fec8bd9..15f9c0ed02a9 100644 --- a/tests/Mail/MailFailoverTransportTest.php +++ b/tests/Mail/MailFailoverTransportTest.php @@ -2,8 +2,8 @@ namespace Illuminate\Tests\Mail; -use Illuminate\Mail\Transport\ArrayTransport; use Orchestra\Testbench\TestCase; +use Symfony\Component\Mailer\Transport\FailoverTransport; class MailFailoverTransportTest extends TestCase { @@ -30,14 +30,8 @@ public function testGetFailoverTransportWithConfiguredTransports() ], ]); - $transport = app('mailer')->getSwiftMailer()->getTransport(); - $this->assertInstanceOf(\Swift_FailoverTransport::class, $transport); - - $transports = $transport->getTransports(); - $this->assertCount(2, $transports); - $this->assertInstanceOf(\Swift_SendmailTransport::class, $transports[0]); - $this->assertEquals('/usr/sbin/sendmail -bs', $transports[0]->getCommand()); - $this->assertInstanceOf(ArrayTransport::class, $transports[1]); + $transport = app('mailer')->getSymfonyTransport(); + $this->assertInstanceOf(FailoverTransport::class, $transport); } public function testGetFailoverTransportWithLaravel6StyleMailConfiguration() @@ -51,13 +45,7 @@ public function testGetFailoverTransportWithLaravel6StyleMailConfiguration() $this->app['config']->set('mail.sendmail', '/usr/sbin/sendmail -bs'); - $transport = app('mailer')->getSwiftMailer()->getTransport(); - $this->assertInstanceOf(\Swift_FailoverTransport::class, $transport); - - $transports = $transport->getTransports(); - $this->assertCount(2, $transports); - $this->assertInstanceOf(\Swift_SendmailTransport::class, $transports[0]); - $this->assertEquals('/usr/sbin/sendmail -bs', $transports[0]->getCommand()); - $this->assertInstanceOf(ArrayTransport::class, $transports[1]); + $transport = app('mailer')->getSymfonyTransport(); + $this->assertInstanceOf(FailoverTransport::class, $transport); } } diff --git a/tests/Mail/MailLogTransportTest.php b/tests/Mail/MailLogTransportTest.php index 5848734d2eec..9062347c9a54 100644 --- a/tests/Mail/MailLogTransportTest.php +++ b/tests/Mail/MailLogTransportTest.php @@ -22,7 +22,7 @@ public function testGetLogTransportWithConfiguredChannel() 'path' => 'mail.log', ]); - $transport = app('mailer')->getSwiftMailer()->getTransport(); + $transport = app('mailer')->getSymfonyTransport(); $this->assertInstanceOf(LogTransport::class, $transport); $logger = $transport->logger(); @@ -30,15 +30,16 @@ public function testGetLogTransportWithConfiguredChannel() $this->assertInstanceOf(Logger::class, $monolog = $logger->getLogger()); $this->assertCount(1, $handlers = $monolog->getHandlers()); - $this->assertInstanceOf(StreamHandler::class, $handler = $handlers[0]); + $this->assertInstanceOf(StreamHandler::class, $handlers[0]); } public function testGetLogTransportWithPsrLogger() { $this->app['config']->set('mail.driver', 'log'); + $logger = $this->app->instance('log', new NullLogger); - $transportLogger = app('mailer')->getSwiftMailer()->getTransport()->logger(); + $transportLogger = app('mailer')->getSymfonyTransport()->logger(); $this->assertEquals($logger, $transportLogger); } diff --git a/tests/Mail/MailMailerTest.php b/tests/Mail/MailMailerTest.php index b14b9ba285cd..5efc1b7019eb 100755 --- a/tests/Mail/MailMailerTest.php +++ b/tests/Mail/MailMailerTest.php @@ -7,194 +7,178 @@ use Illuminate\Mail\Events\MessageSending; use Illuminate\Mail\Events\MessageSent; use Illuminate\Mail\Mailer; +use Illuminate\Mail\Message; +use Illuminate\Mail\Transport\ArrayTransport; use Illuminate\Support\HtmlString; use Mockery as m; use PHPUnit\Framework\TestCase; -use stdClass; -use Swift_Mailer; -use Swift_Message; -use Swift_Mime_SimpleMessage; -use Swift_Transport; class MailMailerTest extends TestCase { protected function tearDown(): void { + unset($_SERVER['__mailer.test']); + m::close(); } public function testMailerSendSendsMessageWithProperViewContent() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMockBuilder(Mailer::class)->onlyMethods(['createMessage'])->setConstructorArgs($this->getMocks())->getMock(); - $message = m::mock(Swift_Mime_SimpleMessage::class); - $mailer->expects($this->once())->method('createMessage')->willReturn($message); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->with('foo', ['data', 'message' => $message])->andReturn($view); + $view = m::mock(Factory::class); + $view->shouldReceive('make')->once()->andReturn($view); $view->shouldReceive('render')->once()->andReturn('rendered.view'); - $message->shouldReceive('setBody')->once()->with('rendered.view', 'text/html'); - $message->shouldReceive('setFrom')->never(); - $this->setSwiftMailer($mailer); - $message->shouldReceive('getSwiftMessage')->once()->andReturn($message); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with($message, []); - $mailer->send('foo', ['data'], function ($m) { - $_SERVER['__mailer.test'] = $m; + + $mailer = new Mailer('array', $view, new ArrayTransport); + + $sentMessage = $mailer->send('foo', ['data'], function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); }); - unset($_SERVER['__mailer.test']); + + $this->assertStringContainsString('rendered.view', $sentMessage->toString()); } public function testMailerSendSendsMessageWithProperViewContentUsingHtmlStrings() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMockBuilder(Mailer::class)->onlyMethods(['createMessage'])->setConstructorArgs($this->getMocks())->getMock(); - $message = m::mock(Swift_Mime_SimpleMessage::class); - $mailer->expects($this->once())->method('createMessage')->willReturn($message); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->never(); + $view = m::mock(Factory::class); $view->shouldReceive('render')->never(); - $message->shouldReceive('setBody')->once()->with('rendered.view', 'text/html'); - $message->shouldReceive('addPart')->once()->with('rendered.text', 'text/plain'); - $message->shouldReceive('setFrom')->never(); - $this->setSwiftMailer($mailer); - $message->shouldReceive('getSwiftMessage')->once()->andReturn($message); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with($message, []); - $mailer->send(['html' => new HtmlString('rendered.view'), 'text' => new HtmlString('rendered.text')], ['data'], function ($m) { - $_SERVER['__mailer.test'] = $m; - }); - unset($_SERVER['__mailer.test']); + + $mailer = new Mailer('array', $view, new ArrayTransport); + + $sentMessage = $mailer->send( + ['html' => new HtmlString('

Hello Laravel

'), 'text' => new HtmlString('Hello World')], + ['data'], + function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); + } + ); + + $this->assertStringContainsString('

Hello Laravel

', $sentMessage->toString()); + $this->assertStringContainsString('Hello World', $sentMessage->toString()); } public function testMailerSendSendsMessageWithProperViewContentUsingHtmlMethod() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMockBuilder(Mailer::class)->onlyMethods(['createMessage'])->setConstructorArgs($this->getMocks())->getMock(); - $message = m::mock(Swift_Mime_SimpleMessage::class); - $mailer->expects($this->once())->method('createMessage')->willReturn($message); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->never(); + $view = m::mock(Factory::class); $view->shouldReceive('render')->never(); - $message->shouldReceive('setBody')->once()->with('rendered.view', 'text/html'); - $message->shouldReceive('setFrom')->never(); - $this->setSwiftMailer($mailer); - $message->shouldReceive('getSwiftMessage')->once()->andReturn($message); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with($message, []); - $mailer->html('rendered.view', function ($m) { - $_SERVER['__mailer.test'] = $m; + + $mailer = new Mailer('array', $view, new ArrayTransport); + + $sentMessage = $mailer->html('

Hello World

', function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); }); - unset($_SERVER['__mailer.test']); + + $this->assertStringContainsString('

Hello World

', $sentMessage->toString()); } public function testMailerSendSendsMessageWithProperPlainViewContent() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMockBuilder(Mailer::class)->onlyMethods(['createMessage'])->setConstructorArgs($this->getMocks())->getMock(); - $message = m::mock(Swift_Mime_SimpleMessage::class); - $mailer->expects($this->once())->method('createMessage')->willReturn($message); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->with('foo', ['data', 'message' => $message])->andReturn($view); - $mailer->getViewFactory()->shouldReceive('make')->once()->with('bar', ['data', 'message' => $message])->andReturn($view); - $view->shouldReceive('render')->twice()->andReturn('rendered.view'); - $message->shouldReceive('setBody')->once()->with('rendered.view', 'text/html'); - $message->shouldReceive('addPart')->once()->with('rendered.view', 'text/plain'); - $message->shouldReceive('setFrom')->never(); - $this->setSwiftMailer($mailer); - $message->shouldReceive('getSwiftMessage')->once()->andReturn($message); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with($message, []); - $mailer->send(['foo', 'bar'], ['data'], function ($m) { - $_SERVER['__mailer.test'] = $m; + $view = m::mock(Factory::class); + $view->shouldReceive('make')->twice()->andReturn($view); + $view->shouldReceive('render')->once()->andReturn('rendered.view'); + $view->shouldReceive('render')->once()->andReturn('rendered.plain'); + + $mailer = new Mailer('array', $view, new ArrayTransport); + + $sentMessage = $mailer->send(['foo', 'bar'], ['data'], function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); }); - unset($_SERVER['__mailer.test']); + + $expected = <<assertStringContainsString($expected, $sentMessage->toString()); + + $expected = <<assertStringContainsString($expected, $sentMessage->toString()); } public function testMailerSendSendsMessageWithProperPlainViewContentWhenExplicit() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMockBuilder(Mailer::class)->onlyMethods(['createMessage'])->setConstructorArgs($this->getMocks())->getMock(); - $message = m::mock(Swift_Mime_SimpleMessage::class); - $mailer->expects($this->once())->method('createMessage')->willReturn($message); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->with('foo', ['data', 'message' => $message])->andReturn($view); - $mailer->getViewFactory()->shouldReceive('make')->once()->with('bar', ['data', 'message' => $message])->andReturn($view); - $view->shouldReceive('render')->twice()->andReturn('rendered.view'); - $message->shouldReceive('setBody')->once()->with('rendered.view', 'text/html'); - $message->shouldReceive('addPart')->once()->with('rendered.view', 'text/plain'); - $message->shouldReceive('setFrom')->never(); - $this->setSwiftMailer($mailer); - $message->shouldReceive('getSwiftMessage')->once()->andReturn($message); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with($message, []); - $mailer->send(['html' => 'foo', 'text' => 'bar'], ['data'], function ($m) { - $_SERVER['__mailer.test'] = $m; + $view = m::mock(Factory::class); + $view->shouldReceive('make')->twice()->andReturn($view); + $view->shouldReceive('render')->once()->andReturn('rendered.view'); + $view->shouldReceive('render')->once()->andReturn('rendered.plain'); + + $mailer = new Mailer('array', $view, new ArrayTransport); + + $sentMessage = $mailer->send(['html' => 'foo', 'text' => 'bar'], ['data'], function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); }); - unset($_SERVER['__mailer.test']); + + $expected = <<assertStringContainsString($expected, $sentMessage->toString()); + + $expected = <<assertStringContainsString($expected, $sentMessage->toString()); } public function testGlobalFromIsRespectedOnAllMessages() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMailer(); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->andReturn($view); + $view = m::mock(Factory::class); + $view->shouldReceive('make')->once()->andReturn($view); $view->shouldReceive('render')->once()->andReturn('rendered.view'); - $this->setSwiftMailer($mailer); - $mailer->alwaysFrom('taylorotwell@gmail.com', 'Taylor Otwell'); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with(m::type(Swift_Message::class), [])->andReturnUsing(function ($message) { - $this->assertEquals(['taylorotwell@gmail.com' => 'Taylor Otwell'], $message->getFrom()); - }); - $mailer->send('foo', ['data'], function ($m) { - // + $mailer = new Mailer('array', $view, new ArrayTransport); + $mailer->alwaysFrom('hello@laravel.com'); + + $sentMessage = $mailer->send('foo', ['data'], function (Message $message) { + $message->to('taylor@laravel.com'); }); + + $this->assertSame('taylor@laravel.com', $sentMessage->getEnvelope()->getRecipients()[0]->getAddress()); } public function testGlobalReturnPathIsRespectedOnAllMessages() { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMailer(); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->andReturn($view); + $view = m::mock(Factory::class); + $view->shouldReceive('make')->once()->andReturn($view); $view->shouldReceive('render')->once()->andReturn('rendered.view'); - $this->setSwiftMailer($mailer); - $mailer->alwaysReturnPath('taylorotwell@gmail.com'); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with(m::type(Swift_Message::class), [])->andReturnUsing(function ($message) { - $this->assertSame('taylorotwell@gmail.com', $message->getReturnPath()); - }); - $mailer->send('foo', ['data'], function ($m) { - // - }); - } - public function testFailedRecipientsAreAppendedAndCanBeRetrieved() - { - unset($_SERVER['__mailer.test']); - $mailer = $this->getMailer(); - $mailer->getSwiftMailer()->shouldReceive('getTransport')->andReturn($transport = m::mock(Swift_Transport::class)); - $transport->shouldReceive('stop'); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->andReturn($view); - $view->shouldReceive('render')->once()->andReturn('rendered.view'); - $swift = new FailingSwiftMailerStub; - $mailer->setSwiftMailer($swift); + $mailer = new Mailer('array', $view, new ArrayTransport); + $mailer->alwaysReturnPath('taylorotwell@gmail.com'); - $mailer->send('foo', ['data'], function ($m) { - // + $sentMessage = $mailer->send('foo', ['data'], function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); }); - $this->assertEquals(['taylorotwell@gmail.com'], $mailer->failures()); + $this->assertStringContainsString('Return-Path: ', $sentMessage->toString()); } public function testEventsAreDispatched() { - unset($_SERVER['__mailer.test']); + $view = m::mock(Factory::class); + $view->shouldReceive('make')->once()->andReturn($view); + $view->shouldReceive('render')->once()->andReturn('rendered.view'); + $events = m::mock(Dispatcher::class); $events->shouldReceive('until')->once()->with(m::type(MessageSending::class)); $events->shouldReceive('dispatch')->once()->with(m::type(MessageSent::class)); - $mailer = $this->getMailer($events); - $view = m::mock(stdClass::class); - $mailer->getViewFactory()->shouldReceive('make')->once()->andReturn($view); - $view->shouldReceive('render')->once()->andReturn('rendered.view'); - $this->setSwiftMailer($mailer); - $mailer->getSwiftMailer()->shouldReceive('send')->once()->with(m::type(Swift_Message::class), []); - $mailer->send('foo', ['data'], function ($m) { - // + + $mailer = new Mailer('array', $view, new ArrayTransport, $events); + + $mailer->send('foo', ['data'], function (Message $message) { + $message->to('taylor@laravel.com')->from('hello@laravel.com'); }); } @@ -204,52 +188,10 @@ public function testMacroable() return 'bar'; }); - $mailer = $this->getMailer(); + $mailer = new Mailer('array', m::mock(Factory::class), new ArrayTransport); $this->assertSame( 'bar', $mailer->foo() ); } - - protected function getMailer($events = null) - { - return new Mailer('smtp', m::mock(Factory::class), m::mock(Swift_Mailer::class), $events); - } - - public function setSwiftMailer($mailer) - { - $swift = m::mock(Swift_Mailer::class); - $swift->shouldReceive('createMessage')->andReturn(new Swift_Message); - $swift->shouldReceive('getTransport')->andReturn($transport = m::mock(Swift_Transport::class)); - $transport->shouldReceive('stop'); - $mailer->setSwiftMailer($swift); - - return $mailer; - } - - protected function getMocks() - { - return ['smtp', m::mock(Factory::class), m::mock(Swift_Mailer::class)]; - } -} - -class FailingSwiftMailerStub -{ - public function send($message, &$failed) - { - $failed[] = 'taylorotwell@gmail.com'; - } - - public function getTransport() - { - $transport = m::mock(Swift_Transport::class); - $transport->shouldReceive('stop'); - - return $transport; - } - - public function createMessage() - { - return new Swift_Message; - } } diff --git a/tests/Mail/MailMessageTest.php b/tests/Mail/MailMessageTest.php index fa752a960c16..d36812492df4 100755 --- a/tests/Mail/MailMessageTest.php +++ b/tests/Mail/MailMessageTest.php @@ -3,18 +3,12 @@ namespace Illuminate\Tests\Mail; use Illuminate\Mail\Message; -use Mockery as m; use PHPUnit\Framework\TestCase; -use stdClass; -use Swift_Mime_Message; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; class MailMessageTest extends TestCase { - /** - * @var \Mockery::mock - */ - protected $swift; - /** * @var \Illuminate\Mail\Message */ @@ -24,100 +18,80 @@ protected function setUp(): void { parent::setUp(); - $this->swift = m::mock(Swift_Mime_Message::class); - $this->message = new Message($this->swift); - } - - protected function tearDown(): void - { - m::close(); + $this->message = new Message(new Email()); } public function testFromMethod() { - $this->swift->shouldReceive('setFrom')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->from('foo@bar.baz', 'Foo')); + $this->assertInstanceOf(Message::class, $message = $this->message->from('foo@bar.baz', 'Foo')); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getFrom()[0]); } public function testSenderMethod() { - $this->swift->shouldReceive('setSender')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->sender('foo@bar.baz', 'Foo')); + $this->assertInstanceOf(Message::class, $message = $this->message->sender('foo@bar.baz', 'Foo')); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getSender()); } public function testReturnPathMethod() { - $this->swift->shouldReceive('setReturnPath')->once()->with('foo@bar.baz'); - $this->assertInstanceOf(Message::class, $this->message->returnPath('foo@bar.baz')); + $this->assertInstanceOf(Message::class, $message = $this->message->returnPath('foo@bar.baz')); + $this->assertEquals(new Address('foo@bar.baz'), $message->getSymfonyMessage()->getReturnPath()); } public function testToMethod() { - $this->swift->shouldReceive('addTo')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->to('foo@bar.baz', 'Foo', false)); + $this->assertInstanceOf(Message::class, $message = $this->message->to('foo@bar.baz', 'Foo', false)); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getTo()[0]); } public function testToMethodWithOverride() { - $this->swift->shouldReceive('setTo')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->to('foo@bar.baz', 'Foo', true)); + $this->assertInstanceOf(Message::class, $message = $this->message->to('foo@bar.baz', 'Foo', true)); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getTo()[0]); } public function testCcMethod() { - $this->swift->shouldReceive('addCc')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->cc('foo@bar.baz', 'Foo')); + $this->assertInstanceOf(Message::class, $message = $this->message->cc('foo@bar.baz', 'Foo')); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getCc()[0]); } public function testBccMethod() { - $this->swift->shouldReceive('addBcc')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->bcc('foo@bar.baz', 'Foo')); + $this->assertInstanceOf(Message::class, $message = $this->message->bcc('foo@bar.baz', 'Foo')); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getBcc()[0]); } public function testReplyToMethod() { - $this->swift->shouldReceive('addReplyTo')->once()->with('foo@bar.baz', 'Foo'); - $this->assertInstanceOf(Message::class, $this->message->replyTo('foo@bar.baz', 'Foo')); + $this->assertInstanceOf(Message::class, $message = $this->message->replyTo('foo@bar.baz', 'Foo')); + $this->assertEquals(new Address('foo@bar.baz', 'Foo'), $message->getSymfonyMessage()->getReplyTo()[0]); } public function testSubjectMethod() { - $this->swift->shouldReceive('setSubject')->once()->with('foo'); - $this->assertInstanceOf(Message::class, $this->message->subject('foo')); + $this->assertInstanceOf(Message::class, $message = $this->message->subject('foo')); + $this->assertEquals('foo', $message->getSymfonyMessage()->getSubject()); } public function testPriorityMethod() { - $this->swift->shouldReceive('setPriority')->once()->with(1); - $this->assertInstanceOf(Message::class, $this->message->priority(1)); - } - - public function testGetSwiftMessageMethod() - { - $this->assertInstanceOf(Swift_Mime_Message::class, $this->message->getSwiftMessage()); + $this->assertInstanceOf(Message::class, $message = $this->message->priority(1)); + $this->assertEquals(1, $message->getSymfonyMessage()->getPriority()); } public function testBasicAttachment() { - $swift = m::mock(stdClass::class); - $message = $this->getMockBuilder(Message::class)->onlyMethods(['createAttachmentFromPath'])->setConstructorArgs([$swift])->getMock(); - $attachment = m::mock(stdClass::class); - $message->expects($this->once())->method('createAttachmentFromPath')->with($this->equalTo('foo.jpg'))->willReturn($attachment); - $swift->shouldReceive('attach')->once()->with($attachment); - $attachment->shouldReceive('setContentType')->once()->with('image/jpeg'); - $attachment->shouldReceive('setFilename')->once()->with('bar.jpg'); - $message->attach('foo.jpg', ['mime' => 'image/jpeg', 'as' => 'bar.jpg']); + $message = new Message(new Email()); + $message->attach('foo.jpg', ['as' => 'foo.jpg', 'mime' => 'image/jpeg']); } public function testDataAttachment() { - $swift = m::mock(stdClass::class); - $message = $this->getMockBuilder(Message::class)->onlyMethods(['createAttachmentFromData'])->setConstructorArgs([$swift])->getMock(); - $attachment = m::mock(stdClass::class); - $message->expects($this->once())->method('createAttachmentFromData')->with($this->equalTo('foo'), $this->equalTo('name'))->willReturn($attachment); - $swift->shouldReceive('attach')->once()->with($attachment); - $attachment->shouldReceive('setContentType')->once()->with('image/jpeg'); - $message->attachData('foo', 'name', ['mime' => 'image/jpeg']); + $message = new Message(new Email()); + $message->attachData('foo', 'foo.jpg', ['mime' => 'image/jpeg']); + + $this->assertEquals('foo', $message->getSymfonyMessage()->getAttachments()[0]->getBody()); } } diff --git a/tests/Mail/MailSesTransportTest.php b/tests/Mail/MailSesTransportTest.php deleted file mode 100644 index a6852b344364..000000000000 --- a/tests/Mail/MailSesTransportTest.php +++ /dev/null @@ -1,140 +0,0 @@ -singleton('config', function () { - return new Repository([ - 'services.ses' => [ - 'key' => 'foo', - 'secret' => 'bar', - 'region' => 'us-east-1', - ], - ]); - }); - - $manager = new MailManager($container); - - /** @var \Illuminate\Mail\Transport\SesTransport $transport */ - $transport = $manager->createTransport(['transport' => 'ses']); - - $ses = $transport->ses(); - - $this->assertSame('us-east-1', $ses->getRegion()); - } - - public function testSend() - { - $message = new Swift_Message('Foo subject', 'Bar body'); - $message->setSender('myself@example.com'); - $message->setTo('me@example.com'); - $message->setBcc('you@example.com'); - - $client = $this->getMockBuilder(SesV2Client::class) - ->addMethods(['sendEmail']) - ->disableOriginalConstructor() - ->getMock(); - $transport = new SesTransport($client); - - // Generate a messageId for our mock to return to ensure that the post-sent message - // has X-Message-ID in its headers - $messageId = Str::random(32); - $sendRawEmailMock = new SendRawEmailMock($messageId); - $client->expects($this->once()) - ->method('sendEmail') - ->with($this->equalTo([ - 'Content' => [ - 'Raw' => ['Data' => (string) $message], - ], - ])) - ->willReturn($sendRawEmailMock); - - $transport->send($message); - - $this->assertEquals($messageId, $message->getHeaders()->get('X-Message-ID')->getFieldBody()); - $this->assertEquals($messageId, $message->getHeaders()->get('X-SES-Message-ID')->getFieldBody()); - } - - public function testSesLocalConfiguration() - { - $container = new Container; - - $container->singleton('config', function () { - return new Repository([ - 'mail' => [ - 'mailers' => [ - 'ses' => [ - 'transport' => 'ses', - 'region' => 'eu-west-1', - 'options' => [ - 'ConfigurationSetName' => 'Laravel', - 'EmailTags' => [ - ['Name' => 'Laravel', 'Value' => 'Framework'], - ], - ], - ], - ], - ], - 'services' => [ - 'ses' => [ - 'region' => 'us-east-1', - ], - ], - ]); - }); - - $container->instance('view', $this->createMock(Factory::class)); - - $container->bind('events', function () { - return null; - }); - - $manager = new MailManager($container); - - /** @var \Illuminate\Mail\Mailer $mailer */ - $mailer = $manager->mailer('ses'); - - /** @var \Illuminate\Mail\Transport\SesTransport $transport */ - $transport = $mailer->getSwiftMailer()->getTransport(); - - $this->assertSame('eu-west-1', $transport->ses()->getRegion()); - - $this->assertSame([ - 'ConfigurationSetName' => 'Laravel', - 'EmailTags' => [ - ['Name' => 'Laravel', 'Value' => 'Framework'], - ], - ], $transport->getOptions()); - } -} - -class SendRawEmailMock -{ - protected $getResponse; - - public function __construct($responseValue) - { - $this->getResponse = $responseValue; - } - - public function get($key) - { - return $this->getResponse; - } -} diff --git a/tests/Mail/MailableQueuedTest.php b/tests/Mail/MailableQueuedTest.php index 47b93429e62e..274dea386754 100644 --- a/tests/Mail/MailableQueuedTest.php +++ b/tests/Mail/MailableQueuedTest.php @@ -15,7 +15,7 @@ use Illuminate\Support\Testing\Fakes\QueueFake; use Mockery as m; use PHPUnit\Framework\TestCase; -use Swift_Mailer; +use Symfony\Component\Mailer\Transport\TransportInterface; class MailableQueuedTest extends TestCase { @@ -91,7 +91,7 @@ public function testQueuedMailableWithAttachmentFromDiskSent() protected function getMocks() { - return ['smtp', m::mock(Factory::class), m::mock(Swift_Mailer::class)]; + return ['smtp', m::mock(Factory::class), m::mock(TransportInterface::class)]; } } diff --git a/tests/Notifications/NotificationMailMessageTest.php b/tests/Notifications/NotificationMailMessageTest.php index ba31b96df353..94db5b6d284c 100644 --- a/tests/Notifications/NotificationMailMessageTest.php +++ b/tests/Notifications/NotificationMailMessageTest.php @@ -128,7 +128,7 @@ public function testCallbackIsSetCorrectly() }; $message = new MailMessage; - $message->withSwiftMessage($callback); + $message->withSymfonyMessage($callback); $this->assertSame([$callback], $message->callbacks); } From 3eb951d206f6f6341bd4cac2a4db06168de2c593 Mon Sep 17 00:00:00 2001 From: Can Vural Date: Wed, 15 Sep 2021 12:32:09 +0200 Subject: [PATCH 191/194] Fixes invalid PHPDoc syntax --- src/Illuminate/Collections/Enumerable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index df98aa53856f..0cba6aec5a96 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -255,7 +255,7 @@ public function each(callable $callback); /** * Execute a callback over each nested chunk of items. * - * @param callable(...mixed): mixed $callback + * @param callable(mixed ...$args): mixed $callback * @return static */ public function eachSpread(callable $callback); @@ -606,7 +606,7 @@ public function map(callable $callback); * * @template TMapSpreadValue * - * @param callable(...mixed): TMapSpreadValue $callback + * @param callable(mixed ...$args): TMapSpreadValue $callback * @return static */ public function mapSpread(callable $callback); From 2832ecc98401b587b4f3a835da624d43efb7a2dd Mon Sep 17 00:00:00 2001 From: Can Vural Date: Wed, 15 Sep 2021 12:48:45 +0200 Subject: [PATCH 192/194] Update PHPDocs --- src/Illuminate/Collections/Enumerable.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 0cba6aec5a96..db94c741c981 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -255,7 +255,7 @@ public function each(callable $callback); /** * Execute a callback over each nested chunk of items. * - * @param callable(mixed ...$args): mixed $callback + * @param callable $callback * @return static */ public function eachSpread(callable $callback); @@ -604,10 +604,8 @@ public function map(callable $callback); /** * Run a map over each nested chunk of items. * - * @template TMapSpreadValue - * - * @param callable(mixed ...$args): TMapSpreadValue $callback - * @return static + * @param callable $callback + * @return static */ public function mapSpread(callable $callback); From 2b2420b501355047a43d8a11299b3b0cf79cf134 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 18 Sep 2021 19:55:33 +0200 Subject: [PATCH 193/194] [9.x] Update psr/log version (#38852) * Update psr/log * Add types for LogManager * Update Logger typing --- composer.json | 1 + src/Illuminate/Log/LogManager.php | 19 ++++++++++--------- src/Illuminate/Log/Logger.php | 21 +++++++++++---------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 716c37d35290..70dec7e20de4 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "nesbot/carbon": "^2.31", "opis/closure": "^3.6", "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^3.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.0", "symfony/console": "^6.0", diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index a3f7f0afdeab..b7dbe5dcc444 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -16,6 +16,7 @@ use Monolog\Handler\WhatFailureGroupHandler; use Monolog\Logger as Monolog; use Psr\Log\LoggerInterface; +use Stringable; use Throwable; class LogManager implements LoggerInterface @@ -521,7 +522,7 @@ protected function parseDriver($driver) * @param array $context * @return void */ - public function emergency($message, array $context = []) + public function emergency(string|Stringable $message, array $context = []): void { $this->driver()->emergency($message, $context); } @@ -536,7 +537,7 @@ public function emergency($message, array $context = []) * @param array $context * @return void */ - public function alert($message, array $context = []) + public function alert(string|Stringable $message, array $context = []): void { $this->driver()->alert($message, $context); } @@ -550,7 +551,7 @@ public function alert($message, array $context = []) * @param array $context * @return void */ - public function critical($message, array $context = []) + public function critical(string|Stringable $message, array $context = []): void { $this->driver()->critical($message, $context); } @@ -563,7 +564,7 @@ public function critical($message, array $context = []) * @param array $context * @return void */ - public function error($message, array $context = []) + public function error(string|Stringable $message, array $context = []): void { $this->driver()->error($message, $context); } @@ -578,7 +579,7 @@ public function error($message, array $context = []) * @param array $context * @return void */ - public function warning($message, array $context = []) + public function warning(string|Stringable $message, array $context = []): void { $this->driver()->warning($message, $context); } @@ -590,7 +591,7 @@ public function warning($message, array $context = []) * @param array $context * @return void */ - public function notice($message, array $context = []) + public function notice(string|Stringable $message, array $context = []): void { $this->driver()->notice($message, $context); } @@ -604,7 +605,7 @@ public function notice($message, array $context = []) * @param array $context * @return void */ - public function info($message, array $context = []) + public function info(string|Stringable $message, array $context = []): void { $this->driver()->info($message, $context); } @@ -616,7 +617,7 @@ public function info($message, array $context = []) * @param array $context * @return void */ - public function debug($message, array $context = []) + public function debug(string|Stringable $message, array $context = []): void { $this->driver()->debug($message, $context); } @@ -629,7 +630,7 @@ public function debug($message, array $context = []) * @param array $context * @return void */ - public function log($level, $message, array $context = []) + public function log($level, string|Stringable $message, array $context = []): void { $this->driver()->log($level, $message, $context); } diff --git a/src/Illuminate/Log/Logger.php b/src/Illuminate/Log/Logger.php index 382b77c6449f..ed7ac45b110d 100755 --- a/src/Illuminate/Log/Logger.php +++ b/src/Illuminate/Log/Logger.php @@ -9,6 +9,7 @@ use Illuminate\Log\Events\MessageLogged; use Psr\Log\LoggerInterface; use RuntimeException; +use Stringable; class Logger implements LoggerInterface { @@ -53,7 +54,7 @@ public function __construct(LoggerInterface $logger, Dispatcher $dispatcher = nu * @param array $context * @return void */ - public function emergency($message, array $context = []) + public function emergency(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -65,7 +66,7 @@ public function emergency($message, array $context = []) * @param array $context * @return void */ - public function alert($message, array $context = []) + public function alert(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -77,7 +78,7 @@ public function alert($message, array $context = []) * @param array $context * @return void */ - public function critical($message, array $context = []) + public function critical(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -89,7 +90,7 @@ public function critical($message, array $context = []) * @param array $context * @return void */ - public function error($message, array $context = []) + public function error(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -101,7 +102,7 @@ public function error($message, array $context = []) * @param array $context * @return void */ - public function warning($message, array $context = []) + public function warning(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -113,7 +114,7 @@ public function warning($message, array $context = []) * @param array $context * @return void */ - public function notice($message, array $context = []) + public function notice(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -125,7 +126,7 @@ public function notice($message, array $context = []) * @param array $context * @return void */ - public function info($message, array $context = []) + public function info(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -137,7 +138,7 @@ public function info($message, array $context = []) * @param array $context * @return void */ - public function debug($message, array $context = []) + public function debug(string|Stringable $message, array $context = []): void { $this->writeLog(__FUNCTION__, $message, $context); } @@ -150,7 +151,7 @@ public function debug($message, array $context = []) * @param array $context * @return void */ - public function log($level, $message, array $context = []) + public function log($level, string|Stringable $message, array $context = []): void { $this->writeLog($level, $message, $context); } @@ -163,7 +164,7 @@ public function log($level, $message, array $context = []) * @param array $context * @return void */ - public function write($level, $message, array $context = []) + public function write($level, string|Stringable $message, array $context = []): void { $this->writeLog($level, $message, $context); } From 1cc68d216974ae120d651300ceb46c5422a1bf5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Dorn?= Date: Sun, 19 Sep 2021 10:29:26 +0200 Subject: [PATCH 194/194] use nullsafe operator instead of optional --- src/Illuminate/Cache/DatabaseLock.php | 2 +- .../Database/Concerns/ManagesTransactions.php | 12 ++++++------ src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- src/Illuminate/Http/Client/PendingRequest.php | 8 ++++---- src/Illuminate/Http/Client/Response.php | 4 ++-- src/Illuminate/Routing/UrlGenerator.php | 2 +- src/Illuminate/Session/Middleware/StartSession.php | 2 +- src/Illuminate/View/AnonymousComponent.php | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Cache/DatabaseLock.php b/src/Illuminate/Cache/DatabaseLock.php index 7fd05c19134a..40d8e62b2fbb 100644 --- a/src/Illuminate/Cache/DatabaseLock.php +++ b/src/Illuminate/Cache/DatabaseLock.php @@ -134,7 +134,7 @@ public function forceRelease() */ protected function getCurrentOwner() { - return optional($this->connection->table($this->table)->where('key', $this->name)->first())->owner; + return $this->connection->table($this->table)->where('key', $this->name)->first()?->owner; } /** diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index fac70295de06..3b1875fb0f6e 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -48,7 +48,7 @@ public function transaction(Closure $callback, $attempts = 1) $this->transactions = max(0, $this->transactions - 1); if ($this->transactions == 0) { - optional($this->transactionsManager)->commit($this->getName()); + $this->transactionsManager?->commit($this->getName()); } } catch (Throwable $e) { $this->handleCommitTransactionException( @@ -83,7 +83,7 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma $this->transactions > 1) { $this->transactions--; - optional($this->transactionsManager)->rollback( + $this->transactionsManager?->rollback( $this->getName(), $this->transactions ); @@ -116,7 +116,7 @@ public function beginTransaction() $this->transactions++; - optional($this->transactionsManager)->begin( + $this->transactionsManager?->begin( $this->getName(), $this->transactions ); @@ -194,7 +194,7 @@ public function commit() $this->transactions = max(0, $this->transactions - 1); if ($this->transactions == 0) { - optional($this->transactionsManager)->commit($this->getName()); + $this->transactionsManager?->commit($this->getName()); } $this->fireConnectionEvent('committed'); @@ -258,7 +258,7 @@ public function rollBack($toLevel = null) $this->transactions = $toLevel; - optional($this->transactionsManager)->rollback( + $this->transactionsManager?->rollback( $this->getName(), $this->transactions ); @@ -297,7 +297,7 @@ protected function handleRollBackException(Throwable $e) if ($this->causedByLostConnection($e)) { $this->transactions = 0; - optional($this->transactionsManager)->rollback( + $this->transactionsManager?->rollback( $this->getName(), $this->transactions ); } diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 84ea798a973b..115c5d03a994 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -303,7 +303,7 @@ protected function context() try { return array_filter([ 'userId' => Auth::id(), - // 'email' => optional(Auth::user())->email, + // 'email' => Auth::user()?->email, ]); } catch (Throwable $e) { return []; diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 40a3a8755753..07b017154026 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -893,7 +893,7 @@ public function buildRecorderHandler() $promise = $handler($request, $options); return $promise->then(function ($response) use ($request, $options) { - optional($this->factory)->recordRequestResponsePair( + $this->factory?->recordRequestResponsePair( (new Request($request))->withData($options['laravel_data']), new Response($response) ); @@ -1030,7 +1030,7 @@ public function getPromise() */ protected function dispatchRequestSendingEvent() { - if ($dispatcher = optional($this->factory)->getDispatcher()) { + if ($dispatcher = $this->factory?->getDispatcher()) { $dispatcher->dispatch(new RequestSending($this->request)); } } @@ -1043,7 +1043,7 @@ protected function dispatchRequestSendingEvent() */ protected function dispatchResponseReceivedEvent(Response $response) { - if (! ($dispatcher = optional($this->factory)->getDispatcher()) || + if (! ($dispatcher = $this->factory?->getDispatcher()) || ! $this->request) { return; } @@ -1058,7 +1058,7 @@ protected function dispatchResponseReceivedEvent(Response $response) */ protected function dispatchConnectionFailedEvent() { - if ($dispatcher = optional($this->factory)->getDispatcher()) { + if ($dispatcher = $this->factory?->getDispatcher()) { $dispatcher->dispatch(new ConnectionFailed($this->request)); } } diff --git a/src/Illuminate/Http/Client/Response.php b/src/Illuminate/Http/Client/Response.php index 84ba0bd56c98..fca8544c37d4 100644 --- a/src/Illuminate/Http/Client/Response.php +++ b/src/Illuminate/Http/Client/Response.php @@ -127,7 +127,7 @@ public function status() */ public function effectiveUri() { - return optional($this->transferStats)->getEffectiveUri(); + return $this->transferStats?->getEffectiveUri(); } /** @@ -222,7 +222,7 @@ public function cookies() */ public function handlerStats() { - return optional($this->transferStats)->getHandlerStats() ?? []; + return $this->transferStats?->getHandlerStats() ?? []; } /** diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 0e2c7f01fd2f..a11755133f55 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -733,7 +733,7 @@ public function setRequest(Request $request) $this->cachedRoot = null; $this->cachedScheme = null; - tap(optional($this->routeGenerator)->defaultParameters ?: [], function ($defaults) { + tap($this->routeGenerator?->defaultParameters ?? [], function ($defaults) { $this->routeGenerator = null; if (! empty($defaults)) { diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index e7d2daa22315..e6edb690c457 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -95,7 +95,7 @@ protected function handleRequestWhileBlocking(Request $request, $session, Closur return $this->handleStatefulRequest($request, $session, $next); } finally { - optional($lock)->release(); + $lock?->release(); } } diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php index 2fb21e1afc4a..eba64365626b 100644 --- a/src/Illuminate/View/AnonymousComponent.php +++ b/src/Illuminate/View/AnonymousComponent.php @@ -51,7 +51,7 @@ public function data() $this->attributes = $this->attributes ?: $this->newAttributeBag(); return array_merge( - optional($this->data['attributes'] ?? null)->getAttributes() ?: [], + ($this->data['attributes'] ?? null)?->getAttributes() ?: [], $this->attributes->getAttributes(), $this->data, ['attributes' => $this->attributes]