From c85bd7ad882f3fdc27304e3f7f26e24d41b34fa9 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 7 Mar 2024 15:21:11 +0100 Subject: [PATCH 001/455] wip --- CHANGELOG.md | 4 ++-- bin/split.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 551ac543e62c..561b779964bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.0.0..11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.0.0..master) -## [v11.0.0 (2024-??-??)](https://github.com/laravel/framework/compare/v11.0.0...11.x) +## [v11.0.0 (2024-??-??)](https://github.com/laravel/framework/compare/v11.0.0...master) Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/11.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/11.x/releases). diff --git a/bin/split.sh b/bin/split.sh index 46033e130b99..9536ec7a4f31 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="11.x" +CURRENT_BRANCH="master" function split() { From ad1fb664690494cd4b3860e012bf1593a1c46f12 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 12 Mar 2024 15:26:59 +0100 Subject: [PATCH 002/455] [12.x] Prep Laravel v12 (#50406) * Prep Laravel v12 * wip * Temp constraint on prompts * wip --- CHANGELOG.md | 8 ++++---- bin/release.sh | 2 +- composer.json | 8 ++++---- src/Illuminate/Auth/composer.json | 20 ++++++++++---------- src/Illuminate/Broadcasting/composer.json | 14 +++++++------- src/Illuminate/Bus/composer.json | 10 +++++----- src/Illuminate/Cache/composer.json | 16 ++++++++-------- src/Illuminate/Collections/composer.json | 8 ++++---- src/Illuminate/Conditionable/composer.json | 2 +- src/Illuminate/Config/composer.json | 6 +++--- src/Illuminate/Console/composer.json | 22 +++++++++++----------- 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 | 12 ++++++------ src/Illuminate/Testing/composer.json | 16 ++++++++-------- src/Illuminate/Translation/composer.json | 12 ++++++------ src/Illuminate/Validation/composer.json | 16 ++++++++-------- src/Illuminate/View/composer.json | 16 ++++++++-------- 36 files changed, 195 insertions(+), 195 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 561b779964bf..6604857ad0c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ -# Release Notes for 11.x +# Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.0.0..master) +## [Unreleased](https://github.com/laravel/framework/compare/v12.0.0..master) -## [v11.0.0 (2024-??-??)](https://github.com/laravel/framework/compare/v11.0.0...master) +## [v12.0.0 (2025-??-??)](https://github.com/laravel/framework/compare/v12.0.0...master) -Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/11.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/11.x/releases). +Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/12.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/12.x/releases). diff --git a/bin/release.sh b/bin/release.sh index b629084461d7..7e2aa75df1b9 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -10,7 +10,7 @@ then exit 1 fi -RELEASE_BRANCH="11.x" +RELEASE_BRANCH="12.x" CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) VERSION=$1 diff --git a/composer.json b/composer.json index c1abf78580bc..7e960e95f2b4 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "fruitcake/php-cors": "^1.3", "guzzlehttp/guzzle": "^7.8", "guzzlehttp/uri-template": "^1.0", - "laravel/prompts": "^0.1.15", + "laravel/prompts": "dev-l12", "laravel/serializable-closure": "^1.3", "league/commonmark": "^2.2.1", "league/flysystem": "^3.8.0", @@ -106,7 +106,7 @@ "league/flysystem-sftp-v3": "^3.0", "mockery/mockery": "^1.6", "nyholm/psr7": "^1.2", - "orchestra/testbench-core": "^9.0", + "orchestra/testbench-core": "^10.0", "pda/pheanstalk": "^5.0", "phpstan/phpstan": "^1.4.7", "phpunit/phpunit": "^10.5|^11.0", @@ -151,7 +151,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { @@ -196,6 +196,6 @@ "composer/package-versions-deprecated": true } }, - "minimum-stability": "stable", + "minimum-stability": "dev", "prefer-stable": true } diff --git a/src/Illuminate/Auth/composer.json b/src/Illuminate/Auth/composer.json index 5b74a53b91c5..7073f8b060cc 100644 --- a/src/Illuminate/Auth/composer.json +++ b/src/Illuminate/Auth/composer.json @@ -16,12 +16,12 @@ "require": { "php": "^8.2", "ext-hash": "*", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/http": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/queue": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/http": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/queue": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -30,13 +30,13 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { - "illuminate/console": "Required to use the auth:clear-resets command (^11.0).", - "illuminate/queue": "Required to fire login / logout events (^11.0).", - "illuminate/session": "Required to use the session based guard (^11.0)." + "illuminate/console": "Required to use the auth:clear-resets command (^12.0).", + "illuminate/queue": "Required to fire login / logout events (^12.0).", + "illuminate/session": "Required to use the session based guard (^12.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index e9e6bbb4a211..103b02ac2733 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -16,12 +16,12 @@ "require": { "php": "^8.2", "psr/log": "^1.0|^2.0|^3.0", - "illuminate/bus": "^11.0", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/queue": "^11.0", - "illuminate/support": "^11.0" + "illuminate/bus": "^12.0", + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/queue": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index 3acfed639cf9..4f255d33abfa 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/pipeline": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/pipeline": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index ec0d26e18469..e49aea9fb3bd 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0" }, "provide": { "psr/simple-cache-implementation": "1.0|2.0|3.0" @@ -30,16 +30,16 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { "ext-apcu": "Required to use the APC cache driver.", "ext-filter": "Required to use the DynamoDb cache driver.", "ext-memcached": "Required to use the memcache cache driver.", - "illuminate/database": "Required to use the database cache driver (^11.0).", - "illuminate/filesystem": "Required to use the file cache driver (^11.0).", - "illuminate/redis": "Required to use the redis cache driver (^11.0).", + "illuminate/database": "Required to use the database cache driver (^12.0).", + "illuminate/filesystem": "Required to use the file cache driver (^12.0).", + "illuminate/redis": "Required to use the redis cache driver (^12.0).", "symfony/cache": "Required to use PSR-6 cache bridge (^7.0)." }, "config": { diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index 1924032ab915..b3577d8d6462 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^8.2", - "illuminate/conditionable": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0" + "illuminate/conditionable": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0" }, "autoload": { "psr-4": { @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Conditionable/composer.json b/src/Illuminate/Conditionable/composer.json index eb1d71eb18ab..919f09ef4611 100644 --- a/src/Illuminate/Conditionable/composer.json +++ b/src/Illuminate/Conditionable/composer.json @@ -23,7 +23,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Config/composer.json b/src/Illuminate/Config/composer.json index ccccc4303e09..48db6c1db52a 100755 --- a/src/Illuminate/Config/composer.json +++ b/src/Illuminate/Config/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 6284998cd1d9..9f99189266db 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -16,12 +16,12 @@ "require": { "php": "^8.2", "ext-mbstring": "*", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0", - "illuminate/view": "^11.0", - "laravel/prompts": "^0.1.12", + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0", + "illuminate/view": "^12.0", + "laravel/prompts": "dev-l12", "nunomaduro/termwind": "^2.0", "symfony/console": "^7.0", "symfony/polyfill-php83": "^1.28", @@ -34,17 +34,17 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { "ext-pcntl": "Required to use signal trapping.", "dragonmantank/cron-expression": "Required to use scheduler (^3.3.2).", "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^7.8).", - "illuminate/bus": "Required to use the scheduled job dispatcher (^11.0).", - "illuminate/container": "Required to use the scheduler (^11.0).", - "illuminate/filesystem": "Required to use the generator command (^11.0).", - "illuminate/queue": "Required to use closures for scheduled jobs (^11.0)." + "illuminate/bus": "Required to use the scheduled job dispatcher (^12.0).", + "illuminate/container": "Required to use the scheduler (^12.0).", + "illuminate/filesystem": "Required to use the generator command (^12.0).", + "illuminate/queue": "Required to use closures for scheduled jobs (^12.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index ab9f51c8f545..16d737f2a216 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": "^8.2", - "illuminate/contracts": "^11.0", + "illuminate/contracts": "^12.0", "psr/container": "^1.1.1|^2.0.1" }, "provide": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index c4b054c2521a..01e8f8495602 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index e8514738ce54..f910ea89b5b0 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -16,10 +16,10 @@ "require": { "php": "^8.2", "ext-hash": "*", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0", "symfony/http-foundation": "^7.0", "symfony/http-kernel": "^7.0" }, @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index bcbb837c0818..aefb9d8feda6 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -18,11 +18,11 @@ "php": "^8.2", "ext-pdo": "*", "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -31,16 +31,16 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { "ext-filter": "Required to use the Postgres database driver.", "fakerphp/faker": "Required to use the eloquent factory builder (^1.21).", - "illuminate/console": "Required to use the database commands (^11.0).", - "illuminate/events": "Required to use the observers with Eloquent (^11.0).", - "illuminate/filesystem": "Required to use the migrations (^11.0).", - "illuminate/pagination": "Required to paginate the result set (^11.0).", + "illuminate/console": "Required to use the database commands (^12.0).", + "illuminate/events": "Required to use the observers with Eloquent (^12.0).", + "illuminate/filesystem": "Required to use the migrations (^12.0).", + "illuminate/pagination": "Required to paginate the result set (^12.0).", "symfony/finder": "Required to use Eloquent model factories (^7.0)." }, "config": { diff --git a/src/Illuminate/Encryption/composer.json b/src/Illuminate/Encryption/composer.json index 0c127430432d..1c430e9c3e34 100644 --- a/src/Illuminate/Encryption/composer.json +++ b/src/Illuminate/Encryption/composer.json @@ -18,8 +18,8 @@ "ext-hash": "*", "ext-mbstring": "*", "ext-openssl": "*", - "illuminate/contracts": "^11.0", - "illuminate/support": "^11.0" + "illuminate/contracts": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Events/composer.json b/src/Illuminate/Events/composer.json index df77fedb69eb..801895fd899f 100755 --- a/src/Illuminate/Events/composer.json +++ b/src/Illuminate/Events/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^8.2", - "illuminate/bus": "^11.0", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0" + "illuminate/bus": "^12.0", + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 95ee6851a485..27e3e8d9c6f2 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0", "symfony/finder": "^7.0" }, "autoload": { @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index dcfee9faf8ab..eaa82f2e7b4a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.0.0'; + const VERSION = '12.x-dev'; /** * The base path for the Laravel installation. diff --git a/src/Illuminate/Hashing/composer.json b/src/Illuminate/Hashing/composer.json index 79443fb9d020..623485f95dfc 100755 --- a/src/Illuminate/Hashing/composer.json +++ b/src/Illuminate/Hashing/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^8.2", - "illuminate/contracts": "^11.0", - "illuminate/support": "^11.0" + "illuminate/contracts": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 9222aedd597b..077f95d6b409 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -19,10 +19,10 @@ "fruitcake/php-cors": "^1.3", "guzzlehttp/guzzle": "^7.8", "guzzlehttp/uri-template": "^1.0", - "illuminate/collections": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/session": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/session": "^12.0", + "illuminate/support": "^12.0", "symfony/http-foundation": "^7.0", "symfony/http-kernel": "^7.0", "symfony/polyfill-php83": "^1.28", @@ -38,7 +38,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index dfdcf13a4e7c..bf631882b2b6 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^8.2", - "illuminate/contracts": "^11.0", - "illuminate/support": "^11.0", + "illuminate/contracts": "^12.0", + "illuminate/support": "^12.0", "monolog/monolog": "^3.0" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Macroable/composer.json b/src/Illuminate/Macroable/composer.json index 08417d06884b..38dc6f161a42 100644 --- a/src/Illuminate/Macroable/composer.json +++ b/src/Illuminate/Macroable/composer.json @@ -23,7 +23,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index cf00d7cc483c..a07dac87ccd4 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -15,11 +15,11 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0", "league/commonmark": "^2.2", "psr/log": "^1.0|^2.0|^3.0", "symfony/mailer": "^7.0", @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index 18321766911a..4041897464c5 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -15,15 +15,15 @@ ], "require": { "php": "^8.2", - "illuminate/broadcasting": "^11.0", - "illuminate/bus": "^11.0", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/filesystem": "^11.0", - "illuminate/mail": "^11.0", - "illuminate/queue": "^11.0", - "illuminate/support": "^11.0" + "illuminate/broadcasting": "^12.0", + "illuminate/bus": "^12.0", + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/filesystem": "^12.0", + "illuminate/mail": "^12.0", + "illuminate/queue": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -32,11 +32,11 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { - "illuminate/database": "Required to use the database transport (^11.0)." + "illuminate/database": "Required to use the database transport (^12.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Pagination/composer.json b/src/Illuminate/Pagination/composer.json index 908762c245bd..b848b4a3b08d 100755 --- a/src/Illuminate/Pagination/composer.json +++ b/src/Illuminate/Pagination/composer.json @@ -16,9 +16,9 @@ "require": { "php": "^8.2", "ext-filter": "*", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Pipeline/composer.json b/src/Illuminate/Pipeline/composer.json index 9cd62e83f78c..fbc26da597d0 100644 --- a/src/Illuminate/Pipeline/composer.json +++ b/src/Illuminate/Pipeline/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^8.2", - "illuminate/contracts": "^11.0", - "illuminate/support": "^11.0" + "illuminate/contracts": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 54fddacecb46..0ef8f8a30926 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -15,14 +15,14 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/console": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/database": "^11.0", - "illuminate/filesystem": "^11.0", - "illuminate/pipeline": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/console": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/database": "^12.0", + "illuminate/filesystem": "^12.0", + "illuminate/pipeline": "^12.0", + "illuminate/support": "^12.0", "laravel/serializable-closure": "^1.2.2", "ramsey/uuid": "^4.7", "symfony/process": "^7.0" @@ -34,7 +34,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { @@ -44,7 +44,7 @@ "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.235.5).", - "illuminate/redis": "Required to use the Redis queue driver (^11.0).", + "illuminate/redis": "Required to use the Redis queue driver (^12.0).", "pda/pheanstalk": "Required to use the Beanstalk queue driver (^5.0)." }, "config": { diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index 1686aeaa13f6..5e403c89c74a 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index a9c4b8a78810..4b46bc149099 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -17,14 +17,14 @@ "php": "^8.2", "ext-filter": "*", "ext-hash": "*", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/http": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/pipeline": "^11.0", - "illuminate/session": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/http": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/pipeline": "^12.0", + "illuminate/session": "^12.0", + "illuminate/support": "^12.0", "symfony/http-foundation": "^7.0", "symfony/http-kernel": "^7.0", "symfony/routing": "^7.0" @@ -36,11 +36,11 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { - "illuminate/console": "Required to use the make commands (^11.0).", + "illuminate/console": "Required to use the make commands (^12.0).", "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.0)." }, diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 56789edc0f78..2ed4196bdffb 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -17,10 +17,10 @@ "php": "^8.2", "ext-ctype": "*", "ext-session": "*", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/filesystem": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/filesystem": "^12.0", + "illuminate/support": "^12.0", "symfony/finder": "^7.0", "symfony/http-foundation": "^7.0" }, @@ -31,11 +31,11 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { - "illuminate/console": "Required to use the session:table command (^11.0)." + "illuminate/console": "Required to use the session:table command (^12.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 5be0cdb4c2d7..db8ea88fa77c 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -19,10 +19,10 @@ "ext-filter": "*", "ext-mbstring": "*", "doctrine/inflector": "^2.0", - "illuminate/collections": "^11.0", - "illuminate/conditionable": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/conditionable": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", "nesbot/carbon": "^2.72.2|^3.0", "voku/portable-ascii": "^2.0" }, @@ -42,11 +42,11 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (^11.0).", + "illuminate/filesystem": "Required to use the composer class (^12.0).", "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0.2).", "ramsey/uuid": "Required to use Str::uuid() (^4.7).", "symfony/process": "Required to use the composer class (^7.0).", diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index 2046c34945fe..29254b53a515 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -16,10 +16,10 @@ "require": { "php": "^8.2", "ext-mbstring": "*", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -28,14 +28,14 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", - "illuminate/console": "Required to assert console commands (^11.0).", - "illuminate/database": "Required to assert databases (^11.0).", - "illuminate/http": "Required to assert responses (^11.0).", + "illuminate/console": "Required to assert console commands (^12.0).", + "illuminate/database": "Required to assert databases (^12.0).", + "illuminate/http": "Required to assert responses (^12.0).", "mockery/mockery": "Required to use mocking (^1.6).", "phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0)." }, diff --git a/src/Illuminate/Translation/composer.json b/src/Illuminate/Translation/composer.json index 539a651b2696..1b0dfa7a5d4b 100755 --- a/src/Illuminate/Translation/composer.json +++ b/src/Illuminate/Translation/composer.json @@ -15,11 +15,11 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/filesystem": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/filesystem": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index ac4f997747a0..74e7c1e61c17 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -19,12 +19,12 @@ "ext-mbstring": "*", "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", "egulias/email-validator": "^3.2.5|^4.0", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0", - "illuminate/translation": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0", + "illuminate/translation": "^12.0", "symfony/http-foundation": "^7.0", "symfony/mime": "^7.0" }, @@ -35,11 +35,11 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "suggest": { - "illuminate/database": "Required to use the database presence verifier (^11.0)." + "illuminate/database": "Required to use the database presence verifier (^12.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index 41472bc1cff1..fd32f9538711 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -16,13 +16,13 @@ "require": { "php": "^8.2", "ext-tokenizer": "*", - "illuminate/collections": "^11.0", - "illuminate/container": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/events": "^11.0", - "illuminate/filesystem": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0" + "illuminate/collections": "^12.0", + "illuminate/container": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/events": "^12.0", + "illuminate/filesystem": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0" }, "autoload": { "psr-4": { @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { From 71c605623480bad3e6f2a36dc23d05a517cbf69c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Mar 2024 14:29:01 +0100 Subject: [PATCH 003/455] wip --- .github/workflows/databases.yml | 10 +++++----- .github/workflows/queues.yml | 8 ++++---- .github/workflows/static-analysis.yml | 2 +- .github/workflows/tests.yml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/databases.yml b/.github/workflows/databases.yml index 63f1aef541a6..1c86c839e614 100644 --- a/.github/workflows/databases.yml +++ b/.github/workflows/databases.yml @@ -39,7 +39,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -85,7 +85,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -130,7 +130,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -176,7 +176,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -222,7 +222,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 diff --git a/.github/workflows/queues.yml b/.github/workflows/queues.yml index 7d3687525f7d..904795428c49 100644 --- a/.github/workflows/queues.yml +++ b/.github/workflows/queues.yml @@ -29,7 +29,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -64,7 +64,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -107,7 +107,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -146,7 +146,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 9d64580c9719..0bb02e7bac32 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -30,7 +30,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8cf52370707c..3dcd0ce3b516 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,7 +62,7 @@ jobs: REDIS_LIBS: liblz4-dev, liblzf-dev, libzstd-dev - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Set minimum PHP 8.2 versions uses: nick-fields/retry@v3 @@ -133,7 +133,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Set Minimum PHP 8.2 Versions uses: nick-fields/retry@v3 From fb14d4326b780a9b2087caf7f12440f45a0f385c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Mar 2024 15:12:56 +0100 Subject: [PATCH 004/455] wip --- .github/workflows/facades.yml | 2 +- src/Illuminate/Process/composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/facades.yml b/.github/workflows/facades.yml index 59c05df44b85..da43a055b5f2 100644 --- a/.github/workflows/facades.yml +++ b/.github/workflows/facades.yml @@ -29,7 +29,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 diff --git a/src/Illuminate/Process/composer.json b/src/Illuminate/Process/composer.json index 1fecb13ba822..cb672fe06544 100644 --- a/src/Illuminate/Process/composer.json +++ b/src/Illuminate/Process/composer.json @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "config": { From baed746a6fe531ca928ad665a9201eed3646ff06 Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Thu, 25 Apr 2024 16:28:58 +0200 Subject: [PATCH 005/455] [12.x] Make `Str::is()` match multiline strings (#51196) * make Str::is() support multiline strings * more tests with patterns containing new lines * cs * cs --- src/Illuminate/Process/PendingProcess.php | 2 +- src/Illuminate/Support/Str.php | 4 +- tests/Process/ProcessTest.php | 25 +++++++++++- tests/Support/SupportStrTest.php | 46 +++++++++++++++++++++++ tests/Support/SupportStringableTest.php | 32 ++++++++++++++++ 5 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Process/PendingProcess.php b/src/Illuminate/Process/PendingProcess.php index 48a28f6b335a..9c2847c58ca5 100644 --- a/src/Illuminate/Process/PendingProcess.php +++ b/src/Illuminate/Process/PendingProcess.php @@ -350,7 +350,7 @@ public function withFakeHandlers(array $fakeHandlers) protected function fakeFor(string $command) { return collect($this->fakeHandlers) - ->first(fn ($handler, $pattern) => $pattern === '*' || Str::is($pattern, $command)); + ->first(fn ($handler, $pattern) => Str::is($pattern, $command)); } /** diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 39570a4bf002..557ddd4ef1f3 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -432,7 +432,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 === '*' || $pattern === $value) { return true; } @@ -443,7 +443,7 @@ public static function is($pattern, $value) // pattern such as "library/*", making any string check convenient. $pattern = str_replace('\*', '.*', $pattern); - if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { + if (preg_match('#^'.$pattern.'\z#su', $value) === 1) { return true; } } diff --git a/tests/Process/ProcessTest.php b/tests/Process/ProcessTest.php index 4c914b2e9698..5369d3f552c8 100644 --- a/tests/Process/ProcessTest.php +++ b/tests/Process/ProcessTest.php @@ -156,7 +156,7 @@ public function testBasicProcessFakeWithMultiLineCommand() $factory->preventStrayProcesses(); $factory->fake([ - '*' => 'The output', + '*' => $expectedOutput = 'The output', ]); $result = $factory->run(<<<'COMMAND' @@ -167,6 +167,29 @@ public function testBasicProcessFakeWithMultiLineCommand() COMMAND); $this->assertSame(0, $result->exitCode()); + $this->assertSame("$expectedOutput\n", $result->output()); + } + + public function testProcessFakeWithMultiLineCommand() + { + $factory = new Factory; + + $factory->preventStrayProcesses(); + + $factory->fake([ + '*--branch main*' => 'not this one', + '*--branch develop*' => $expectedOutput = 'yes thank you', + ]); + + $result = $factory->run(<<<'COMMAND' + git clone --depth 1 \ + --single-branch \ + --branch develop \ + git://some-url . + COMMAND); + + $this->assertSame(0, $result->exitCode()); + $this->assertSame("$expectedOutput\n", $result->output()); } public function testProcessFakeExitCodes() diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 909699b7a266..1f4ab12ad738 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -487,6 +487,52 @@ public function testIs() $this->assertTrue(Str::is([null], null)); } + public function testIsWithMultilineStrings() + { + $this->assertFalse(Str::is('/', "/\n")); + $this->assertTrue(Str::is('/*', "/\n")); + $this->assertTrue(Str::is('*/*', "/\n")); + $this->assertTrue(Str::is('*/*', "\n/\n")); + + $this->assertTrue(Str::is('*', "\n")); + $this->assertTrue(Str::is('*', "\n\n")); + $this->assertFalse(Str::is('', "\n")); + $this->assertFalse(Str::is('', "\n\n")); + + $multilineValue = <<<'VALUE' + assertTrue(Str::is($multilineValue, $multilineValue)); + $this->assertTrue(Str::is('*', $multilineValue)); + $this->assertTrue(Str::is("*namespace Illuminate\Tests\*", $multilineValue)); + $this->assertFalse(Str::is("namespace Illuminate\Tests\*", $multilineValue)); + $this->assertFalse(Str::is("*namespace Illuminate\Tests", $multilineValue)); + $this->assertTrue(Str::is('assertTrue(Str::is("assertFalse(Str::is('use Exception;', $multilineValue)); + $this->assertFalse(Str::is('use Exception;*', $multilineValue)); + $this->assertTrue(Str::is('*use Exception;', $multilineValue)); + + $this->assertTrue(Str::is("assertTrue(Str::is(<<<'PATTERN' + assertTrue(Str::is(<<<'PATTERN' + assertTrue(Str::isUrl('https://laravel.com')); diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index a1de110b6fc7..2c8e3d8ff702 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -800,6 +800,38 @@ public function testIs() $this->assertFalse($this->stringable('test')->is([])); } + public function testIsWithMultilineStrings() + { + $this->assertFalse($this->stringable("/\n")->is('/')); + $this->assertTrue($this->stringable("/\n")->is('/*')); + $this->assertTrue($this->stringable("/\n")->is('*/*')); + $this->assertTrue($this->stringable("\n/\n")->is('*/*')); + + $this->assertTrue($this->stringable("\n")->is('*')); + $this->assertTrue($this->stringable("\n\n")->is('*')); + $this->assertFalse($this->stringable("\n")->is('')); + $this->assertFalse($this->stringable("\n\n")->is('')); + + $multilineValue = <<<'VALUE' + assertTrue($this->stringable($multilineValue)->is($multilineValue)); + $this->assertTrue($this->stringable($multilineValue)->is('*')); + $this->assertTrue($this->stringable($multilineValue)->is("*namespace Illuminate\Tests\*")); + $this->assertFalse($this->stringable($multilineValue)->is("namespace Illuminate\Tests\*")); + $this->assertFalse($this->stringable($multilineValue)->is("*namespace Illuminate\Tests")); + $this->assertTrue($this->stringable($multilineValue)->is('assertTrue($this->stringable($multilineValue)->is("assertFalse($this->stringable($multilineValue)->is('use Exception;')); + $this->assertFalse($this->stringable($multilineValue)->is('use Exception;*')); + $this->assertTrue($this->stringable($multilineValue)->is('*use Exception;')); + } + public function testKebab() { $this->assertSame('laravel-php-framework', (string) $this->stringable('LaravelPhpFramework')->kebab()); From f22eaf2fcfe1ae626e55e7cc85e1af2259642c80 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 20 May 2024 15:30:12 +0200 Subject: [PATCH 006/455] Use native MariaDB CLI commands (#51505) --- src/Illuminate/Database/Console/DbCommand.php | 2 +- .../Database/Schema/MariaDbSchemaState.php | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index b7561e08277f..38dde8bbd412 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -133,7 +133,7 @@ public function getCommand(array $connection) { return [ 'mysql' => 'mysql', - 'mariadb' => 'mysql', + 'mariadb' => 'mariadb', 'pgsql' => 'psql', 'sqlite' => 'sqlite3', 'sqlsrv' => 'sqlcmd', diff --git a/src/Illuminate/Database/Schema/MariaDbSchemaState.php b/src/Illuminate/Database/Schema/MariaDbSchemaState.php index f8323c4471f2..93fbba9b38a3 100644 --- a/src/Illuminate/Database/Schema/MariaDbSchemaState.php +++ b/src/Illuminate/Database/Schema/MariaDbSchemaState.php @@ -4,6 +4,23 @@ class MariaDbSchemaState extends MySqlSchemaState { + /** + * Load the given schema file into the database. + * + * @param string $path + * @return void + */ + public function load($path) + { + $command = 'mariadb '.$this->connectionString().' --database="${:LARAVEL_LOAD_DATABASE}" < "${:LARAVEL_LOAD_PATH}"'; + + $process = $this->makeProcess($command)->setTimeout(null); + + $process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [ + 'LARAVEL_LOAD_PATH' => $path, + ])); + } + /** * Get the base dump command arguments for MariaDB as a string. * @@ -11,7 +28,7 @@ class MariaDbSchemaState extends MySqlSchemaState */ protected function baseDumpCommand() { - $command = 'mysqldump '.$this->connectionString().' --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc --column-statistics=0'; + $command = 'mariadb-dump '.$this->connectionString().' --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc'; return $command.' "${:LARAVEL_LOAD_DATABASE}"'; } From 500c039fbcea0c46c0741fe951a8892fc1a89945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilsen=20Hern=C3=A1ndez?= <13445515+wilsenhc@users.noreply.github.com> Date: Thu, 23 May 2024 14:40:22 -0400 Subject: [PATCH 007/455] [12.x] Adds missing streamJson() to ResponseFactory contract (#51544) * [12.x] Adds missing streamJson() to ResponseFactory contact * Update ResponseFactory.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Contracts/Routing/ResponseFactory.php | 11 +++++++++++ src/Illuminate/Routing/ResponseFactory.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Contracts/Routing/ResponseFactory.php b/src/Illuminate/Contracts/Routing/ResponseFactory.php index 0aa51d5515f0..22cbd3cb1a83 100644 --- a/src/Illuminate/Contracts/Routing/ResponseFactory.php +++ b/src/Illuminate/Contracts/Routing/ResponseFactory.php @@ -67,6 +67,17 @@ public function jsonp($callback, $data = [], $status = 200, array $headers = [], */ public function stream($callback, $status = 200, array $headers = []); + /** + * Create a new streamed JSON response instance. + * + * @param array $data + * @param int $status + * @param array $headers + * @param int $encodingOptions + * @return \Symfony\Component\HttpFoundation\StreamedJsonResponse + */ + public function streamJson($data, $status = 200, $headers = [], $encodingOptions = 15); + /** * Create a new streamed response instance as a file download. * diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index 0c90965c897f..03a688f9d75a 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -131,7 +131,7 @@ public function stream($callback, $status = 200, array $headers = []) } /** - * Create a new streamed response instance. + * Create a new streamed JSON response instance. * * @param array $data * @param int $status From 83e28d065b7bc53f3e53a5c188806844eee30161 Mon Sep 17 00:00:00 2001 From: Adrien Foulon <6115458+Tofandel@users.noreply.github.com> Date: Thu, 30 May 2024 16:45:43 +0200 Subject: [PATCH 008/455] Merge preserving keys only one level deep (#51516) --- src/Illuminate/Validation/Validator.php | 6 ++--- tests/Validation/ValidationValidatorTest.php | 23 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 2dff098c11a2..d20dcc60cb50 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -1205,9 +1205,9 @@ public function addRules($rules) $response = (new ValidationRuleParser($this->data)) ->explode(ValidationRuleParser::filterConditionalRules($rules, $this->data)); - $this->rules = array_merge_recursive( - $this->rules, $response->rules - ); + foreach ($response->rules as $key => $rule) { + $this->rules[$key] = array_merge($this->rules[$key] ?? [], $rule); + } $this->implicitAttributes = array_merge( $this->implicitAttributes, $response->implicitAttributes diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 7defa977f82c..d0009f1cb7c6 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -5090,6 +5090,29 @@ public function testAlternativeFormat() $this->assertTrue($v->passes()); } + public function testNumericKeys() + { + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['3' => 'aslsdlks'], [3 => 'required']); + $this->assertTrue($v->passes()); + } + + public function testMergeRules() + { + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['x' => 'asl', 'a' => [1, 4]], ['x' => ['alpha', ['min', 3]], 'a.*' => 'integer']); + $v->addRules(['x' => ['required', ['max', 10]], 'a.1' => 'digits:1']); + $this->assertEquals( + [ + 'x' => ['alpha', ['min', 3], 'required', ['max', 10]], + 'a.0' => ['integer'], + 'a.1' => ['integer', 'digits:1'], + ], + $v->getRules() + ); + $this->assertTrue($v->passes()); + } + public function testValidateAlpha() { $trans = $this->getIlluminateArrayTranslator(); From 6aae2a34a0a22dcdf9d3f71d37b2a83ca43fe0c2 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 24 Jul 2024 09:51:01 +0800 Subject: [PATCH 009/455] [12.x] Test Improvements (#52248) --- .github/workflows/databases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/databases.yml b/.github/workflows/databases.yml index 33be1d59d4c5..9d4a21b87f9c 100644 --- a/.github/workflows/databases.yml +++ b/.github/workflows/databases.yml @@ -260,7 +260,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 From 42be005969164d9f50d46805a68929b212be3e09 Mon Sep 17 00:00:00 2001 From: Hristijan Manasijev <34198639+KIKOmanasijev@users.noreply.github.com> Date: Mon, 29 Jul 2024 09:44:38 +0200 Subject: [PATCH 010/455] [12.x] mergeIfMissing allows merging with nested arrays (#52242) * feat: mergeIfMissing allows merging with nested arrays * Fix failing tests * Fix styling --- src/Illuminate/Http/Request.php | 14 +++++++++----- tests/Http/HttpRequestTest.php | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 40a61eff5736..55c0d9c447d2 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -349,9 +349,13 @@ public function userAgent() */ public function merge(array $input) { - $this->getInputSource()->add($input); - - return $this; + return tap($this, function (Request $request) use ($input) { + $request->getInputSource() + ->replace(collect($input)->reduce( + fn ($requestInput, $value, $key) => data_set($requestInput, $key, $value), + $this->getInputSource()->all() + )); + }); } /** @@ -547,8 +551,8 @@ public function hasSession(bool $skipIfUninitialized = false): bool public function getSession(): SessionInterface { return $this->hasSession() - ? $this->session - : throw new SessionNotFoundException; + ? $this->session + : throw new SessionNotFoundException; } /** diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 7c4f26872d5c..031d613f3e5b 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -983,6 +983,16 @@ public function testMergeIfMissingMethod() $request->mergeIfMissing($merge); $this->assertSame('Taylor', $request->input('name')); $this->assertSame(1, $request->input('boolean_setting')); + + $request = Request::create('/', 'GET', ['user' => ['first_name' => 'Taylor', 'email' => 'taylor@laravel.com']]); + $merge = ['user.last_name' => 'Otwell']; + $request->mergeIfMissing($merge); + $this->assertSame('Otwell', $request->input('user.last_name')); + + $request = Request::create('/', 'GET', ['user' => ['first_name' => 'Taylor', 'email' => 'taylor@laravel.com']]); + $merge = ['user.first_name' => 'John']; + $request->mergeIfMissing($merge); + $this->assertSame('Taylor', $request->input('user.first_name')); } public function testReplaceMethod() From c1a21ab613e31a4ef4ed5faed4ab3e770689d0a9 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Thu, 1 Aug 2024 18:50:50 -0300 Subject: [PATCH 011/455] [12.x] Fix chunked queries not honoring user-defined limits and offsets (#52093) * Chunks with pre-existing limits * Handles pre-existing offsets on chunks * Tweaks comments * Tweaks comments * Handles existing limits and offsets in the chunkById() method * Favor casting with intval() instead of ternary for offset * Adds getter methods for offset and limit * Remove casting as its being done in the getter methods * StyleCI * Adds getter methods to the eloquent query Builder too * Fix mocked tests * StyleCI * Fix mocked tests * Adds intval to the skip so we cast null to zero * Tweaks tests * Remove test tweaks on a test that was not related * formatting --------- Co-authored-by: Taylor Otwell --- .../Database/Concerns/BuildsQueries.php | 45 +++- src/Illuminate/Database/Eloquent/Builder.php | 20 ++ src/Illuminate/Database/Query/Builder.php | 24 ++ .../Database/DatabaseEloquentBuilderTest.php | 68 +++--- .../DatabaseEloquentIntegrationTest.php | 217 ++++++++++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 51 ++-- 6 files changed, 364 insertions(+), 61 deletions(-) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 4d401125fb0c..9c8c6c91f3f7 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -39,13 +39,21 @@ public function chunk($count, callable $callback) { $this->enforceOrderBy(); + $skip = $this->getOffset(); + $remaining = $this->getLimit(); + $page = 1; do { - // We'll execute the query for the given page and get the results. If there are - // no results we can just break and return from here. When there are results - // we will call the callback with the current chunk of these results here. - $results = $this->forPage($page, $count)->get(); + $offset = (($page - 1) * $count) + intval($skip); + + $limit = is_null($remaining) ? $count : min($count, $remaining); + + if ($limit == 0) { + break; + } + + $results = $this->offset($offset)->limit($limit)->get(); $countResults = $results->count(); @@ -53,9 +61,10 @@ public function chunk($count, callable $callback) break; } - // On each chunk result set, we will pass them to the callback and then let the - // developer take care of everything within the callback, which allows us to - // keep the memory low for spinning through large result sets for working. + if (! is_null($remaining)) { + $remaining = max($remaining - $countResults, 0); + } + if ($callback($results, $page) === false) { return false; } @@ -153,23 +162,33 @@ public function chunkByIdDesc($count, callable $callback, $column = null, $alias public function orderedChunkById($count, callable $callback, $column = null, $alias = null, $descending = false) { $column ??= $this->defaultKeyName(); - $alias ??= $column; - $lastId = null; + $skip = $this->getOffset(); + $remaining = $this->getLimit(); $page = 1; do { $clone = clone $this; + if ($skip && $page > 1) { + $clone->offset(0); + } + + $limit = is_null($remaining) ? $count : min($count, $remaining); + + if ($limit == 0) { + break; + } + // We'll execute the query for the given page and get the results. If there are // no results we can just break and return from here. When there are results // we will call the callback with the current chunk of these results here. if ($descending) { - $results = $clone->forPageBeforeId($count, $lastId, $column)->get(); + $results = $clone->forPageBeforeId($limit, $lastId, $column)->get(); } else { - $results = $clone->forPageAfterId($count, $lastId, $column)->get(); + $results = $clone->forPageAfterId($limit, $lastId, $column)->get(); } $countResults = $results->count(); @@ -178,6 +197,10 @@ public function orderedChunkById($count, callable $callback, $column = null, $al break; } + if (! is_null($remaining)) { + $remaining = max($remaining - $countResults, 0); + } + // On each chunk result set, we will pass them to the callback and then let the // developer take care of everything within the callback, which allows us to // keep the memory low for spinning through large result sets for working. diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 5a4f4e117aa6..662582feee22 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1873,6 +1873,26 @@ public function withoutEagerLoads() return $this->setEagerLoads([]); } + /** + * Get the "limit" value from the query or null if it's not set. + * + * @return mixed + */ + public function getLimit() + { + return $this->query->getLimit(); + } + + /** + * Get the "offset" value from the query or null if it's not set. + * + * @return mixed + */ + public function getOffset() + { + return $this->query->getOffset(); + } + /** * Get the default key name of the table. * diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index e32d8b49e20c..4369f7f7d293 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -4063,6 +4063,30 @@ protected function getUnionBuilders() : collect(); } + /** + * Get the "limit" value for the query or null if it's not set. + * + * @return mixed + */ + public function getLimit() + { + $value = $this->unions ? $this->unionLimit : $this->limit; + + return ! is_null($value) ? (int) $value : null; + } + + /** + * Get the "offset" value for the query or null if it's not set. + * + * @return mixed + */ + public function getOffset() + { + $value = $this->unions ? $this->unionOffset : $this->offset; + + return ! is_null($value) ? (int) $value : null; + } + /** * Get the current query value bindings in a flattened array. * diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 21f560e39a92..76069ab28386 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -369,15 +369,19 @@ public function testValueOrFailMethodWithModelNotFoundThrowsModelNotFoundExcepti public function testChunkWithLastChunkComplete() { - $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,offset,limit,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; $chunk1 = new Collection(['foo1', 'foo2']); $chunk2 = new Collection(['foo3', 'foo4']); $chunk3 = new Collection([]); - $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->once()->with(2, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->once()->with(3, 2)->andReturnSelf(); + + $builder->shouldReceive('getOffset')->once()->andReturn(null); + $builder->shouldReceive('getLimit')->once()->andReturn(null); + $builder->shouldReceive('offset')->once()->with(0)->andReturnSelf(); + $builder->shouldReceive('offset')->once()->with(2)->andReturnSelf(); + $builder->shouldReceive('offset')->once()->with(4)->andReturnSelf(); + $builder->shouldReceive('limit')->times(3)->with(2)->andReturnSelf(); $builder->shouldReceive('get')->times(3)->andReturn($chunk1, $chunk2, $chunk3); $callbackAssertor = m::mock(stdClass::class); @@ -392,13 +396,16 @@ public function testChunkWithLastChunkComplete() public function testChunkWithLastChunkPartial() { - $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,offset,limit,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; $chunk1 = new Collection(['foo1', 'foo2']); $chunk2 = new Collection(['foo3']); - $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->once()->with(2, 2)->andReturnSelf(); + $builder->shouldReceive('getOffset')->once()->andReturn(null); + $builder->shouldReceive('getLimit')->once()->andReturn(null); + $builder->shouldReceive('offset')->once()->with(0)->andReturnSelf(); + $builder->shouldReceive('offset')->once()->with(2)->andReturnSelf(); + $builder->shouldReceive('limit')->twice()->with(2)->andReturnSelf(); $builder->shouldReceive('get')->times(2)->andReturn($chunk1, $chunk2); $callbackAssertor = m::mock(stdClass::class); @@ -412,13 +419,16 @@ public function testChunkWithLastChunkPartial() public function testChunkCanBeStoppedByReturningFalse() { - $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,offset,limit,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; $chunk1 = new Collection(['foo1', 'foo2']); $chunk2 = new Collection(['foo3']); - $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->never()->with(2, 2); + + $builder->shouldReceive('getOffset')->once()->andReturn(null); + $builder->shouldReceive('getLimit')->once()->andReturn(null); + $builder->shouldReceive('offset')->once()->with(0)->andReturnSelf(); + $builder->shouldReceive('limit')->once()->with(2)->andReturnSelf(); $builder->shouldReceive('get')->times(1)->andReturn($chunk1); $callbackAssertor = m::mock(stdClass::class); @@ -434,29 +444,30 @@ public function testChunkCanBeStoppedByReturningFalse() public function testChunkWithCountZero() { - $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,offset,limit,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; - $chunk = new Collection([]); - $builder->shouldReceive('forPage')->once()->with(1, 0)->andReturnSelf(); - $builder->shouldReceive('get')->times(1)->andReturn($chunk); - - $callbackAssertor = m::mock(stdClass::class); - $callbackAssertor->shouldReceive('doSomething')->never(); + $builder->shouldReceive('getOffset')->once()->andReturn(null); + $builder->shouldReceive('getLimit')->once()->andReturn(null); + $builder->shouldReceive('offset')->never(); + $builder->shouldReceive('limit')->never(); + $builder->shouldReceive('get')->never(); - $builder->chunk(0, function ($results) use ($callbackAssertor) { - $callbackAssertor->doSomething($results); + $builder->chunk(0, function () { + $this->fail('Should not be called.'); }); } public function testChunkPaginatesUsingIdWithLastChunkComplete() { - $builder = m::mock(Builder::class.'[forPageAfterId,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,forPageAfterId,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; $chunk1 = new Collection([(object) ['someIdField' => 1], (object) ['someIdField' => 2]]); $chunk2 = new Collection([(object) ['someIdField' => 10], (object) ['someIdField' => 11]]); $chunk3 = new Collection([]); + $builder->shouldReceive('getOffset')->andReturnNull(); + $builder->shouldReceive('getLimit')->andReturnNull(); $builder->shouldReceive('forPageAfterId')->once()->with(2, 0, 'someIdField')->andReturnSelf(); $builder->shouldReceive('forPageAfterId')->once()->with(2, 2, 'someIdField')->andReturnSelf(); $builder->shouldReceive('forPageAfterId')->once()->with(2, 11, 'someIdField')->andReturnSelf(); @@ -474,11 +485,13 @@ public function testChunkPaginatesUsingIdWithLastChunkComplete() public function testChunkPaginatesUsingIdWithLastChunkPartial() { - $builder = m::mock(Builder::class.'[forPageAfterId,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,forPageAfterId,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; $chunk1 = new Collection([(object) ['someIdField' => 1], (object) ['someIdField' => 2]]); $chunk2 = new Collection([(object) ['someIdField' => 10]]); + $builder->shouldReceive('getOffset')->andReturnNull(); + $builder->shouldReceive('getLimit')->andReturnNull(); $builder->shouldReceive('forPageAfterId')->once()->with(2, 0, 'someIdField')->andReturnSelf(); $builder->shouldReceive('forPageAfterId')->once()->with(2, 2, 'someIdField')->andReturnSelf(); $builder->shouldReceive('get')->times(2)->andReturn($chunk1, $chunk2); @@ -494,18 +507,19 @@ public function testChunkPaginatesUsingIdWithLastChunkPartial() public function testChunkPaginatesUsingIdWithCountZero() { - $builder = m::mock(Builder::class.'[forPageAfterId,get]', [$this->getMockQueryBuilder()]); + $builder = m::mock(Builder::class.'[getOffset,getLimit,forPageAfterId,get]', [$this->getMockQueryBuilder()]); $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; - $chunk = new Collection([]); - $builder->shouldReceive('forPageAfterId')->once()->with(0, 0, 'someIdField')->andReturnSelf(); - $builder->shouldReceive('get')->times(1)->andReturn($chunk); + $builder->shouldReceive('getOffset')->andReturnNull(); + $builder->shouldReceive('getLimit')->andReturnNull(); + $builder->shouldReceive('forPageAfterId')->never(); + $builder->shouldReceive('get')->never(); $callbackAssertor = m::mock(stdClass::class); $callbackAssertor->shouldReceive('doSomething')->never(); - $builder->chunkById(0, function ($results) use ($callbackAssertor) { - $callbackAssertor->doSomething($results); + $builder->chunkById(0, function () { + $this->fail('Should never be called.'); }, 'someIdField'); } diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 3dbb553891c9..38f0f5553e19 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -669,6 +669,223 @@ public function testCreatingModelWithEmptyAttributes() $this->assertFalse($model->wasRecentlyCreated); } + public function testChunk() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->orderBy('id', 'asc')->chunk(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('First', $users[0]->name); + $this->assertSame('Second', $users[1]->name); + } else { + $this->assertCount(1, $users); + $this->assertSame('Third', $users[0]->name); + } + + $chunks++; + }); + + $this->assertEquals(2, $chunks); + } + + public function testChunksWithLimitsWhereLimitIsLessThanTotal() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->orderBy('id', 'asc')->limit(2)->chunk(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('First', $users[0]->name); + $this->assertSame('Second', $users[1]->name); + } else { + $this->fail('Should only have had one page.'); + } + + $chunks++; + }); + + $this->assertEquals(1, $chunks); + } + + public function testChunksWithLimitsWhereLimitIsMoreThanTotal() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->orderBy('id', 'asc')->limit(10)->chunk(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('First', $users[0]->name); + $this->assertSame('Second', $users[1]->name); + } elseif ($page === 2) { + $this->assertCount(1, $users); + $this->assertSame('Third', $users[0]->name); + } else { + $this->fail('Should have had two pages.'); + } + + $chunks++; + }); + + $this->assertEquals(2, $chunks); + } + + public function testChunksWithOffset() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->orderBy('id', 'asc')->offset(1)->chunk(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('Second', $users[0]->name); + $this->assertSame('Third', $users[1]->name); + } else { + $this->fail('Should only have had one page.'); + } + + $chunks++; + }); + + $this->assertEquals(1, $chunks); + } + + public function testChunksWithOffsetWhereMoreThanTotal() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->orderBy('id', 'asc')->offset(3)->chunk(2, function () use (&$chunks) { + $chunks++; + }); + + $this->assertEquals(0, $chunks); + } + + public function testChunksWithLimitsAndOffsets() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + EloquentTestUser::create(['name' => 'Fourth', 'email' => 'fourth@example.com']); + EloquentTestUser::create(['name' => 'Fifth', 'email' => 'fifth@example.com']); + EloquentTestUser::create(['name' => 'Sixth', 'email' => 'sixth@example.com']); + EloquentTestUser::create(['name' => 'Seventh', 'email' => 'seventh@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->orderBy('id', 'asc')->offset(2)->limit(3)->chunk(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('Third', $users[0]->name); + $this->assertSame('Fourth', $users[1]->name); + } elseif ($page == 2) { + $this->assertCount(1, $users); + $this->assertSame('Fifth', $users[0]->name); + } else { + $this->fail('Should only have had two pages.'); + } + + $chunks++; + }); + + $this->assertEquals(2, $chunks); + } + + public function testChunkByIdWithLimits() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->limit(2)->chunkById(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('First', $users[0]->name); + $this->assertSame('Second', $users[1]->name); + } else { + $this->fail('Should only have had one page.'); + } + + $chunks++; + }); + + $this->assertEquals(1, $chunks); + } + + public function testChunkByIdWithOffsets() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->offset(1)->chunkById(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('Second', $users[0]->name); + $this->assertSame('Third', $users[1]->name); + } else { + $this->fail('Should only have had one page.'); + } + + $chunks++; + }); + + $this->assertEquals(1, $chunks); + } + + public function testChunkByIdWithLimitsAndOffsets() + { + EloquentTestUser::create(['name' => 'First', 'email' => 'first@example.com']); + EloquentTestUser::create(['name' => 'Second', 'email' => 'second@example.com']); + EloquentTestUser::create(['name' => 'Third', 'email' => 'third@example.com']); + EloquentTestUser::create(['name' => 'Fourth', 'email' => 'fourth@example.com']); + EloquentTestUser::create(['name' => 'Fifth', 'email' => 'fifth@example.com']); + EloquentTestUser::create(['name' => 'Sixth', 'email' => 'sixth@example.com']); + EloquentTestUser::create(['name' => 'Seventh', 'email' => 'seventh@example.com']); + + $chunks = 0; + + EloquentTestUser::query()->offset(2)->limit(3)->chunkById(2, function (Collection $users, $page) use (&$chunks) { + if ($page == 1) { + $this->assertCount(2, $users); + $this->assertSame('Third', $users[0]->name); + $this->assertSame('Fourth', $users[1]->name); + } elseif ($page == 2) { + $this->assertCount(1, $users); + $this->assertSame('Fifth', $users[0]->name); + } else { + $this->fail('Should only have had two pages.'); + } + + $chunks++; + }); + + $this->assertEquals(2, $chunks); + } + public function testChunkByIdWithNonIncrementingKey() { EloquentTestNonIncrementingSecond::create(['name' => ' First']); diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index c345ffcfb5c8..7296b71b9a6f 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -4721,9 +4721,13 @@ public function testChunkWithLastChunkComplete() $chunk1 = collect(['foo1', 'foo2']); $chunk2 = collect(['foo3', 'foo4']); $chunk3 = collect([]); - $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->once()->with(2, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->once()->with(3, 2)->andReturnSelf(); + + $builder->shouldReceive('getOffset')->once()->andReturnNull(); + $builder->shouldReceive('getLimit')->once()->andReturnNull(); + $builder->shouldReceive('offset')->once()->with(0)->andReturnSelf(); + $builder->shouldReceive('offset')->once()->with(2)->andReturnSelf(); + $builder->shouldReceive('offset')->once()->with(4)->andReturnSelf(); + $builder->shouldReceive('limit')->times(3)->with(2)->andReturnSelf(); $builder->shouldReceive('get')->times(3)->andReturn($chunk1, $chunk2, $chunk3); $callbackAssertor = m::mock(stdClass::class); @@ -4743,8 +4747,12 @@ public function testChunkWithLastChunkPartial() $chunk1 = collect(['foo1', 'foo2']); $chunk2 = collect(['foo3']); - $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->once()->with(2, 2)->andReturnSelf(); + + $builder->shouldReceive('getOffset')->once()->andReturnNull(); + $builder->shouldReceive('getLimit')->once()->andReturnNull(); + $builder->shouldReceive('offset')->once()->with(0)->andReturnSelf(); + $builder->shouldReceive('offset')->once()->with(2)->andReturnSelf(); + $builder->shouldReceive('limit')->twice()->with(2)->andReturnSelf(); $builder->shouldReceive('get')->times(2)->andReturn($chunk1, $chunk2); $callbackAssertor = m::mock(stdClass::class); @@ -4763,8 +4771,10 @@ public function testChunkCanBeStoppedByReturningFalse() $chunk1 = collect(['foo1', 'foo2']); $chunk2 = collect(['foo3']); - $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); - $builder->shouldReceive('forPage')->never()->with(2, 2); + $builder->shouldReceive('getOffset')->once()->andReturnNull(); + $builder->shouldReceive('getLimit')->once()->andReturnNull(); + $builder->shouldReceive('offset')->once()->with(0)->andReturnSelf(); + $builder->shouldReceive('limit')->once()->with(2)->andReturnSelf(); $builder->shouldReceive('get')->times(1)->andReturn($chunk1); $callbackAssertor = m::mock(stdClass::class); @@ -4783,15 +4793,14 @@ public function testChunkWithCountZero() $builder = $this->getMockQueryBuilder(); $builder->orders[] = ['column' => 'foobar', 'direction' => 'asc']; - $chunk = collect([]); - $builder->shouldReceive('forPage')->once()->with(1, 0)->andReturnSelf(); - $builder->shouldReceive('get')->times(1)->andReturn($chunk); - - $callbackAssertor = m::mock(stdClass::class); - $callbackAssertor->shouldReceive('doSomething')->never(); + $builder->shouldReceive('getOffset')->once()->andReturnNull(); + $builder->shouldReceive('getLimit')->once()->andReturnNull(); + $builder->shouldReceive('offset')->never(); + $builder->shouldReceive('limit')->never(); + $builder->shouldReceive('get')->never(); - $builder->chunk(0, function ($results) use ($callbackAssertor) { - $callbackAssertor->doSomething($results); + $builder->chunk(0, function () { + $this->fail('Should never be called.'); }); } @@ -4866,15 +4875,11 @@ public function testChunkPaginatesUsingIdWithCountZero() $builder = $this->getMockQueryBuilder(); $builder->orders[] = ['column' => 'foobar', 'direction' => 'asc']; - $chunk = collect([]); - $builder->shouldReceive('forPageAfterId')->once()->with(0, 0, 'someIdField')->andReturnSelf(); - $builder->shouldReceive('get')->times(1)->andReturn($chunk); - - $callbackAssertor = m::mock(stdClass::class); - $callbackAssertor->shouldReceive('doSomething')->never(); + $builder->shouldReceive('forPageAfterId')->never(); + $builder->shouldReceive('get')->never(); - $builder->chunkById(0, function ($results) use ($callbackAssertor) { - $callbackAssertor->doSomething($results); + $builder->chunkById(0, function () { + $this->fail('Should never be called.'); }, 'someIdField'); } From 87f9dd5792a111c09f8cd916782aa95b39efce09 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 5 Aug 2024 15:24:50 +0100 Subject: [PATCH 012/455] [12.x] Replace md5 with much faster xxhash (#52301) * Replace md5 with much faster xxhash * Update CacheTest.php * Update RateLimited.php * Update ThrottleRequests.php --- src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- src/Illuminate/Http/Middleware/SetCacheHeaders.php | 2 +- .../Queue/Middleware/ThrottlesExceptions.php | 2 +- src/Illuminate/Support/Onceable.php | 2 +- src/Illuminate/View/Compilers/BladeCompiler.php | 2 +- tests/Http/Middleware/CacheTest.php | 4 ++-- tests/View/Blade/BladeComponentTagCompilerTest.php | 12 ++++++------ 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 057d7af429d6..0d5658be6ed9 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -417,7 +417,7 @@ protected function shouldntReport(Throwable $e) } return ! $this->container->make(RateLimiter::class)->attempt( - with($throttle->key ?: 'illuminate:foundation:exceptions:'.$e::class, fn ($key) => $this->hashThrottleKeys ? md5($key) : $key), + with($throttle->key ?: 'illuminate:foundation:exceptions:'.$e::class, fn ($key) => $this->hashThrottleKeys ? hash('xxh128', $key) : $key), $throttle->maxAttempts, fn () => true, $throttle->decaySeconds diff --git a/src/Illuminate/Http/Middleware/SetCacheHeaders.php b/src/Illuminate/Http/Middleware/SetCacheHeaders.php index ae40ba0d98c5..05b11f782ef4 100644 --- a/src/Illuminate/Http/Middleware/SetCacheHeaders.php +++ b/src/Illuminate/Http/Middleware/SetCacheHeaders.php @@ -62,7 +62,7 @@ public function handle($request, Closure $next, $options = []) } if (isset($options['etag']) && $options['etag'] === true) { - $options['etag'] = $response->getEtag() ?? md5($response->getContent()); + $options['etag'] = $response->getEtag() ?? hash('xxh128', $response->getContent()); } if (isset($options['last_modified'])) { diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index 83d789616649..0b6baf05b645 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -171,7 +171,7 @@ protected function getKey($job) return $this->prefix.$job->job->uuid(); } - return $this->prefix.md5(get_class($job)); + return $this->prefix.hash('xxh128', get_class($job)); } /** diff --git a/src/Illuminate/Support/Onceable.php b/src/Illuminate/Support/Onceable.php index 169a2b71470f..2d1ab8a43be9 100644 --- a/src/Illuminate/Support/Onceable.php +++ b/src/Illuminate/Support/Onceable.php @@ -66,7 +66,7 @@ protected static function hashFromTrace(array $trace, callable $callable) $callable instanceof Closure ? (new ReflectionClosure($callable))->getClosureUsedVariables() : [], ); - return md5(sprintf( + return hash('xxh128', sprintf( '%s@%s%s:%s (%s)', $trace[0]['file'], isset($trace[1]['class']) ? ($trace[1]['class'].'@') : '', diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 7911462ebf32..1107249f88b0 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -810,7 +810,7 @@ public function getClassComponentAliases() */ public function anonymousComponentPath(string $path, ?string $prefix = null) { - $prefixHash = md5($prefix ?: $path); + $prefixHash = hash('xxh128', $prefix ?: $path); $this->anonymousComponentPaths[] = [ 'path' => $path, diff --git a/tests/Http/Middleware/CacheTest.php b/tests/Http/Middleware/CacheTest.php index cf238c39d706..2be61992a8df 100644 --- a/tests/Http/Middleware/CacheTest.php +++ b/tests/Http/Middleware/CacheTest.php @@ -108,7 +108,7 @@ public function testGenerateEtag() return new Response('some content'); }, 'etag;max_age=100;s_maxage=200'); - $this->assertSame('"9893532233caff98cd083a116b013c0b"', $response->getEtag()); + $this->assertSame('"4f1b32bff4356281946800d355007128"', $response->getEtag()); $this->assertSame('max-age=100, public, s-maxage=200', $response->headers->get('Cache-Control')); } @@ -124,7 +124,7 @@ public function testDoesNotOverrideEtag() public function testIsNotModified() { $request = new Request; - $request->headers->set('If-None-Match', '"9893532233caff98cd083a116b013c0b"'); + $request->headers->set('If-None-Match', '"4f1b32bff4356281946800d355007128"'); $response = (new Cache)->handle($request, function () { return new Response('some content'); diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index 38a4a037b21a..89fc9aa92302 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -598,7 +598,7 @@ public function testClasslessComponentsWithAnonymousComponentPath() $app->shouldReceive('getNamespace')->once()->andReturn('App\\'); $factory->shouldReceive('exists')->andReturnUsing(function ($arg) { - return $arg === md5('test-directory').'::panel.index'; + return $arg === hash('xxh128', 'test-directory').'::panel.index'; }); Container::setInstance($container); @@ -606,14 +606,14 @@ public function testClasslessComponentsWithAnonymousComponentPath() $blade = m::mock(BladeCompiler::class)->makePartial(); $blade->shouldReceive('getAnonymousComponentPaths')->once()->andReturn([ - ['path' => 'test-directory', 'prefix' => null, 'prefixHash' => md5('test-directory')], + ['path' => 'test-directory', 'prefix' => null, 'prefixHash' => hash('xxh128', 'test-directory')], ]); $compiler = $this->compiler([], [], $blade); $result = $compiler->compileTags(''); - $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel.index','data' => []]) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".hash('xxh128', 'test-directory')."::panel.index','data' => []]) except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?> @@ -631,7 +631,7 @@ public function testClasslessIndexComponentsWithAnonymousComponentPath() $app->shouldReceive('getNamespace')->once()->andReturn('App\\'); $factory->shouldReceive('exists')->andReturnUsing(function ($arg) { - return $arg === md5('test-directory').'::panel'; + return $arg === hash('xxh128', 'test-directory').'::panel'; }); Container::setInstance($container); @@ -639,14 +639,14 @@ public function testClasslessIndexComponentsWithAnonymousComponentPath() $blade = m::mock(BladeCompiler::class)->makePartial(); $blade->shouldReceive('getAnonymousComponentPaths')->once()->andReturn([ - ['path' => 'test-directory', 'prefix' => null, 'prefixHash' => md5('test-directory')], + ['path' => 'test-directory', 'prefix' => null, 'prefixHash' => hash('xxh128', 'test-directory')], ]); $compiler = $this->compiler([], [], $blade); $result = $compiler->compileTags(''); - $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel','data' => []]) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".hash('xxh128', 'test-directory')."::panel','data' => []]) except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?> From c50ee3031dafbae6b2d606a0c57faa3663e6b607 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Fri, 16 Aug 2024 20:32:47 +0200 Subject: [PATCH 013/455] Switch models to UUID v7 (#52433) --- src/Illuminate/Database/Eloquent/Concerns/HasUuids.php | 2 +- .../Concerns/{HasVersion7Uuids.php => HasVersion4Uuids.php} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/Illuminate/Database/Eloquent/Concerns/{HasVersion7Uuids.php => HasVersion4Uuids.php} (62%) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasUuids.php b/src/Illuminate/Database/Eloquent/Concerns/HasUuids.php index 55d1acfe770e..0755befdc3e1 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasUuids.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasUuids.php @@ -34,7 +34,7 @@ public function uniqueIds() */ public function newUniqueId() { - return (string) Str::orderedUuid(); + return (string) Str::uuid7(); } /** diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasVersion7Uuids.php b/src/Illuminate/Database/Eloquent/Concerns/HasVersion4Uuids.php similarity index 62% rename from src/Illuminate/Database/Eloquent/Concerns/HasVersion7Uuids.php rename to src/Illuminate/Database/Eloquent/Concerns/HasVersion4Uuids.php index 455bf74aa576..eac53c67ba8d 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasVersion7Uuids.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasVersion4Uuids.php @@ -4,17 +4,17 @@ use Illuminate\Support\Str; -trait HasVersion7Uuids +trait HasVersion4Uuids { use HasUuids; /** - * Generate a new UUID (version 7) for the model. + * Generate a new UUID (version 4) for the model. * * @return string */ public function newUniqueId() { - return (string) Str::uuid7(); + return (string) Str::orderedUuid(); } } From f29df4740d724f1c36385c9989569e3feb9422df Mon Sep 17 00:00:00 2001 From: Caleb White Date: Wed, 12 Jun 2024 23:07:20 -0500 Subject: [PATCH 014/455] feat: use database default datetime precision --- src/Illuminate/Database/Schema/Blueprint.php | 116 ++-- src/Illuminate/Database/Schema/Builder.php | 25 +- .../DatabaseMariaDbSchemaGrammarTest.php | 647 +++++++++--------- .../DatabaseMySqlSchemaGrammarTest.php | 647 +++++++++--------- .../DatabasePostgresSchemaGrammarTest.php | 633 +++++++---------- .../DatabaseSQLiteSchemaGrammarTest.php | 397 +++++------ .../Database/DatabaseSchemaBlueprintTest.php | 529 +++++++------- .../DatabaseSqlServerSchemaGrammarTest.php | 371 +++++----- .../Database/DatabaseSchemaBlueprintTest.php | 250 +++---- .../Database/SchemaBuilderTest.php | 23 +- .../Database/TimestampTypeTest.php | 6 +- 11 files changed, 1749 insertions(+), 1895 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 3db52937dc23..d957a5e630cb 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -16,6 +16,16 @@ class Blueprint { use Macroable; + /** + * The database connection instance. + */ + protected Connection $connection; + + /** + * The schema grammar instance. + */ + protected Grammar $grammar; + /** * The table the blueprint describes. * @@ -94,8 +104,10 @@ class Blueprint * @param string $prefix * @return void */ - public function __construct($table, ?Closure $callback = null, $prefix = '') + public function __construct(Connection $connection, $table, ?Closure $callback = null, $prefix = '') { + $this->connection = $connection; + $this->grammar = $connection->getSchemaGrammar(); $this->table = $table; $this->prefix = $prefix; @@ -107,34 +119,30 @@ public function __construct($table, ?Closure $callback = null, $prefix = '') /** * Execute the blueprint against the database. * - * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ - public function build(Connection $connection, Grammar $grammar) + public function build() { - foreach ($this->toSql($connection, $grammar) as $statement) { - $connection->statement($statement); + foreach ($this->toSql() as $statement) { + $this->connection->statement($statement); } } /** * Get the raw SQL statements for the blueprint. * - * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return array */ - public function toSql(Connection $connection, Grammar $grammar) + public function toSql() { - $this->addImpliedCommands($connection, $grammar); + $this->addImpliedCommands(); $statements = []; // Each type of command has a corresponding compiler function on the schema // grammar which is used to build the necessary SQL statements to build // the blueprint element, so we'll just call that compilers function. - $this->ensureCommandsAreValid($connection); + $this->ensureCommandsAreValid(); foreach ($this->commands as $command) { if ($command->shouldBeSkipped) { @@ -143,12 +151,12 @@ public function toSql(Connection $connection, Grammar $grammar) $method = 'compile'.ucfirst($command->name); - if (method_exists($grammar, $method) || $grammar::hasMacro($method)) { + if (method_exists($this->grammar, $method) || $this->grammar::hasMacro($method)) { if ($this->hasState()) { $this->state->update($command); } - if (! is_null($sql = $grammar->$method($this, $command, $connection))) { + if (! is_null($sql = $this->grammar->$method($this, $command, $this->connection))) { $statements = array_merge($statements, (array) $sql); } } @@ -160,12 +168,11 @@ public function toSql(Connection $connection, Grammar $grammar) /** * Ensure the commands on the blueprint are valid for the connection type. * - * @param \Illuminate\Database\Connection $connection * @return void * * @throws \BadMethodCallException */ - protected function ensureCommandsAreValid(Connection $connection) + protected function ensureCommandsAreValid() { // } @@ -188,15 +195,12 @@ protected function commandsNamed(array $names) /** * Add the commands that are implied by the blueprint's state. * - * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ - protected function addImpliedCommands(Connection $connection, Grammar $grammar) + protected function addImpliedCommands() { - $this->addFluentIndexes($connection, $grammar); - - $this->addFluentCommands($connection, $grammar); + $this->addFluentIndexes(); + $this->addFluentCommands(); if (! $this->creating()) { $this->commands = array_map( @@ -206,25 +210,23 @@ protected function addImpliedCommands(Connection $connection, Grammar $grammar) $this->commands ); - $this->addAlterCommands($connection, $grammar); + $this->addAlterCommands(); } } /** * Add the index commands fluently specified on columns. * - * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ - protected function addFluentIndexes(Connection $connection, Grammar $grammar) + protected function addFluentIndexes() { foreach ($this->columns as $column) { foreach (['primary', 'unique', 'index', 'fulltext', 'fullText', 'spatialIndex'] as $index) { // If the column is supposed to be changed to an auto increment column and // the specified index is primary, there is no need to add a command on // MySQL, as it will be handled during the column definition instead. - if ($index === 'primary' && $column->autoIncrement && $column->change && $grammar instanceof MySqlGrammar) { + if ($index === 'primary' && $column->autoIncrement && $column->change && $this->grammar instanceof MySqlGrammar) { continue 2; } @@ -264,14 +266,12 @@ protected function addFluentIndexes(Connection $connection, Grammar $grammar) /** * Add the fluent commands specified on any columns. * - * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ - public function addFluentCommands(Connection $connection, Grammar $grammar) + public function addFluentCommands() { foreach ($this->columns as $column) { - foreach ($grammar->getFluentCommands() as $commandName) { + foreach ($this->grammar->getFluentCommands() as $commandName) { $this->addCommand($commandName, compact('column')); } } @@ -280,17 +280,15 @@ public function addFluentCommands(Connection $connection, Grammar $grammar) /** * Add the alter commands if whenever needed. * - * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ - public function addAlterCommands(Connection $connection, Grammar $grammar) + public function addAlterCommands() { - if (! $grammar instanceof SQLiteGrammar) { + if (! $this->grammar instanceof SQLiteGrammar) { return; } - $alterCommands = $grammar->getAlterCommands($connection); + $alterCommands = $this->grammar->getAlterCommands($this->connection); [$commands, $lastCommandWasAlter, $hasAlterCommand] = [ [], false, false, @@ -313,7 +311,7 @@ public function addAlterCommands(Connection $connection, Grammar $grammar) } if ($hasAlterCommand) { - $this->state = new BlueprintState($this, $connection, $grammar); + $this->state = new BlueprintState($this, $this->connection, $this->grammar); } $this->commands = $commands; @@ -1162,8 +1160,10 @@ public function date($column) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function dateTime($column, $precision = 0) + public function dateTime($column, $precision = null) { + $precision ??= $this->defaultTimePrecision(); + return $this->addColumn('dateTime', $column, compact('precision')); } @@ -1174,8 +1174,10 @@ public function dateTime($column, $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function dateTimeTz($column, $precision = 0) + public function dateTimeTz($column, $precision = null) { + $precision ??= $this->defaultTimePrecision(); + return $this->addColumn('dateTimeTz', $column, compact('precision')); } @@ -1186,8 +1188,10 @@ public function dateTimeTz($column, $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function time($column, $precision = 0) + public function time($column, $precision = null) { + $precision ??= $this->defaultTimePrecision(); + return $this->addColumn('time', $column, compact('precision')); } @@ -1198,8 +1202,10 @@ public function time($column, $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function timeTz($column, $precision = 0) + public function timeTz($column, $precision = null) { + $precision ??= $this->defaultTimePrecision(); + return $this->addColumn('timeTz', $column, compact('precision')); } @@ -1210,8 +1216,10 @@ public function timeTz($column, $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function timestamp($column, $precision = 0) + public function timestamp($column, $precision = null) { + $precision ??= $this->defaultTimePrecision(); + return $this->addColumn('timestamp', $column, compact('precision')); } @@ -1222,8 +1230,10 @@ public function timestamp($column, $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function timestampTz($column, $precision = 0) + public function timestampTz($column, $precision = null) { + $precision ??= $this->defaultTimePrecision(); + return $this->addColumn('timestampTz', $column, compact('precision')); } @@ -1233,7 +1243,7 @@ public function timestampTz($column, $precision = 0) * @param int|null $precision * @return void */ - public function timestamps($precision = 0) + public function timestamps($precision = null) { $this->timestamp('created_at', $precision)->nullable(); @@ -1248,7 +1258,7 @@ public function timestamps($precision = 0) * @param int|null $precision * @return void */ - public function nullableTimestamps($precision = 0) + public function nullableTimestamps($precision = null) { $this->timestamps($precision); } @@ -1259,7 +1269,7 @@ public function nullableTimestamps($precision = 0) * @param int|null $precision * @return void */ - public function timestampsTz($precision = 0) + public function timestampsTz($precision = null) { $this->timestampTz('created_at', $precision)->nullable(); @@ -1272,7 +1282,7 @@ public function timestampsTz($precision = 0) * @param int|null $precision * @return void */ - public function datetimes($precision = 0) + public function datetimes($precision = null) { $this->datetime('created_at', $precision)->nullable(); @@ -1286,7 +1296,7 @@ public function datetimes($precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function softDeletes($column = 'deleted_at', $precision = 0) + public function softDeletes($column = 'deleted_at', $precision = null) { return $this->timestamp($column, $precision)->nullable(); } @@ -1298,7 +1308,7 @@ public function softDeletes($column = 'deleted_at', $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function softDeletesTz($column = 'deleted_at', $precision = 0) + public function softDeletesTz($column = 'deleted_at', $precision = null) { return $this->timestampTz($column, $precision)->nullable(); } @@ -1310,7 +1320,7 @@ public function softDeletesTz($column = 'deleted_at', $precision = 0) * @param int|null $precision * @return \Illuminate\Database\Schema\ColumnDefinition */ - public function softDeletesDatetime($column = 'deleted_at', $precision = 0) + public function softDeletesDatetime($column = 'deleted_at', $precision = null) { return $this->datetime($column, $precision)->nullable(); } @@ -1853,4 +1863,12 @@ public function getChangedColumns() return (bool) $column->change; }); } + + /** + * Get the default time precision. + */ + protected function defaultTimePrecision(): ?int + { + return $this->connection->getSchemaBuilder()::$defaultTimePrecision; + } } diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 7b899c0a1c7c..311affdd3e59 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -41,6 +41,11 @@ class Builder */ public static $defaultStringLength = 255; + /** + * The default time precision for migrations. + */ + public static ?int $defaultTimePrecision = 0; + /** * The default relationship morph key type. * @@ -71,6 +76,14 @@ public static function defaultStringLength($length) static::$defaultStringLength = $length; } + /** + * Set the default time precision for migrations. + */ + public static function defaultTimePrecision(?int $precision): void + { + static::$defaultTimePrecision = $precision; + } + /** * Set the default morph key type for migrations. * @@ -561,7 +574,7 @@ public function withoutForeignKeyConstraints(Closure $callback) */ protected function build(Blueprint $blueprint) { - $blueprint->build($this->connection, $this->grammar); + $blueprint->build(); } /** @@ -573,15 +586,15 @@ protected function build(Blueprint $blueprint) */ protected function createBlueprint($table, ?Closure $callback = null) { - $prefix = $this->connection->getConfig('prefix_indexes') - ? $this->connection->getConfig('prefix') - : ''; + $connection = $this->connection; + + $prefix = $connection->getConfig('prefix_indexes') ? $connection->getConfig('prefix') : ''; if (isset($this->resolver)) { - return call_user_func($this->resolver, $table, $callback, $prefix); + return call_user_func($this->resolver, $connection, $table, $callback, $prefix); } - return Container::getInstance()->make(Blueprint::class, compact('table', 'callback', 'prefix')); + return Container::getInstance()->make(Blueprint::class, compact('connection', 'table', 'callback', 'prefix')); } /** diff --git a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php index 85d0de26f311..53a573e33b8d 100755 --- a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php +++ b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\ForeignIdColumnDefinition; use Illuminate\Database\Schema\Grammars\MariaDbGrammar; +use Illuminate\Database\Schema\MariaDbBuilder; use Illuminate\Tests\Database\Fixtures\Enums\Foo; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -20,29 +21,29 @@ protected function tearDown(): void public function testBasicCreateTable() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email'); - $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); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); - $blueprint = new Blueprint('users'); - $blueprint->increments('id'); - $blueprint->string('email'); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ @@ -50,14 +51,14 @@ public function testBasicCreateTable() 'alter table `users` add `email` varchar(255) not null', ], $statements); - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->uuid('id')->primary(); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->uuid('id')->primary(); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table `users` (`id` uuid not null, primary key (`id`))', $statements[0]); @@ -65,17 +66,17 @@ public function testBasicCreateTable() public function testAutoIncrementStartingValue() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id')->startingValue(1000); - $blueprint->string('email'); - $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); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id')->startingValue(1000); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); @@ -84,10 +85,10 @@ public function testAutoIncrementStartingValue() public function testAddColumnsWithMultipleAutoIncrementStartingValue() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id()->from(100); $blueprint->string('name')->from(200); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertEquals([ 'alter table `users` add `id` bigint unsigned not null auto_increment primary key', @@ -98,32 +99,32 @@ public function testAddColumnsWithMultipleAutoIncrementStartingValue() public function testEngineCreateTable() { - $blueprint = new Blueprint('users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); + $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); $blueprint->engine('InnoDB'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); - $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email'); - $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('InnoDB'); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); @@ -131,32 +132,32 @@ public function testEngineCreateTable() public function testCharsetCollationCreateTable() { - $blueprint = new Blueprint('users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); $blueprint->charset('utf8mb4'); $blueprint->collation('utf8mb4_unicode_ci'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'", $statements[0]); - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email')->charset('utf8mb4')->collation('utf8mb4_unicode_ci'); - $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); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email')->charset('utf8mb4')->collation('utf8mb4_unicode_ci'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) character set utf8mb4 collate 'utf8mb4_unicode_ci' not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); @@ -164,17 +165,18 @@ public function testCharsetCollationCreateTable() public function testBasicCreateTableWithPrefix() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email'); $grammar = $this->getGrammar(); $grammar->setTablePrefix('prefix_'); - $conn = $this->getConnection(); + $conn = $this->getConnection($grammar); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $grammar); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table `prefix_users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); @@ -182,16 +184,16 @@ public function testBasicCreateTableWithPrefix() public function testCreateTemporaryTable() { - $blueprint = new Blueprint('users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->temporary(); $blueprint->increments('id'); $blueprint->string('email'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create temporary table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); @@ -199,9 +201,9 @@ public function testCreateTemporaryTable() public function testDropTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->drop(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table `users`', $statements[0]); @@ -209,9 +211,9 @@ public function testDropTable() public function testDropTableIfExists() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIfExists(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table if exists `users`', $statements[0]); @@ -219,23 +221,23 @@ public function testDropTableIfExists() public function testDropColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `foo`', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn(['foo', 'bar']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `foo`, drop `bar`', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `foo`, drop `bar`', $statements[0]); @@ -243,9 +245,9 @@ public function testDropColumn() public function testDropPrimary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropPrimary(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop primary key', $statements[0]); @@ -253,9 +255,9 @@ public function testDropPrimary() public function testDropUnique() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropUnique('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop index `foo`', $statements[0]); @@ -263,9 +265,9 @@ public function testDropUnique() public function testDropIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIndex('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop index `foo`', $statements[0]); @@ -273,9 +275,9 @@ public function testDropIndex() public function testDropSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->dropSpatialIndex(['coordinates']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` drop index `geo_coordinates_spatialindex`', $statements[0]); @@ -283,9 +285,9 @@ public function testDropSpatialIndex() public function testDropForeign() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropForeign('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop foreign key `foo`', $statements[0]); @@ -293,9 +295,9 @@ public function testDropForeign() public function testDropTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `created_at`, drop `updated_at`', $statements[0]); @@ -303,9 +305,9 @@ public function testDropTimestamps() public function testDropTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `created_at`, drop `updated_at`', $statements[0]); @@ -313,9 +315,9 @@ public function testDropTimestampsTz() public function testDropMorphs() { - $blueprint = new Blueprint('photos'); + $blueprint = new Blueprint($this->getConnection(), 'photos'); $blueprint->dropMorphs('imageable'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table `photos` drop index `photos_imageable_type_imageable_id_index`', $statements[0]); @@ -324,9 +326,9 @@ public function testDropMorphs() public function testRenameTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rename('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('rename table `users` to `foo`', $statements[0]); @@ -334,9 +336,9 @@ public function testRenameTable() public function testRenameIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->renameIndex('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` rename index `foo` to `bar`', $statements[0]); @@ -344,9 +346,9 @@ public function testRenameIndex() public function testAddingPrimaryKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->primary('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add primary key (`foo`)', $statements[0]); @@ -354,9 +356,9 @@ public function testAddingPrimaryKey() public function testAddingPrimaryKeyWithAlgorithm() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->primary('foo', 'bar', 'hash'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add primary key using hash(`foo`)', $statements[0]); @@ -364,9 +366,9 @@ public function testAddingPrimaryKeyWithAlgorithm() public function testAddingUniqueKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->unique('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add unique `bar`(`foo`)', $statements[0]); @@ -374,9 +376,9 @@ public function testAddingUniqueKey() public function testAddingIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add index `baz`(`foo`, `bar`)', $statements[0]); @@ -384,9 +386,9 @@ public function testAddingIndex() public function testAddingIndexWithAlgorithm() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz', 'hash'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add index `baz` using hash(`foo`, `bar`)', $statements[0]); @@ -394,9 +396,9 @@ public function testAddingIndexWithAlgorithm() public function testAddingFulltextIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->fulltext('body'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add fulltext `users_body_fulltext`(`body`)', $statements[0]); @@ -404,9 +406,9 @@ public function testAddingFulltextIndex() public function testAddingSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->spatialIndex('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add spatial index `geo_coordinates_spatialindex`(`coordinates`)', $statements[0]); @@ -414,9 +416,9 @@ public function testAddingSpatialIndex() public function testAddingFluentSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point')->spatialIndex(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table `geo` add spatial index `geo_coordinates_spatialindex`(`coordinates`)', $statements[1]); @@ -424,9 +426,9 @@ public function testAddingFluentSpatialIndex() public function testAddingRawIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rawIndex('(function(column))', 'raw_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add index `raw_index`((function(column)))', $statements[0]); @@ -434,23 +436,23 @@ public function testAddingRawIndex() public function testAddingForeignKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('foo_id')->references('id')->on('orders'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add constraint `users_foo_id_foreign` foreign key (`foo_id`) references `orders` (`id`)', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('foo_id')->references('id')->on('orders')->cascadeOnDelete(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add constraint `users_foo_id_foreign` foreign key (`foo_id`) references `orders` (`id`) on delete cascade', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('foo_id')->references('id')->on('orders')->cascadeOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add constraint `users_foo_id_foreign` foreign key (`foo_id`) references `orders` (`id`) on update cascade', $statements[0]); @@ -458,9 +460,9 @@ public function testAddingForeignKey() public function testAddingIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); @@ -468,9 +470,9 @@ public function testAddingIncrementingID() public function testAddingSmallIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` smallint unsigned not null auto_increment primary key', $statements[0]); @@ -478,16 +480,16 @@ public function testAddingSmallIncrementingID() public function testAddingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` bigint unsigned not null auto_increment primary key', $statements[0]); @@ -495,14 +497,14 @@ public function testAddingID() public function testAddingForeignID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignId = $blueprint->foreignId('foo'); $blueprint->foreignId('company_id')->constrained(); $blueprint->foreignId('laravel_idea_id')->constrained(); $blueprint->foreignId('team_id')->references('id')->on('teams'); $blueprint->foreignId('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignId); $this->assertSame([ @@ -520,9 +522,9 @@ public function testAddingForeignID() public function testAddingForeignIdSpecifyingIndexNameInConstraint() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreignId('company_id')->constrained(indexName: 'my_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertSame([ 'alter table `users` add `company_id` bigint unsigned not null', 'alter table `users` add constraint `my_index` foreign key (`company_id`) references `companies` (`id`)', @@ -531,9 +533,9 @@ public function testAddingForeignIdSpecifyingIndexNameInConstraint() public function testAddingBigIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); @@ -541,9 +543,9 @@ public function testAddingBigIncrementingID() public function testAddingColumnInTableFirst() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('name')->first(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `name` varchar(255) not null first', $statements[0]); @@ -551,9 +553,9 @@ public function testAddingColumnInTableFirst() public function testAddingColumnAfterAnotherColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('name')->after('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `name` varchar(255) not null after `foo`', $statements[0]); @@ -561,13 +563,13 @@ public function testAddingColumnAfterAnotherColumn() public function testAddingMultipleColumnsAfterAnotherColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->after('foo', function ($blueprint) { $blueprint->string('one'); $blueprint->string('two'); }); $blueprint->string('three'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ 'alter table `users` add `one` varchar(255) not null after `foo`', @@ -578,11 +580,11 @@ public function testAddingMultipleColumnsAfterAnotherColumn() public function testAddingGeneratedColumn() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs('price - 5'); $blueprint->integer('discounted_stored')->storedAs('price - 5'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -591,11 +593,11 @@ public function testAddingGeneratedColumn() 'alter table `products` add `discounted_stored` int as (price - 5) stored', ], $statements); - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs('price - 5')->nullable(false); $blueprint->integer('discounted_stored')->storedAs('price - 5')->nullable(false); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -607,11 +609,11 @@ public function testAddingGeneratedColumn() public function testAddingGeneratedColumnWithCharset() { - $blueprint = new Blueprint('links'); + $blueprint = new Blueprint($this->getConnection(), 'links'); $blueprint->string('url', 2083)->charset('ascii'); $blueprint->string('url_hash_virtual', 64)->virtualAs('sha2(url, 256)')->charset('ascii'); $blueprint->string('url_hash_stored', 64)->storedAs('sha2(url, 256)')->charset('ascii'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -623,11 +625,11 @@ public function testAddingGeneratedColumnWithCharset() public function testAddingGeneratedColumnByExpression() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs(new Expression('price - 5')); $blueprint->integer('discounted_stored')->storedAs(new Expression('price - 5')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -639,9 +641,9 @@ public function testAddingGeneratedColumnByExpression() public function testAddingInvisibleColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('secret', 64)->nullable(false)->invisible(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `secret` varchar(64) not null invisible', $statements[0]); @@ -649,37 +651,37 @@ public function testAddingInvisibleColumn() public function testAddingString() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(255) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default('bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) null default \'bar\'', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default(new Expression('CURRENT TIMESTAMP')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) null default CURRENT TIMESTAMP', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default(Foo::BAR); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) null default \'bar\'', $statements[0]); @@ -687,9 +689,9 @@ public function testAddingString() public function testAddingText() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->text('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` text not null', $statements[0]); @@ -697,16 +699,16 @@ public function testAddingText() public function testAddingBigInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` bigint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` bigint not null auto_increment primary key', $statements[0]); @@ -714,16 +716,16 @@ public function testAddingBigInteger() public function testAddingInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` int not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` int not null auto_increment primary key', $statements[0]); @@ -731,9 +733,9 @@ public function testAddingInteger() public function testAddingIncrementsWithStartingValues() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id()->startingValue(1000); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); @@ -742,16 +744,16 @@ public function testAddingIncrementsWithStartingValues() public function testAddingMediumInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` mediumint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` mediumint not null auto_increment primary key', $statements[0]); @@ -759,16 +761,16 @@ public function testAddingMediumInteger() public function testAddingSmallInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` smallint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` smallint not null auto_increment primary key', $statements[0]); @@ -776,16 +778,16 @@ public function testAddingSmallInteger() public function testAddingTinyInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` tinyint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` tinyint not null auto_increment primary key', $statements[0]); @@ -793,9 +795,9 @@ public function testAddingTinyInteger() public function testAddingFloat() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->float('foo', 5); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` float(5) not null', $statements[0]); @@ -803,9 +805,9 @@ public function testAddingFloat() public function testAddingDouble() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->double('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` double not null', $statements[0]); @@ -813,9 +815,9 @@ public function testAddingDouble() public function testAddingDecimal() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->decimal('foo', 5, 2); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` decimal(5, 2) not null', $statements[0]); @@ -823,9 +825,9 @@ public function testAddingDecimal() public function testAddingBoolean() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->boolean('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` tinyint(1) not null', $statements[0]); @@ -833,9 +835,9 @@ public function testAddingBoolean() public function testAddingEnum() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->enum('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `role` enum(\'member\', \'admin\') not null', $statements[0]); @@ -843,9 +845,9 @@ public function testAddingEnum() public function testAddingSet() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->set('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `role` set(\'member\', \'admin\') not null', $statements[0]); @@ -853,9 +855,9 @@ public function testAddingSet() public function testAddingJson() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->json('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` json not null', $statements[0]); @@ -863,9 +865,9 @@ public function testAddingJson() public function testAddingJsonb() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->jsonb('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` json not null', $statements[0]); @@ -873,9 +875,9 @@ public function testAddingJsonb() public function testAddingDate() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->date('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` date not null', $statements[0]); @@ -883,201 +885,201 @@ public function testAddingDate() public function testAddingYear() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->year('birth_year'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `birth_year` year not null', $statements[0]); } public function testAddingDateTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime(1) not null', $statements[0]); } public function testAddingDateTimeWithDefaultCurrent() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo')->useCurrent(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null default CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithOnUpdateCurrent() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo')->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null on update CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithDefaultCurrentAndOnUpdateCurrent() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo')->useCurrent()->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithDefaultCurrentOnUpdateCurrentAndPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo', 3)->useCurrent()->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime(3) not null default CURRENT_TIMESTAMP(3) on update CURRENT_TIMESTAMP(3)', $statements[0]); } public function testAddingDateTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('foo', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime(1) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null', $statements[0]); } public function testAddingTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time not null', $statements[0]); } public function testAddingTimeWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time(1) not null', $statements[0]); } public function testAddingTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time not null', $statements[0]); } public function testAddingTimeTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time(1) not null', $statements[0]); } public function testAddingTimestamp() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp not null', $statements[0]); } public function testAddingTimestampWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null', $statements[0]); } public function testAddingTimestampWithDefault() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at')->default('2015-07-22 11:43:17'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("alter table `users` add `created_at` timestamp not null default '2015-07-22 11:43:17'", $statements[0]); } public function testAddingTimestampWithDefaultCurrentSpecifyingPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1)->useCurrent(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null default CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampWithOnUpdateCurrentSpecifyingPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1)->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null on update CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampWithDefaultCurrentAndOnUpdateCurrentSpecifyingPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1)->useCurrent()->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null default CURRENT_TIMESTAMP(1) on update CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp not null', $statements[0]); } public function testAddingTimestampTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null', $statements[0]); } public function testAddingTimeStampTzWithDefault() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at')->default('2015-07-22 11:43:17'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("alter table `users` add `created_at` timestamp not null default '2015-07-22 11:43:17'", $statements[0]); } public function testAddingTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table `users` add `created_at` timestamp null', @@ -1087,9 +1089,9 @@ public function testAddingTimestamps() public function testAddingTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table `users` add `created_at` timestamp null', @@ -1099,9 +1101,9 @@ public function testAddingTimestampsTz() public function testAddingRememberToken() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rememberToken(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `remember_token` varchar(100) null', $statements[0]); @@ -1109,9 +1111,9 @@ public function testAddingRememberToken() public function testAddingBinary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->binary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` blob not null', $statements[0]); @@ -1119,9 +1121,9 @@ public function testAddingBinary() public function testAddingUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` uuid not null', $statements[0]); @@ -1129,9 +1131,9 @@ public function testAddingUuid() public function testAddingUuidDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `uuid` uuid not null', $statements[0]); @@ -1139,14 +1141,14 @@ public function testAddingUuidDefaultsColumnName() public function testAddingForeignUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignUuid = $blueprint->foreignUuid('foo'); $blueprint->foreignUuid('company_id')->constrained(); $blueprint->foreignUuid('laravel_idea_id')->constrained(); $blueprint->foreignUuid('team_id')->references('id')->on('teams'); $blueprint->foreignUuid('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignUuid); $this->assertSame([ @@ -1164,9 +1166,9 @@ public function testAddingForeignUuid() public function testAddingIpAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(45) not null', $statements[0]); @@ -1174,9 +1176,9 @@ public function testAddingIpAddress() public function testAddingIpAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `ip_address` varchar(45) not null', $statements[0]); @@ -1184,9 +1186,9 @@ public function testAddingIpAddressDefaultsColumnName() public function testAddingMacAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(17) not null', $statements[0]); @@ -1194,9 +1196,9 @@ public function testAddingMacAddress() public function testAddingMacAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `mac_address` varchar(17) not null', $statements[0]); @@ -1204,9 +1206,9 @@ public function testAddingMacAddressDefaultsColumnName() public function testAddingGeometry() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` geometry not null', $statements[0]); @@ -1214,9 +1216,9 @@ public function testAddingGeometry() public function testAddingGeography() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geography('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` geometry ref_system_id=4326 not null', $statements[0]); @@ -1224,9 +1226,9 @@ public function testAddingGeography() public function testAddingPoint() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` point not null', $statements[0]); @@ -1234,9 +1236,9 @@ public function testAddingPoint() public function testAddingPointWithSrid() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point', 4326); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` point ref_system_id=4326 not null', $statements[0]); @@ -1244,9 +1246,9 @@ public function testAddingPointWithSrid() public function testAddingPointWithSridColumn() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point', 4326)->after('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` point ref_system_id=4326 not null after `id`', $statements[0]); @@ -1254,9 +1256,9 @@ public function testAddingPointWithSridColumn() public function testAddingLineString() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'linestring'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` linestring not null', $statements[0]); @@ -1264,9 +1266,9 @@ public function testAddingLineString() public function testAddingPolygon() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'polygon'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` polygon not null', $statements[0]); @@ -1274,9 +1276,9 @@ public function testAddingPolygon() public function testAddingGeometryCollection() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'geometrycollection'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` geometrycollection not null', $statements[0]); @@ -1284,9 +1286,9 @@ public function testAddingGeometryCollection() public function testAddingMultiPoint() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multipoint'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` multipoint not null', $statements[0]); @@ -1294,9 +1296,9 @@ public function testAddingMultiPoint() public function testAddingMultiLineString() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multilinestring'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` multilinestring not null', $statements[0]); @@ -1304,9 +1306,9 @@ public function testAddingMultiLineString() public function testAddingMultiPolygon() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multipolygon'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` multipolygon not null', $statements[0]); @@ -1314,9 +1316,9 @@ public function testAddingMultiPolygon() public function testAddingComment() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo')->comment("Escape ' when using words like it's"); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("alter table `users` add `foo` varchar(255) not null comment 'Escape \\' when using words like it\\'s'", $statements[0]); @@ -1354,38 +1356,38 @@ public function testCreateTableWithVirtualAsColumn() $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_column'); $blueprint->string('my_other_column')->virtualAs('my_column'); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute->nested'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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]); @@ -1393,14 +1395,14 @@ public function testCreateTableWithVirtualAsColumn() public function testCreateTableWithVirtualAsColumnWhenJsonColumnHasArrayKey() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->string('my_json_column')->virtualAsJson('my_json_column->foo[0][1]'); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->string('my_json_column')->virtualAsJson('my_json_column->foo[0][1]'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`my_json_column` varchar(255) as (json_unquote(json_extract(`my_json_column`, '$.\"foo\"[0][1]'))))", $statements[0]); @@ -1413,38 +1415,38 @@ public function testCreateTableWithStoredAsColumn() $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_column'); $blueprint->string('my_other_column')->storedAs('my_column'); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute->nested'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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]); @@ -1493,13 +1495,26 @@ public function testGrammarsAreMacroable() $this->assertTrue($c); } - protected function getConnection() - { - return m::mock(Connection::class); + protected function getConnection( + ?MariaDbGrammar $grammar = null, + ?MariaDbBuilder $builder = null, + ) { + $grammar ??= $this->getGrammar(); + $builder ??= $this->getBuilder(); + + return m::mock(Connection::class) + ->shouldReceive('getSchemaGrammar')->andReturn($grammar) + ->shouldReceive('getSchemaBuilder')->andReturn($builder) + ->getMock(); } public function getGrammar() { return new MariaDbGrammar; } + + public function getBuilder() + { + return mock(MariaDbBuilder::class); + } } diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index e959b66d8831..ad8ccf13ec13 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\ForeignIdColumnDefinition; use Illuminate\Database\Schema\Grammars\MySqlGrammar; +use Illuminate\Database\Schema\MySqlBuilder; use Illuminate\Tests\Database\Fixtures\Enums\Foo; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -20,29 +21,29 @@ protected function tearDown(): void public function testBasicCreateTable() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email'); - $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); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); - $blueprint = new Blueprint('users'); - $blueprint->increments('id'); - $blueprint->string('email'); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ @@ -50,14 +51,14 @@ public function testBasicCreateTable() 'alter table `users` add `email` varchar(255) not null', ], $statements); - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->uuid('id')->primary(); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->uuid('id')->primary(); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table `users` (`id` char(36) not null, primary key (`id`))', $statements[0]); @@ -65,17 +66,17 @@ public function testBasicCreateTable() public function testAutoIncrementStartingValue() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id')->startingValue(1000); - $blueprint->string('email'); - $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); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id')->startingValue(1000); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); @@ -84,10 +85,10 @@ public function testAutoIncrementStartingValue() public function testAddColumnsWithMultipleAutoIncrementStartingValue() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id()->from(100); $blueprint->string('name')->from(200); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertEquals([ 'alter table `users` add `id` bigint unsigned not null auto_increment primary key', @@ -98,32 +99,32 @@ public function testAddColumnsWithMultipleAutoIncrementStartingValue() public function testEngineCreateTable() { - $blueprint = new Blueprint('users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); + $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); $blueprint->engine('InnoDB'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); - $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email'); - $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('InnoDB'); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); @@ -131,32 +132,32 @@ public function testEngineCreateTable() public function testCharsetCollationCreateTable() { - $blueprint = new Blueprint('users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); $blueprint->charset('utf8mb4'); $blueprint->collation('utf8mb4_unicode_ci'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'", $statements[0]); - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email')->charset('utf8mb4')->collation('utf8mb4_unicode_ci'); - $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); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email')->charset('utf8mb4')->collation('utf8mb4_unicode_ci'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) character set utf8mb4 collate 'utf8mb4_unicode_ci' not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); @@ -164,17 +165,18 @@ public function testCharsetCollationCreateTable() public function testBasicCreateTableWithPrefix() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->increments('id'); - $blueprint->string('email'); $grammar = $this->getGrammar(); $grammar->setTablePrefix('prefix_'); - $conn = $this->getConnection(); + $conn = $this->getConnection($grammar); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $grammar); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->increments('id'); + $blueprint->string('email'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table `prefix_users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); @@ -182,16 +184,16 @@ public function testBasicCreateTableWithPrefix() public function testCreateTemporaryTable() { - $blueprint = new Blueprint('users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->temporary(); $blueprint->increments('id'); $blueprint->string('email'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create temporary table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); @@ -199,9 +201,9 @@ public function testCreateTemporaryTable() public function testDropTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->drop(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table `users`', $statements[0]); @@ -209,9 +211,9 @@ public function testDropTable() public function testDropTableIfExists() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIfExists(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table if exists `users`', $statements[0]); @@ -219,23 +221,23 @@ public function testDropTableIfExists() public function testDropColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `foo`', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn(['foo', 'bar']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `foo`, drop `bar`', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `foo`, drop `bar`', $statements[0]); @@ -243,9 +245,9 @@ public function testDropColumn() public function testDropPrimary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropPrimary(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop primary key', $statements[0]); @@ -253,9 +255,9 @@ public function testDropPrimary() public function testDropUnique() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropUnique('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop index `foo`', $statements[0]); @@ -263,9 +265,9 @@ public function testDropUnique() public function testDropIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIndex('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop index `foo`', $statements[0]); @@ -273,9 +275,9 @@ public function testDropIndex() public function testDropSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->dropSpatialIndex(['coordinates']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` drop index `geo_coordinates_spatialindex`', $statements[0]); @@ -283,9 +285,9 @@ public function testDropSpatialIndex() public function testDropForeign() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropForeign('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop foreign key `foo`', $statements[0]); @@ -293,9 +295,9 @@ public function testDropForeign() public function testDropTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `created_at`, drop `updated_at`', $statements[0]); @@ -303,9 +305,9 @@ public function testDropTimestamps() public function testDropTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` drop `created_at`, drop `updated_at`', $statements[0]); @@ -313,9 +315,9 @@ public function testDropTimestampsTz() public function testDropMorphs() { - $blueprint = new Blueprint('photos'); + $blueprint = new Blueprint($this->getConnection(), 'photos'); $blueprint->dropMorphs('imageable'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table `photos` drop index `photos_imageable_type_imageable_id_index`', $statements[0]); @@ -324,9 +326,9 @@ public function testDropMorphs() public function testRenameTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rename('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('rename table `users` to `foo`', $statements[0]); @@ -334,9 +336,9 @@ public function testRenameTable() public function testRenameIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->renameIndex('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` rename index `foo` to `bar`', $statements[0]); @@ -344,9 +346,9 @@ public function testRenameIndex() public function testAddingPrimaryKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->primary('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add primary key (`foo`)', $statements[0]); @@ -354,9 +356,9 @@ public function testAddingPrimaryKey() public function testAddingPrimaryKeyWithAlgorithm() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->primary('foo', 'bar', 'hash'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add primary key using hash(`foo`)', $statements[0]); @@ -364,9 +366,9 @@ public function testAddingPrimaryKeyWithAlgorithm() public function testAddingUniqueKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->unique('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add unique `bar`(`foo`)', $statements[0]); @@ -374,9 +376,9 @@ public function testAddingUniqueKey() public function testAddingIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add index `baz`(`foo`, `bar`)', $statements[0]); @@ -384,9 +386,9 @@ public function testAddingIndex() public function testAddingIndexWithAlgorithm() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz', 'hash'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add index `baz` using hash(`foo`, `bar`)', $statements[0]); @@ -394,9 +396,9 @@ public function testAddingIndexWithAlgorithm() public function testAddingFulltextIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->fulltext('body'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add fulltext `users_body_fulltext`(`body`)', $statements[0]); @@ -404,9 +406,9 @@ public function testAddingFulltextIndex() public function testAddingSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->spatialIndex('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add spatial index `geo_coordinates_spatialindex`(`coordinates`)', $statements[0]); @@ -414,9 +416,9 @@ public function testAddingSpatialIndex() public function testAddingFluentSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point')->spatialIndex(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table `geo` add spatial index `geo_coordinates_spatialindex`(`coordinates`)', $statements[1]); @@ -424,9 +426,9 @@ public function testAddingFluentSpatialIndex() public function testAddingRawIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rawIndex('(function(column))', 'raw_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add index `raw_index`((function(column)))', $statements[0]); @@ -434,23 +436,23 @@ public function testAddingRawIndex() public function testAddingForeignKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('foo_id')->references('id')->on('orders'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add constraint `users_foo_id_foreign` foreign key (`foo_id`) references `orders` (`id`)', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('foo_id')->references('id')->on('orders')->cascadeOnDelete(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add constraint `users_foo_id_foreign` foreign key (`foo_id`) references `orders` (`id`) on delete cascade', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('foo_id')->references('id')->on('orders')->cascadeOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add constraint `users_foo_id_foreign` foreign key (`foo_id`) references `orders` (`id`) on update cascade', $statements[0]); @@ -458,9 +460,9 @@ public function testAddingForeignKey() public function testAddingIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); @@ -468,9 +470,9 @@ public function testAddingIncrementingID() public function testAddingSmallIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` smallint unsigned not null auto_increment primary key', $statements[0]); @@ -478,16 +480,16 @@ public function testAddingSmallIncrementingID() public function testAddingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` bigint unsigned not null auto_increment primary key', $statements[0]); @@ -495,14 +497,14 @@ public function testAddingID() public function testAddingForeignID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignId = $blueprint->foreignId('foo'); $blueprint->foreignId('company_id')->constrained(); $blueprint->foreignId('laravel_idea_id')->constrained(); $blueprint->foreignId('team_id')->references('id')->on('teams'); $blueprint->foreignId('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignId); $this->assertSame([ @@ -520,9 +522,9 @@ public function testAddingForeignID() public function testAddingForeignIdSpecifyingIndexNameInConstraint() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreignId('company_id')->constrained(indexName: 'my_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertSame([ 'alter table `users` add `company_id` bigint unsigned not null', 'alter table `users` add constraint `my_index` foreign key (`company_id`) references `companies` (`id`)', @@ -531,9 +533,9 @@ public function testAddingForeignIdSpecifyingIndexNameInConstraint() public function testAddingBigIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); @@ -541,9 +543,9 @@ public function testAddingBigIncrementingID() public function testAddingColumnInTableFirst() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('name')->first(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `name` varchar(255) not null first', $statements[0]); @@ -551,9 +553,9 @@ public function testAddingColumnInTableFirst() public function testAddingColumnAfterAnotherColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('name')->after('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `name` varchar(255) not null after `foo`', $statements[0]); @@ -561,13 +563,13 @@ public function testAddingColumnAfterAnotherColumn() public function testAddingMultipleColumnsAfterAnotherColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->after('foo', function ($blueprint) { $blueprint->string('one'); $blueprint->string('two'); }); $blueprint->string('three'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ 'alter table `users` add `one` varchar(255) not null after `foo`', @@ -578,11 +580,11 @@ public function testAddingMultipleColumnsAfterAnotherColumn() public function testAddingGeneratedColumn() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs('price - 5'); $blueprint->integer('discounted_stored')->storedAs('price - 5'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -591,11 +593,11 @@ public function testAddingGeneratedColumn() 'alter table `products` add `discounted_stored` int as (price - 5) stored', ], $statements); - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs('price - 5')->nullable(false); $blueprint->integer('discounted_stored')->storedAs('price - 5')->nullable(false); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -607,11 +609,11 @@ public function testAddingGeneratedColumn() public function testAddingGeneratedColumnWithCharset() { - $blueprint = new Blueprint('links'); + $blueprint = new Blueprint($this->getConnection(), 'links'); $blueprint->string('url', 2083)->charset('ascii'); $blueprint->string('url_hash_virtual', 64)->virtualAs('sha2(url, 256)')->charset('ascii'); $blueprint->string('url_hash_stored', 64)->storedAs('sha2(url, 256)')->charset('ascii'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -623,11 +625,11 @@ public function testAddingGeneratedColumnWithCharset() public function testAddingGeneratedColumnByExpression() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs(new Expression('price - 5')); $blueprint->integer('discounted_stored')->storedAs(new Expression('price - 5')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ @@ -639,9 +641,9 @@ public function testAddingGeneratedColumnByExpression() public function testAddingInvisibleColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('secret', 64)->nullable(false)->invisible(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `secret` varchar(64) not null invisible', $statements[0]); @@ -649,37 +651,37 @@ public function testAddingInvisibleColumn() public function testAddingString() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(255) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default('bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) null default \'bar\'', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default(new Expression('CURRENT TIMESTAMP')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) null default CURRENT TIMESTAMP', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default(Foo::BAR); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(100) null default \'bar\'', $statements[0]); @@ -687,9 +689,9 @@ public function testAddingString() public function testAddingText() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->text('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` text not null', $statements[0]); @@ -697,16 +699,16 @@ public function testAddingText() public function testAddingBigInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` bigint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` bigint not null auto_increment primary key', $statements[0]); @@ -714,16 +716,16 @@ public function testAddingBigInteger() public function testAddingInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` int not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` int not null auto_increment primary key', $statements[0]); @@ -731,9 +733,9 @@ public function testAddingInteger() public function testAddingIncrementsWithStartingValues() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id()->startingValue(1000); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); @@ -742,16 +744,16 @@ public function testAddingIncrementsWithStartingValues() public function testAddingMediumInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` mediumint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` mediumint not null auto_increment primary key', $statements[0]); @@ -759,16 +761,16 @@ public function testAddingMediumInteger() public function testAddingSmallInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` smallint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` smallint not null auto_increment primary key', $statements[0]); @@ -776,16 +778,16 @@ public function testAddingSmallInteger() public function testAddingTinyInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` tinyint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` tinyint not null auto_increment primary key', $statements[0]); @@ -793,9 +795,9 @@ public function testAddingTinyInteger() public function testAddingFloat() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->float('foo', 5); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` float(5) not null', $statements[0]); @@ -803,9 +805,9 @@ public function testAddingFloat() public function testAddingDouble() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->double('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` double not null', $statements[0]); @@ -813,9 +815,9 @@ public function testAddingDouble() public function testAddingDecimal() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->decimal('foo', 5, 2); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` decimal(5, 2) not null', $statements[0]); @@ -823,9 +825,9 @@ public function testAddingDecimal() public function testAddingBoolean() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->boolean('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` tinyint(1) not null', $statements[0]); @@ -833,9 +835,9 @@ public function testAddingBoolean() public function testAddingEnum() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->enum('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `role` enum(\'member\', \'admin\') not null', $statements[0]); @@ -843,9 +845,9 @@ public function testAddingEnum() public function testAddingSet() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->set('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `role` set(\'member\', \'admin\') not null', $statements[0]); @@ -853,9 +855,9 @@ public function testAddingSet() public function testAddingJson() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->json('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` json not null', $statements[0]); @@ -863,9 +865,9 @@ public function testAddingJson() public function testAddingJsonb() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->jsonb('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` json not null', $statements[0]); @@ -873,9 +875,9 @@ public function testAddingJsonb() public function testAddingDate() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->date('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` date not null', $statements[0]); @@ -883,201 +885,201 @@ public function testAddingDate() public function testAddingYear() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->year('birth_year'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `birth_year` year not null', $statements[0]); } public function testAddingDateTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime(1) not null', $statements[0]); } public function testAddingDateTimeWithDefaultCurrent() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo')->useCurrent(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null default CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithOnUpdateCurrent() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo')->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null on update CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithDefaultCurrentAndOnUpdateCurrent() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo')->useCurrent()->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithDefaultCurrentOnUpdateCurrentAndPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('foo', 3)->useCurrent()->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime(3) not null default CURRENT_TIMESTAMP(3) on update CURRENT_TIMESTAMP(3)', $statements[0]); } public function testAddingDateTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('foo', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime(1) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` datetime not null', $statements[0]); } public function testAddingTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time not null', $statements[0]); } public function testAddingTimeWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time(1) not null', $statements[0]); } public function testAddingTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time not null', $statements[0]); } public function testAddingTimeTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` time(1) not null', $statements[0]); } public function testAddingTimestamp() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp not null', $statements[0]); } public function testAddingTimestampWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null', $statements[0]); } public function testAddingTimestampWithDefault() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at')->default('2015-07-22 11:43:17'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("alter table `users` add `created_at` timestamp not null default '2015-07-22 11:43:17'", $statements[0]); } public function testAddingTimestampWithDefaultCurrentSpecifyingPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1)->useCurrent(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null default CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampWithOnUpdateCurrentSpecifyingPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1)->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null on update CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampWithDefaultCurrentAndOnUpdateCurrentSpecifyingPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1)->useCurrent()->useCurrentOnUpdate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null default CURRENT_TIMESTAMP(1) on update CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp not null', $statements[0]); } public function testAddingTimestampTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `created_at` timestamp(1) not null', $statements[0]); } public function testAddingTimeStampTzWithDefault() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at')->default('2015-07-22 11:43:17'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("alter table `users` add `created_at` timestamp not null default '2015-07-22 11:43:17'", $statements[0]); } public function testAddingTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table `users` add `created_at` timestamp null', @@ -1087,9 +1089,9 @@ public function testAddingTimestamps() public function testAddingTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table `users` add `created_at` timestamp null', @@ -1099,9 +1101,9 @@ public function testAddingTimestampsTz() public function testAddingRememberToken() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rememberToken(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `remember_token` varchar(100) null', $statements[0]); @@ -1109,9 +1111,9 @@ public function testAddingRememberToken() public function testAddingBinary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->binary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` blob not null', $statements[0]); @@ -1119,9 +1121,9 @@ public function testAddingBinary() public function testAddingUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` char(36) not null', $statements[0]); @@ -1129,9 +1131,9 @@ public function testAddingUuid() public function testAddingUuidDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `uuid` char(36) not null', $statements[0]); @@ -1139,14 +1141,14 @@ public function testAddingUuidDefaultsColumnName() public function testAddingForeignUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignUuid = $blueprint->foreignUuid('foo'); $blueprint->foreignUuid('company_id')->constrained(); $blueprint->foreignUuid('laravel_idea_id')->constrained(); $blueprint->foreignUuid('team_id')->references('id')->on('teams'); $blueprint->foreignUuid('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignUuid); $this->assertSame([ @@ -1164,9 +1166,9 @@ public function testAddingForeignUuid() public function testAddingIpAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(45) not null', $statements[0]); @@ -1174,9 +1176,9 @@ public function testAddingIpAddress() public function testAddingIpAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `ip_address` varchar(45) not null', $statements[0]); @@ -1184,9 +1186,9 @@ public function testAddingIpAddressDefaultsColumnName() public function testAddingMacAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `foo` varchar(17) not null', $statements[0]); @@ -1194,9 +1196,9 @@ public function testAddingMacAddress() public function testAddingMacAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `users` add `mac_address` varchar(17) not null', $statements[0]); @@ -1204,9 +1206,9 @@ public function testAddingMacAddressDefaultsColumnName() public function testAddingGeometry() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` geometry not null', $statements[0]); @@ -1214,9 +1216,9 @@ public function testAddingGeometry() public function testAddingGeography() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geography('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` geometry srid 4326 not null', $statements[0]); @@ -1224,9 +1226,9 @@ public function testAddingGeography() public function testAddingPoint() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` point not null', $statements[0]); @@ -1234,9 +1236,9 @@ public function testAddingPoint() public function testAddingPointWithSrid() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point', 4326); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` point srid 4326 not null', $statements[0]); @@ -1244,9 +1246,9 @@ public function testAddingPointWithSrid() public function testAddingPointWithSridColumn() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point', 4326)->after('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` point srid 4326 not null after `id`', $statements[0]); @@ -1254,9 +1256,9 @@ public function testAddingPointWithSridColumn() public function testAddingLineString() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'linestring'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` linestring not null', $statements[0]); @@ -1264,9 +1266,9 @@ public function testAddingLineString() public function testAddingPolygon() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'polygon'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` polygon not null', $statements[0]); @@ -1274,9 +1276,9 @@ public function testAddingPolygon() public function testAddingGeometryCollection() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'geometrycollection'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` geometrycollection not null', $statements[0]); @@ -1284,9 +1286,9 @@ public function testAddingGeometryCollection() public function testAddingMultiPoint() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multipoint'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` multipoint not null', $statements[0]); @@ -1294,9 +1296,9 @@ public function testAddingMultiPoint() public function testAddingMultiLineString() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multilinestring'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` multilinestring not null', $statements[0]); @@ -1304,9 +1306,9 @@ public function testAddingMultiLineString() public function testAddingMultiPolygon() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multipolygon'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table `geo` add `coordinates` multipolygon not null', $statements[0]); @@ -1314,9 +1316,9 @@ public function testAddingMultiPolygon() public function testAddingComment() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo')->comment("Escape ' when using words like it's"); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("alter table `users` add `foo` varchar(255) not null comment 'Escape \\' when using words like it\\'s'", $statements[0]); @@ -1354,38 +1356,38 @@ public function testCreateTableWithVirtualAsColumn() $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_column'); $blueprint->string('my_other_column')->virtualAs('my_column'); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute->nested'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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]); @@ -1393,14 +1395,14 @@ public function testCreateTableWithVirtualAsColumn() public function testCreateTableWithVirtualAsColumnWhenJsonColumnHasArrayKey() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->string('my_json_column')->virtualAsJson('my_json_column->foo[0][1]'); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->string('my_json_column')->virtualAsJson('my_json_column->foo[0][1]'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table `users` (`my_json_column` varchar(255) as (json_unquote(json_extract(`my_json_column`, '$.\"foo\"[0][1]'))))", $statements[0]); @@ -1413,38 +1415,38 @@ public function testCreateTableWithStoredAsColumn() $conn->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8_unicode_ci'); $conn->shouldReceive('getConfig')->once()->with('engine')->andReturn(null); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_column'); $blueprint->string('my_other_column')->storedAs('my_column'); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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'); + $conn = $this->getConnection(); + $conn->shouldReceive('getConfig')->andReturn(null); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute->nested'); - $conn = $this->getConnection(); - $conn->shouldReceive('getConfig')->andReturn(null); - - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $statements = $blueprint->toSql(); $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]); @@ -1493,13 +1495,26 @@ public function testGrammarsAreMacroable() $this->assertTrue($c); } - protected function getConnection() - { - return m::mock(Connection::class); + protected function getConnection( + ?MySqlGrammar $grammar = null, + ?MySqlBuilder $builder = null, + ) { + $grammar ??= $this->getGrammar(); + $builder ??= $this->getBuilder(); + + return m::mock(Connection::class) + ->shouldReceive('getSchemaGrammar')->andReturn($grammar) + ->shouldReceive('getSchemaBuilder')->andReturn($builder) + ->getMock(); } public function getGrammar() { return new MySqlGrammar; } + + public function getBuilder() + { + return mock(MySqlBuilder::class); + } } diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index db13ec2c5c44..bb00bd927123 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -8,7 +8,10 @@ use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\ForeignIdColumnDefinition; use Illuminate\Database\Schema\Grammars\PostgresGrammar; +use Illuminate\Database\Schema\PostgresBuilder; use Mockery as m; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; class DatabasePostgresSchemaGrammarTest extends TestCase @@ -20,20 +23,20 @@ protected function tearDown(): void public function testBasicCreateTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); $blueprint->string('name')->collation('nb_NO.utf8'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "users" ("id" serial not null primary key, "email" varchar(255) not null, "name" varchar(255) collate "nb_NO.utf8" not null)', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ @@ -44,12 +47,12 @@ public function testBasicCreateTable() public function testCreateTableWithAutoIncrementStartingValue() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->increments('id')->startingValue(1000); $blueprint->string('email'); $blueprint->string('name')->collation('nb_NO.utf8'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('create table "users" ("id" serial not null primary key, "email" varchar(255) not null, "name" varchar(255) collate "nb_NO.utf8" not null)', $statements[0]); @@ -58,11 +61,11 @@ public function testCreateTableWithAutoIncrementStartingValue() public function testAddColumnsWithMultipleAutoIncrementStartingValue() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id()->from(100); $blueprint->increments('code')->from(200); $blueprint->string('name')->from(300); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertEquals([ 'alter table "users" add column "id" bigserial not null primary key', @@ -75,11 +78,11 @@ public function testAddColumnsWithMultipleAutoIncrementStartingValue() public function testCreateTableAndCommentColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email')->comment('my first comment'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('create table "users" ("id" serial not null primary key, "email" varchar(255) not null)', $statements[0]); @@ -88,12 +91,12 @@ public function testCreateTableAndCommentColumn() public function testCreateTemporaryTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->temporary(); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create temporary table "users" ("id" serial not null primary key, "email" varchar(255) not null)', $statements[0]); @@ -101,9 +104,9 @@ public function testCreateTemporaryTable() public function testDropTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->drop(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table "users"', $statements[0]); @@ -111,9 +114,9 @@ public function testDropTable() public function testDropTableIfExists() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIfExists(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table if exists "users"', $statements[0]); @@ -121,23 +124,23 @@ public function testDropTableIfExists() public function testDropColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop column "foo"', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn(['foo', 'bar']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop column "foo", drop column "bar"', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop column "foo", drop column "bar"', $statements[0]); @@ -145,9 +148,9 @@ public function testDropColumn() public function testDropPrimary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropPrimary(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop constraint "users_pkey"', $statements[0]); @@ -155,9 +158,9 @@ public function testDropPrimary() public function testDropUnique() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropUnique('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop constraint "foo"', $statements[0]); @@ -165,9 +168,9 @@ public function testDropUnique() public function testDropIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIndex('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "foo"', $statements[0]); @@ -175,9 +178,9 @@ public function testDropIndex() public function testDropSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->dropSpatialIndex(['coordinates']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "geo_coordinates_spatialindex"', $statements[0]); @@ -185,9 +188,9 @@ public function testDropSpatialIndex() public function testDropForeign() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropForeign('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop constraint "foo"', $statements[0]); @@ -195,9 +198,9 @@ public function testDropForeign() public function testDropTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop column "created_at", drop column "updated_at"', $statements[0]); @@ -205,9 +208,9 @@ public function testDropTimestamps() public function testDropTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop column "created_at", drop column "updated_at"', $statements[0]); @@ -215,9 +218,9 @@ public function testDropTimestampsTz() public function testDropMorphs() { - $blueprint = new Blueprint('photos'); + $blueprint = new Blueprint($this->getConnection(), 'photos'); $blueprint->dropMorphs('imageable'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('drop index "photos_imageable_type_imageable_id_index"', $statements[0]); @@ -226,9 +229,9 @@ public function testDropMorphs() public function testRenameTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rename('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" rename to "foo"', $statements[0]); @@ -236,9 +239,9 @@ public function testRenameTable() public function testRenameIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->renameIndex('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter index "foo" rename to "bar"', $statements[0]); @@ -246,9 +249,9 @@ public function testRenameIndex() public function testAddingPrimaryKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->primary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add primary key ("foo")', $statements[0]); @@ -256,9 +259,9 @@ public function testAddingPrimaryKey() public function testAddingUniqueKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->unique('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add constraint "bar" unique ("foo")', $statements[0]); @@ -266,9 +269,9 @@ public function testAddingUniqueKey() public function testAddingIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "baz" on "users" ("foo", "bar")', $statements[0]); @@ -276,9 +279,9 @@ public function testAddingIndex() public function testAddingIndexWithAlgorithm() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz', 'hash'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "baz" on "users" using hash ("foo", "bar")', $statements[0]); @@ -286,9 +289,9 @@ public function testAddingIndexWithAlgorithm() public function testAddingFulltextIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->fulltext('body'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "users_body_fulltext" on "users" using gin ((to_tsvector(\'english\', "body")))', $statements[0]); @@ -296,9 +299,9 @@ public function testAddingFulltextIndex() public function testAddingFulltextIndexMultipleColumns() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->fulltext(['body', 'title']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "users_body_title_fulltext" on "users" using gin ((to_tsvector(\'english\', "body") || to_tsvector(\'english\', "title")))', $statements[0]); @@ -306,9 +309,9 @@ public function testAddingFulltextIndexMultipleColumns() public function testAddingFulltextIndexWithLanguage() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->fulltext('body')->language('spanish'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "users_body_fulltext" on "users" using gin ((to_tsvector(\'spanish\', "body")))', $statements[0]); @@ -316,9 +319,9 @@ public function testAddingFulltextIndexWithLanguage() public function testAddingFulltextIndexWithFluency() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('body')->fulltext(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('create index "users_body_fulltext" on "users" using gin ((to_tsvector(\'english\', "body")))', $statements[1]); @@ -326,9 +329,9 @@ public function testAddingFulltextIndexWithFluency() public function testAddingSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->spatialIndex('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "geo_coordinates_spatialindex" on "geo" using gist ("coordinates")', $statements[0]); @@ -336,9 +339,9 @@ public function testAddingSpatialIndex() public function testAddingFluentSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point')->spatialIndex(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('create index "geo_coordinates_spatialindex" on "geo" using gist ("coordinates")', $statements[1]); @@ -346,9 +349,9 @@ public function testAddingFluentSpatialIndex() public function testAddingRawIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rawIndex('(function(column))', 'raw_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "raw_index" on "users" ((function(column)))', $statements[0]); @@ -356,9 +359,9 @@ public function testAddingRawIndex() public function testAddingIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" serial not null primary key', $statements[0]); @@ -366,9 +369,9 @@ public function testAddingIncrementingID() public function testAddingSmallIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" smallserial not null primary key', $statements[0]); @@ -376,9 +379,9 @@ public function testAddingSmallIncrementingID() public function testAddingMediumIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" serial not null primary key', $statements[0]); @@ -386,16 +389,16 @@ public function testAddingMediumIncrementingID() public function testAddingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" bigserial not null primary key', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" bigserial not null primary key', $statements[0]); @@ -403,14 +406,14 @@ public function testAddingID() public function testAddingForeignID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignId = $blueprint->foreignId('foo'); $blueprint->foreignId('company_id')->constrained(); $blueprint->foreignId('laravel_idea_id')->constrained(); $blueprint->foreignId('team_id')->references('id')->on('teams'); $blueprint->foreignId('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignId); $this->assertSame([ @@ -428,9 +431,9 @@ public function testAddingForeignID() public function testAddingForeignIdSpecifyingIndexNameInConstraint() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreignId('company_id')->constrained(indexName: 'my_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertSame([ 'alter table "users" add column "company_id" bigint not null', 'alter table "users" add constraint "my_index" foreign key ("company_id") references "companies" ("id")', @@ -439,9 +442,9 @@ public function testAddingForeignIdSpecifyingIndexNameInConstraint() public function testAddingBigIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" bigserial not null primary key', $statements[0]); @@ -449,23 +452,23 @@ public function testAddingBigIncrementingID() public function testAddingString() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar(255) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar(100) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default('bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar(100) null default \'bar\'', $statements[0]); @@ -473,18 +476,18 @@ public function testAddingString() public function testAddingStringWithoutLengthLimit() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar(255) not null', $statements[0]); Builder::$defaultStringLength = null; - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); try { $this->assertCount(1, $statements); @@ -496,18 +499,18 @@ public function testAddingStringWithoutLengthLimit() public function testAddingCharWithoutLengthLimit() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->char('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" char(255) not null', $statements[0]); Builder::$defaultStringLength = null; - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->char('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); try { $this->assertCount(1, $statements); @@ -519,9 +522,9 @@ public function testAddingCharWithoutLengthLimit() public function testAddingText() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->text('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" text not null', $statements[0]); @@ -529,16 +532,16 @@ public function testAddingText() public function testAddingBigInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" bigint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" bigserial not null primary key', $statements[0]); @@ -546,16 +549,16 @@ public function testAddingBigInteger() public function testAddingInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" serial not null primary key', $statements[0]); @@ -563,16 +566,16 @@ public function testAddingInteger() public function testAddingMediumInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" serial not null primary key', $statements[0]); @@ -580,16 +583,16 @@ public function testAddingMediumInteger() public function testAddingTinyInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" smallint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" smallserial not null primary key', $statements[0]); @@ -597,16 +600,16 @@ public function testAddingTinyInteger() public function testAddingSmallInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" smallint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" smallserial not null primary key', $statements[0]); @@ -614,9 +617,9 @@ public function testAddingSmallInteger() public function testAddingFloat() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->float('foo', 5); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" float(5) not null', $statements[0]); @@ -624,9 +627,9 @@ public function testAddingFloat() public function testAddingDouble() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->double('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" double precision not null', $statements[0]); @@ -634,9 +637,9 @@ public function testAddingDouble() public function testAddingDecimal() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->decimal('foo', 5, 2); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" decimal(5, 2) not null', $statements[0]); @@ -644,9 +647,9 @@ public function testAddingDecimal() public function testAddingBoolean() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->boolean('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" boolean not null', $statements[0]); @@ -654,9 +657,9 @@ public function testAddingBoolean() public function testAddingEnum() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->enum('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "role" varchar(255) check ("role" in (\'member\', \'admin\')) not null', $statements[0]); @@ -664,9 +667,9 @@ public function testAddingEnum() public function testAddingDate() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->date('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" date not null', $statements[0]); @@ -674,18 +677,18 @@ public function testAddingDate() public function testAddingYear() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->year('birth_year'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "birth_year" integer not null', $statements[0]); } public function testAddingJson() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->json('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" json not null', $statements[0]); @@ -693,205 +696,48 @@ public function testAddingJson() public function testAddingJsonb() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->jsonb('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" jsonb not null', $statements[0]); } - public function testAddingDateTime() + #[DataProvider('datetimeAndPrecisionProvider')] + public function testAddingDatetimeMethods(string $method, string $type, ?int $userPrecision, false|int|null $grammarPrecision, ?int $expected) { - $blueprint = new Blueprint('users'); - $blueprint->dateTime('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + PostgresBuilder::defaultTimePrecision($grammarPrecision); + $blueprint = new Blueprint($this->getConnection(), 'users'); + $blueprint->{$method}('created_at', $userPrecision); + $statements = $blueprint->toSql(); + $type = is_null($expected) ? $type : "{$type}({$expected})"; + $with = str_contains($method, 'Tz') ? 'with' : 'without'; $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(0) without time zone not null', $statements[0]); + $this->assertSame("alter table \"users\" add column \"created_at\" {$type} {$with} time zone not null", $statements[0]); } - public function testAddingDateTimeWithPrecision() + #[TestWith(['timestamps'])] + #[TestWith(['timestampsTz'])] + public function testAddingTimestamps(string $method) { - $blueprint = new Blueprint('users'); - $blueprint->dateTime('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(1) without time zone not null', $statements[0]); - } - - public function testAddingDateTimeWithNullPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->dateTime('created_at', null); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp without time zone not null', $statements[0]); - } - - public function testAddingDateTimeTz() - { - $blueprint = new Blueprint('users'); - $blueprint->dateTimeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(0) with time zone not null', $statements[0]); - } - - public function testAddingDateTimeTzWithPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->dateTimeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(1) with time zone not null', $statements[0]); - } - - public function testAddingDateTimeTzWithNullPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->dateTimeTz('created_at', null); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp with time zone not null', $statements[0]); - } - - public function testAddingTime() - { - $blueprint = new Blueprint('users'); - $blueprint->time('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" time(0) without time zone not null', $statements[0]); - } - - public function testAddingTimeWithPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->time('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" time(1) without time zone not null', $statements[0]); - } - - public function testAddingTimeWithNullPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->time('created_at', null); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" time without time zone not null', $statements[0]); - } - - public function testAddingTimeTz() - { - $blueprint = new Blueprint('users'); - $blueprint->timeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" time(0) with time zone not null', $statements[0]); - } - - public function testAddingTimeTzWithPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->timeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" time(1) with time zone not null', $statements[0]); - } - - public function testAddingTimeTzWithNullPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->timeTz('created_at', null); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" time with time zone not null', $statements[0]); - } - - public function testAddingTimestamp() - { - $blueprint = new Blueprint('users'); - $blueprint->timestamp('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(0) without time zone not null', $statements[0]); - } - - public function testAddingTimestampWithPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->timestamp('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(1) without time zone not null', $statements[0]); - } - - public function testAddingTimestampWithNullPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->timestamp('created_at', null); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp without time zone not null', $statements[0]); - } - - public function testAddingTimestampTz() - { - $blueprint = new Blueprint('users'); - $blueprint->timestampTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(0) with time zone not null', $statements[0]); - } - - public function testAddingTimestampTzWithPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->timestampTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp(1) with time zone not null', $statements[0]); - } - - public function testAddingTimestampTzWithNullPrecision() - { - $blueprint = new Blueprint('users'); - $blueprint->timestampTz('created_at', null); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "created_at" timestamp with time zone not null', $statements[0]); - } - - public function testAddingTimestamps() - { - $blueprint = new Blueprint('users'); - $blueprint->timestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + PostgresBuilder::defaultTimePrecision(0); + $blueprint = new Blueprint($this->getConnection(), 'users'); + $blueprint->{$method}(); + $statements = $blueprint->toSql(); + $with = str_contains($method, 'Tz') ? 'with' : 'without'; $this->assertCount(2, $statements); $this->assertSame([ - 'alter table "users" add column "created_at" timestamp(0) without time zone null', - 'alter table "users" add column "updated_at" timestamp(0) without time zone null', - ], $statements); - } - - public function testAddingTimestampsTz() - { - $blueprint = new Blueprint('users'); - $blueprint->timestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(2, $statements); - $this->assertSame([ - 'alter table "users" add column "created_at" timestamp(0) with time zone null', - 'alter table "users" add column "updated_at" timestamp(0) with time zone null', + "alter table \"users\" add column \"created_at\" timestamp(0) {$with} time zone null", + "alter table \"users\" add column \"updated_at\" timestamp(0) {$with} time zone null", ], $statements); } public function testAddingBinary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->binary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" bytea not null', $statements[0]); @@ -899,9 +745,9 @@ public function testAddingBinary() public function testAddingUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" uuid not null', $statements[0]); @@ -909,9 +755,9 @@ public function testAddingUuid() public function testAddingUuidDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "uuid" uuid not null', $statements[0]); @@ -919,14 +765,14 @@ public function testAddingUuidDefaultsColumnName() public function testAddingForeignUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignUuid = $blueprint->foreignUuid('foo'); $blueprint->foreignUuid('company_id')->constrained(); $blueprint->foreignUuid('laravel_idea_id')->constrained(); $blueprint->foreignUuid('team_id')->references('id')->on('teams'); $blueprint->foreignUuid('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignUuid); $this->assertSame([ @@ -944,47 +790,47 @@ public function testAddingForeignUuid() public function testAddingGeneratedAs() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('foo')->generatedAs(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null generated by default as identity primary key', $statements[0]); // With always modifier - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('foo')->generatedAs()->always(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null generated always as identity primary key', $statements[0]); // With sequence options - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('foo')->generatedAs('increment by 10 start with 100'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null generated by default as identity (increment by 10 start with 100) primary key', $statements[0]); // Not a primary key - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo')->generatedAs(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null generated by default as identity', $statements[0]); } public function testAddingVirtualAs() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo')->nullable(); $blueprint->boolean('bar')->virtualAs('foo is not null'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table "users" add column "foo" integer null', 'alter table "users" add column "bar" boolean not null generated always as (foo is not null)', ], $statements); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo')->nullable(); $blueprint->boolean('bar')->virtualAs(new Expression('foo is not null')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table "users" add column "foo" integer null', @@ -994,20 +840,20 @@ public function testAddingVirtualAs() public function testAddingStoredAs() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo')->nullable(); $blueprint->boolean('bar')->storedAs('foo is not null'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table "users" add column "foo" integer null', 'alter table "users" add column "bar" boolean not null generated always as (foo is not null) stored', ], $statements); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo')->nullable(); $blueprint->boolean('bar')->storedAs(new Expression('foo is not null')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table "users" add column "foo" integer null', @@ -1017,9 +863,9 @@ public function testAddingStoredAs() public function testAddingIpAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" inet not null', $statements[0]); @@ -1027,9 +873,9 @@ public function testAddingIpAddress() public function testAddingIpAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "ip_address" inet not null', $statements[0]); @@ -1037,9 +883,9 @@ public function testAddingIpAddressDefaultsColumnName() public function testAddingMacAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" macaddr not null', $statements[0]); @@ -1047,9 +893,9 @@ public function testAddingMacAddress() public function testAddingMacAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "mac_address" macaddr not null', $statements[0]); @@ -1057,30 +903,30 @@ public function testAddingMacAddressDefaultsColumnName() public function testCompileForeign() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('parent_id')->references('id')->on('parents')->onDelete('cascade')->deferrable(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add constraint "users_parent_id_foreign" foreign key ("parent_id") references "parents" ("id") on delete cascade deferrable', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('parent_id')->references('id')->on('parents')->onDelete('cascade')->deferrable(false)->initiallyImmediate(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add constraint "users_parent_id_foreign" foreign key ("parent_id") references "parents" ("id") on delete cascade not deferrable', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('parent_id')->references('id')->on('parents')->onDelete('cascade')->deferrable()->initiallyImmediate(false); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add constraint "users_parent_id_foreign" foreign key ("parent_id") references "parents" ("id") on delete cascade deferrable initially deferred', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreign('parent_id')->references('id')->on('parents')->onDelete('cascade')->deferrable()->notValid(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add constraint "users_parent_id_foreign" foreign key ("parent_id") references "parents" ("id") on delete cascade deferrable not valid', $statements[0]); @@ -1088,9 +934,9 @@ public function testCompileForeign() public function testAddingGeometry() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry not null', $statements[0]); @@ -1098,9 +944,9 @@ public function testAddingGeometry() public function testAddingGeography() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geography('coordinates', 'pointzm', 4269); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geography(pointzm,4269) not null', $statements[0]); @@ -1108,9 +954,9 @@ public function testAddingGeography() public function testAddingPoint() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(point) not null', $statements[0]); @@ -1118,9 +964,9 @@ public function testAddingPoint() public function testAddingPointWithSrid() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point', 4269); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(point,4269) not null', $statements[0]); @@ -1128,9 +974,9 @@ public function testAddingPointWithSrid() public function testAddingLineString() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'linestring'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(linestring) not null', $statements[0]); @@ -1138,9 +984,9 @@ public function testAddingLineString() public function testAddingPolygon() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'polygon'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(polygon) not null', $statements[0]); @@ -1148,9 +994,9 @@ public function testAddingPolygon() public function testAddingGeometryCollection() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'geometrycollection'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(geometrycollection) not null', $statements[0]); @@ -1158,9 +1004,9 @@ public function testAddingGeometryCollection() public function testAddingMultiPoint() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multipoint'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(multipoint) not null', $statements[0]); @@ -1168,9 +1014,9 @@ public function testAddingMultiPoint() public function testAddingMultiLineString() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multilinestring'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(multilinestring) not null', $statements[0]); @@ -1178,9 +1024,9 @@ public function testAddingMultiLineString() public function testAddingMultiPolygon() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'multipolygon'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry(multipolygon) not null', $statements[0]); @@ -1258,9 +1104,17 @@ public function testCompileColumns() $this->assertStringContainsString("where c.relname = 'table' and n.nspname = 'public'", $statement); } - protected function getConnection() - { - return m::mock(Connection::class); + protected function getConnection( + ?PostgresGrammar $grammar = null, + ?PostgresBuilder $builder = null + ) { + $grammar ??= $this->getGrammar(); + $builder ??= $this->getBuilder(); + + return m::mock(Connection::class) + ->shouldReceive('getSchemaGrammar')->andReturn($grammar) + ->shouldReceive('getSchemaBuilder')->andReturn($builder) + ->getMock(); } public function getGrammar() @@ -1268,6 +1122,39 @@ public function getGrammar() return new PostgresGrammar; } + public function getBuilder() + { + return mock(PostgresBuilder::class); + } + + /** @return list */ + public static function datetimeAndPrecisionProvider(): array + { + $methods = [ + ['method' => 'datetime', 'type' => 'timestamp'], + ['method' => 'datetimeTz', 'type' => 'timestamp'], + ['method' => 'timestamp', 'type' => 'timestamp'], + ['method' => 'timestampTz', 'type' => 'timestamp'], + ['method' => 'time', 'type' => 'time'], + ['method' => 'timeTz', 'type' => 'time'], + ]; + $precisions = [ + 'user can override grammar default' => ['userPrecision' => 1, 'grammarPrecision' => null, 'expected' => 1], + 'fallback to grammar default' => ['userPrecision' => null, 'grammarPrecision' => 5, 'expected' => 5], + 'fallback to database default' => ['userPrecision' => null, 'grammarPrecision' => null, 'expected' => null], + ]; + + $result = []; + + foreach ($methods as $datetime) { + foreach ($precisions as $precision) { + $result[] = array_merge($datetime, $precision); + } + } + + return $result; + } + public function testGrammarsAreMacroable() { // compileReplace macro. diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index 6454a9d82c60..245fd70467ef 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -23,19 +23,19 @@ protected function tearDown(): void public function testBasicCreateTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "users" ("id" integer primary key autoincrement not null, "email" varchar not null)', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $expected = [ @@ -47,12 +47,12 @@ public function testBasicCreateTable() public function testCreateTemporaryTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->temporary(); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create temporary table "users" ("id" integer primary key autoincrement not null, "email" varchar not null)', $statements[0]); @@ -60,9 +60,9 @@ public function testCreateTemporaryTable() public function testDropTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->drop(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table "users"', $statements[0]); @@ -70,9 +70,9 @@ public function testDropTable() public function testDropTableIfExists() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIfExists(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table if exists "users"', $statements[0]); @@ -80,9 +80,9 @@ public function testDropTableIfExists() public function testDropUnique() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropUnique('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "foo"', $statements[0]); @@ -90,9 +90,9 @@ public function testDropUnique() public function testDropIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIndex('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "foo"', $statements[0]); @@ -130,16 +130,16 @@ public function testDropSpatialIndex() $this->expectException(RuntimeException::class); $this->expectExceptionMessage('The database driver in use does not support spatial indexes.'); - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->dropSpatialIndex(['coordinates']); - $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $blueprint->toSql(); } public function testRenameTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rename('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" rename to "foo"', $statements[0]); @@ -183,10 +183,10 @@ public function testRenameIndex() public function testAddingPrimaryKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('foo')->primary(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "users" ("foo" varchar not null, primary key ("foo"))', $statements[0]); @@ -194,12 +194,12 @@ public function testAddingPrimaryKey() public function testAddingForeignKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('foo')->primary(); $blueprint->string('order_id'); $blueprint->foreign('order_id')->references('id')->on('orders'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "users" ("foo" varchar not null, "order_id" varchar not null, foreign key("order_id") references "orders"("id"), primary key ("foo"))', $statements[0]); @@ -207,9 +207,9 @@ public function testAddingForeignKey() public function testAddingUniqueKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->unique('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create unique index "bar" on "users" ("foo")', $statements[0]); @@ -217,9 +217,9 @@ public function testAddingUniqueKey() public function testAddingIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "baz" on "users" ("foo", "bar")', $statements[0]); @@ -230,9 +230,9 @@ public function testAddingSpatialIndex() $this->expectException(RuntimeException::class); $this->expectExceptionMessage('The database driver in use does not support spatial indexes.'); - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->spatialIndex('coordinates'); - $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $blueprint->toSql(); } public function testAddingFluentSpatialIndex() @@ -240,16 +240,16 @@ public function testAddingFluentSpatialIndex() $this->expectException(RuntimeException::class); $this->expectExceptionMessage('The database driver in use does not support spatial indexes.'); - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates')->spatialIndex(); - $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $blueprint->toSql(); } public function testAddingRawIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rawIndex('(function(column))', 'raw_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "raw_index" on "users" ((function(column)))', $statements[0]); @@ -257,9 +257,9 @@ public function testAddingRawIndex() public function testAddingIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" integer primary key autoincrement not null', $statements[0]); @@ -267,9 +267,9 @@ public function testAddingIncrementingID() public function testAddingSmallIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" integer primary key autoincrement not null', $statements[0]); @@ -277,9 +277,9 @@ public function testAddingSmallIncrementingID() public function testAddingMediumIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" integer primary key autoincrement not null', $statements[0]); @@ -287,16 +287,16 @@ public function testAddingMediumIncrementingID() public function testAddingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" integer primary key autoincrement not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer primary key autoincrement not null', $statements[0]); @@ -304,22 +304,20 @@ public function testAddingID() public function testAddingForeignID() { - $blueprint = new Blueprint('users'); + $connection = $this->getConnection(); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $connection->shouldReceive('getPostProcessor')->andReturn(new SQliteProcessor); + $connection->shouldReceive('selectFromWriteConnection')->andReturn([]); + $connection->shouldReceive('scalar')->andReturn(''); + + $blueprint = new Blueprint($connection, 'users'); $foreignId = $blueprint->foreignId('foo'); $blueprint->foreignId('company_id')->constrained(); $blueprint->foreignId('laravel_idea_id')->constrained(); $blueprint->foreignId('team_id')->references('id')->on('teams'); $blueprint->foreignId('team_column_id')->constrained('teams'); - $grammar = $this->getGrammar(); - $connection = $this->getConnection(); - $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getSchemaBuilder')->andReturn(new SQLiteBuilder($connection)); - $connection->shouldReceive('getTablePrefix')->andReturn(''); - $connection->shouldReceive('getPostProcessor')->andReturn(new SQliteProcessor); - $connection->shouldReceive('selectFromWriteConnection')->andReturn([]); - $connection->shouldReceive('scalar')->andReturn(''); - $statements = $blueprint->toSql($connection, $grammar); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignId); $this->assertSame([ @@ -349,18 +347,16 @@ public function testAddingForeignID() public function testAddingForeignIdSpecifyingIndexNameInConstraint() { - $blueprint = new Blueprint('users'); - $blueprint->foreignId('company_id')->constrained(indexName: 'my_index'); - - $grammar = $this->getGrammar(); $connection = $this->getConnection(); - $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getSchemaBuilder')->andReturn(new SQLiteBuilder($connection)); $connection->shouldReceive('getTablePrefix')->andReturn(''); $connection->shouldReceive('getPostProcessor')->andReturn(new SQliteProcessor); $connection->shouldReceive('selectFromWriteConnection')->andReturn([]); $connection->shouldReceive('scalar')->andReturn(''); - $statements = $blueprint->toSql($connection, $grammar); + + $blueprint = new Blueprint($connection, 'users'); + $blueprint->foreignId('company_id')->constrained(indexName: 'my_index'); + + $statements = $blueprint->toSql(); $this->assertSame([ 'alter table "users" add column "company_id" integer not null', @@ -373,9 +369,9 @@ public function testAddingForeignIdSpecifyingIndexNameInConstraint() public function testAddingBigIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "id" integer primary key autoincrement not null', $statements[0]); @@ -383,23 +379,23 @@ public function testAddingBigIncrementingID() public function testAddingString() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default('bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar default \'bar\'', $statements[0]); @@ -407,9 +403,9 @@ public function testAddingString() public function testAddingText() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->text('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" text not null', $statements[0]); @@ -417,16 +413,16 @@ public function testAddingText() public function testAddingBigInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer primary key autoincrement not null', $statements[0]); @@ -434,16 +430,16 @@ public function testAddingBigInteger() public function testAddingInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer primary key autoincrement not null', $statements[0]); @@ -451,16 +447,16 @@ public function testAddingInteger() public function testAddingMediumInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer primary key autoincrement not null', $statements[0]); @@ -468,16 +464,16 @@ public function testAddingMediumInteger() public function testAddingTinyInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer primary key autoincrement not null', $statements[0]); @@ -485,16 +481,16 @@ public function testAddingTinyInteger() public function testAddingSmallInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" integer primary key autoincrement not null', $statements[0]); @@ -502,9 +498,9 @@ public function testAddingSmallInteger() public function testAddingFloat() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->float('foo', 5); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" float not null', $statements[0]); @@ -512,9 +508,9 @@ public function testAddingFloat() public function testAddingDouble() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->double('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" double not null', $statements[0]); @@ -522,9 +518,9 @@ public function testAddingDouble() public function testAddingDecimal() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->decimal('foo', 5, 2); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" numeric not null', $statements[0]); @@ -532,9 +528,9 @@ public function testAddingDecimal() public function testAddingBoolean() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->boolean('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" tinyint(1) not null', $statements[0]); @@ -542,9 +538,9 @@ public function testAddingBoolean() public function testAddingEnum() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->enum('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "role" varchar check ("role" in (\'member\', \'admin\')) not null', $statements[0]); @@ -552,9 +548,9 @@ public function testAddingEnum() public function testAddingJson() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->json('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" text not null', $statements[0]); @@ -562,9 +558,9 @@ public function testAddingJson() public function testAddingJsonb() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->jsonb('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" text not null', $statements[0]); @@ -572,9 +568,9 @@ public function testAddingJsonb() public function testAddingDate() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->date('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" date not null', $statements[0]); @@ -582,126 +578,126 @@ public function testAddingDate() public function testAddingYear() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->year('birth_year'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "birth_year" integer not null', $statements[0]); } public function testAddingDateTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingDateTimeWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingDateTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingDateTimeTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" time not null', $statements[0]); } public function testAddingTimeWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" time not null', $statements[0]); } public function testAddingTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" time not null', $statements[0]); } public function testAddingTimeTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" time not null', $statements[0]); } public function testAddingTimestamp() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingTimestampWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingTimestampTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingTimestampTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "created_at" datetime not null', $statements[0]); } public function testAddingTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertEquals([ 'alter table "users" add column "created_at" datetime', @@ -711,9 +707,9 @@ public function testAddingTimestamps() public function testAddingTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertEquals([ 'alter table "users" add column "created_at" datetime', @@ -723,9 +719,9 @@ public function testAddingTimestampsTz() public function testAddingRememberToken() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rememberToken(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "remember_token" varchar', $statements[0]); @@ -733,9 +729,9 @@ public function testAddingRememberToken() public function testAddingBinary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->binary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" blob not null', $statements[0]); @@ -743,9 +739,9 @@ public function testAddingBinary() public function testAddingUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); @@ -753,9 +749,9 @@ public function testAddingUuid() public function testAddingUuidDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "uuid" varchar not null', $statements[0]); @@ -763,22 +759,20 @@ public function testAddingUuidDefaultsColumnName() public function testAddingForeignUuid() { - $blueprint = new Blueprint('users'); + $connection = $this->getConnection(); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $connection->shouldReceive('getPostProcessor')->andReturn(new SQliteProcessor); + $connection->shouldReceive('selectFromWriteConnection')->andReturn([]); + $connection->shouldReceive('scalar')->andReturn(''); + + $blueprint = new Blueprint($connection, 'users'); $foreignUuid = $blueprint->foreignUuid('foo'); $blueprint->foreignUuid('company_id')->constrained(); $blueprint->foreignUuid('laravel_idea_id')->constrained(); $blueprint->foreignUuid('team_id')->references('id')->on('teams'); $blueprint->foreignUuid('team_column_id')->constrained('teams'); - $grammar = $this->getGrammar(); - $connection = $this->getConnection(); - $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getSchemaBuilder')->andReturn(new SQLiteBuilder($connection)); - $connection->shouldReceive('getTablePrefix')->andReturn(''); - $connection->shouldReceive('getPostProcessor')->andReturn(new SQliteProcessor); - $connection->shouldReceive('selectFromWriteConnection')->andReturn([]); - $connection->shouldReceive('scalar')->andReturn(''); - $statements = $blueprint->toSql($connection, $grammar); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignUuid); $this->assertSame([ @@ -808,9 +802,9 @@ public function testAddingForeignUuid() public function testAddingIpAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); @@ -818,9 +812,9 @@ public function testAddingIpAddress() public function testAddingIpAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "ip_address" varchar not null', $statements[0]); @@ -828,9 +822,9 @@ public function testAddingIpAddressDefaultsColumnName() public function testAddingMacAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "foo" varchar not null', $statements[0]); @@ -838,9 +832,9 @@ public function testAddingMacAddress() public function testAddingMacAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add column "mac_address" varchar not null', $statements[0]); @@ -848,9 +842,9 @@ public function testAddingMacAddressDefaultsColumnName() public function testAddingGeometry() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add column "coordinates" geometry not null', $statements[0]); @@ -858,21 +852,21 @@ public function testAddingGeometry() public function testAddingGeneratedColumn() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->create(); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs('"price" - 5'); $blueprint->integer('discounted_stored')->storedAs('"price" - 5'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "products" ("price" integer not null, "discounted_virtual" integer as ("price" - 5), "discounted_stored" integer as ("price" - 5) stored)', $statements[0]); - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs('"price" - 5')->nullable(false); $blueprint->integer('discounted_stored')->storedAs('"price" - 5')->nullable(false); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $expected = [ @@ -885,12 +879,12 @@ public function testAddingGeneratedColumn() public function testAddingGeneratedColumnByExpression() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->create(); $blueprint->integer('price'); $blueprint->integer('discounted_virtual')->virtualAs(new Expression('"price" - 5')); $blueprint->integer('discounted_stored')->storedAs(new Expression('"price" - 5')); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "products" ("price" integer not null, "discounted_virtual" integer as ("price" - 5), "discounted_stored" integer as ("price" - 5) stored)', $statements[0]); @@ -910,32 +904,32 @@ public function testGrammarsAreMacroable() public function testCreateTableWithVirtualAsColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('my_column'); $blueprint->string('my_other_column')->virtualAs('my_column'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $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 = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $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 = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->virtualAsJson('my_json_column->some_attribute->nested'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $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]); @@ -943,14 +937,14 @@ public function testCreateTableWithVirtualAsColumn() public function testCreateTableWithVirtualAsColumnWhenJsonColumnHasArrayKey() { - $blueprint = new Blueprint('users'); - $blueprint->create(); - $blueprint->string('my_json_column')->virtualAsJson('my_json_column->foo[0][1]'); - $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); - $statements = $blueprint->toSql($conn, $this->getGrammar()); + $blueprint = new Blueprint($conn, 'users'); + $blueprint->create(); + $blueprint->string('my_json_column')->virtualAsJson('my_json_column->foo[0][1]'); + + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("create table \"users\" (\"my_json_column\" varchar as (json_extract(\"my_json_column\", '$.\"foo\"[0][1]')))", $statements[0]); @@ -958,32 +952,32 @@ public function testCreateTableWithVirtualAsColumnWhenJsonColumnHasArrayKey() public function testCreateTableWithStoredAsColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('my_column'); $blueprint->string('my_other_column')->storedAs('my_column'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $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 = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $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 = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->string('my_json_column'); $blueprint->string('my_other_column')->storedAsJson('my_json_column->some_attribute->nested'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $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]); @@ -991,23 +985,38 @@ public function testCreateTableWithStoredAsColumn() public function testDroppingColumnsWorks() { - $blueprint = new Blueprint('users', function ($table) { + $blueprint = new Blueprint($this->getConnection(), 'users', function ($table) { $table->dropColumn('name'); }); - $this->assertEquals(['alter table "users" drop column "name"'], $blueprint->toSql($this->getConnection(), $this->getGrammar())); + $this->assertEquals(['alter table "users" drop column "name"'], $blueprint->toSql()); } - protected function getConnection() - { - $connection = m::mock(Connection::class); - $connection->shouldReceive('getServerVersion')->andReturn('3.35'); + protected function getConnection( + ?SQLiteGrammar $grammar = null, + ?SQLiteBuilder $builder = null, + ) { + $grammar ??= $this->getGrammar(); + $builder ??= $this->getBuilder(); - return $connection; + return m::mock(Connection::class) + ->shouldReceive('getSchemaGrammar')->andReturn($grammar) + ->shouldReceive('getSchemaBuilder')->andReturn($builder) + ->shouldReceive('getServerVersion')->andReturn('3.35') + ->getMock(); } public function getGrammar() { - return new SQLiteGrammar; + return new SQLiteGrammar(); + } + + public function getBuilder() + { + return mock(SQLiteBuilder::class) + ->shouldReceive('getColumns')->andReturn([]) + ->shouldReceive('getIndexes')->andReturn([]) + ->shouldReceive('getForeignKeys')->andReturn([]) + ->getMock(); } } diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index b9048e2a2bed..3978d350773a 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -2,14 +2,21 @@ namespace Illuminate\Tests\Database; +use Closure; use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Builder; +use Illuminate\Database\Schema\Grammars\Grammar; use Illuminate\Database\Schema\Grammars\MariaDbGrammar; use Illuminate\Database\Schema\Grammars\MySqlGrammar; use Illuminate\Database\Schema\Grammars\PostgresGrammar; use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Database\Schema\Grammars\SqlServerGrammar; +use Illuminate\Database\Schema\MariaDbBuilder; +use Illuminate\Database\Schema\MySqlBuilder; +use Illuminate\Database\Schema\PostgresBuilder; +use Illuminate\Database\Schema\SQLiteBuilder; +use Illuminate\Database\Schema\SqlServerBuilder; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -23,29 +30,28 @@ protected function tearDown(): void public function testToSqlRunsCommandsFromBlueprint() { - $conn = m::mock(Connection::class); + $conn = $this->getConnection(); $conn->shouldReceive('statement')->once()->with('foo'); $conn->shouldReceive('statement')->once()->with('bar'); - $grammar = m::mock(MySqlGrammar::class); - $blueprint = $this->getMockBuilder(Blueprint::class)->onlyMethods(['toSql'])->setConstructorArgs(['users'])->getMock(); - $blueprint->expects($this->once())->method('toSql')->with($this->equalTo($conn), $this->equalTo($grammar))->willReturn(['foo', 'bar']); + $blueprint = $this->getMockBuilder(Blueprint::class)->onlyMethods(['toSql'])->setConstructorArgs([$conn, 'users'])->getMock(); + $blueprint->expects($this->once())->method('toSql')->willReturn(['foo', 'bar']); - $blueprint->build($conn, $grammar); + $blueprint->build(); } public function testIndexDefaultNames() { - $blueprint = new Blueprint('users'); + $blueprint = $this->getBlueprint(table: 'users'); $blueprint->unique(['foo', 'bar']); $commands = $blueprint->getCommands(); $this->assertSame('users_foo_bar_unique', $commands[0]->index); - $blueprint = new Blueprint('users'); + $blueprint = $this->getBlueprint(table: 'users'); $blueprint->index('foo'); $commands = $blueprint->getCommands(); $this->assertSame('users_foo_index', $commands[0]->index); - $blueprint = new Blueprint('geo'); + $blueprint = $this->getBlueprint(table: 'geo'); $blueprint->spatialIndex('coordinates'); $commands = $blueprint->getCommands(); $this->assertSame('geo_coordinates_spatialindex', $commands[0]->index); @@ -53,17 +59,17 @@ public function testIndexDefaultNames() public function testIndexDefaultNamesWhenPrefixSupplied() { - $blueprint = new Blueprint('users', null, 'prefix_'); + $blueprint = $this->getBlueprint(table: 'users', prefix: 'prefix_'); $blueprint->unique(['foo', 'bar']); $commands = $blueprint->getCommands(); $this->assertSame('prefix_users_foo_bar_unique', $commands[0]->index); - $blueprint = new Blueprint('users', null, 'prefix_'); + $blueprint = $this->getBlueprint(table: 'users', prefix: 'prefix_'); $blueprint->index('foo'); $commands = $blueprint->getCommands(); $this->assertSame('prefix_users_foo_index', $commands[0]->index); - $blueprint = new Blueprint('geo', null, 'prefix_'); + $blueprint = $this->getBlueprint(table: 'geo', prefix: 'prefix_'); $blueprint->spatialIndex('coordinates'); $commands = $blueprint->getCommands(); $this->assertSame('prefix_geo_coordinates_spatialindex', $commands[0]->index); @@ -71,17 +77,17 @@ public function testIndexDefaultNamesWhenPrefixSupplied() public function testDropIndexDefaultNames() { - $blueprint = new Blueprint('users'); + $blueprint = $this->getBlueprint(table: 'users'); $blueprint->dropUnique(['foo', 'bar']); $commands = $blueprint->getCommands(); $this->assertSame('users_foo_bar_unique', $commands[0]->index); - $blueprint = new Blueprint('users'); + $blueprint = $this->getBlueprint(table: 'users'); $blueprint->dropIndex(['foo']); $commands = $blueprint->getCommands(); $this->assertSame('users_foo_index', $commands[0]->index); - $blueprint = new Blueprint('geo'); + $blueprint = $this->getBlueprint(table: 'geo'); $blueprint->dropSpatialIndex(['coordinates']); $commands = $blueprint->getCommands(); $this->assertSame('geo_coordinates_spatialindex', $commands[0]->index); @@ -89,17 +95,17 @@ public function testDropIndexDefaultNames() public function testDropIndexDefaultNamesWhenPrefixSupplied() { - $blueprint = new Blueprint('users', null, 'prefix_'); + $blueprint = $this->getBlueprint(table: 'users', prefix: 'prefix_'); $blueprint->dropUnique(['foo', 'bar']); $commands = $blueprint->getCommands(); $this->assertSame('prefix_users_foo_bar_unique', $commands[0]->index); - $blueprint = new Blueprint('users', null, 'prefix_'); + $blueprint = $this->getBlueprint(table: 'users', prefix: 'prefix_'); $blueprint->dropIndex(['foo']); $commands = $blueprint->getCommands(); $this->assertSame('prefix_users_foo_index', $commands[0]->index); - $blueprint = new Blueprint('geo', null, 'prefix_'); + $blueprint = $this->getBlueprint(table: 'geo', prefix: 'prefix_'); $blueprint->dropSpatialIndex(['coordinates']); $commands = $blueprint->getCommands(); $this->assertSame('prefix_geo_coordinates_spatialindex', $commands[0]->index); @@ -107,157 +113,126 @@ public function testDropIndexDefaultNamesWhenPrefixSupplied() public function testDefaultCurrentDateTime() { - $base = new Blueprint('users', function ($table) { - $table->dateTime('created')->useCurrent(); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; - $this->assertEquals(['alter table `users` add `created` datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new MySqlGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; - $connection->shouldReceive('getServerVersion')->andReturn('3.35'); - $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SQLiteGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SqlServerGrammar)); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->dateTime('created')->useCurrent(); + })->toSql(); + }; + + $this->assertEquals(['alter table `users` add `created` datetime not null default CURRENT_TIMESTAMP'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SQLiteGrammar)); + $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SqlServerGrammar)); } public function testDefaultCurrentTimestamp() { - $base = new Blueprint('users', function ($table) { - $table->timestamp('created')->useCurrent(); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; - $this->assertEquals(['alter table `users` add `created` timestamp not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new MySqlGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; - $connection->shouldReceive('getServerVersion')->andReturn('3.35'); - $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SQLiteGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SqlServerGrammar)); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->timestamp('created')->useCurrent(); + })->toSql(); + }; + + $this->assertEquals(['alter table `users` add `created` timestamp not null default CURRENT_TIMESTAMP'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SQLiteGrammar)); + $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SqlServerGrammar)); } public function testRemoveColumn() { - $base = new Blueprint('users', function ($table) { - $table->string('foo'); - $table->string('remove_this'); - $table->removeColumn('remove_this'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; - - $this->assertEquals(['alter table `users` add `foo` varchar(255) not null'], $blueprint->toSql($connection, new MySqlGrammar)); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->string('foo'); + $table->string('remove_this'); + $table->removeColumn('remove_this'); + })->toSql(); + }; + + $this->assertEquals(['alter table `users` add `foo` varchar(255) not null'], $getSql(new MySqlGrammar)); } public function testRenameColumn() { - $base = new Blueprint('users', function ($table) { - $table->renameColumn('foo', 'bar'); - }); - - $connection = m::mock(Connection::class); - $connection->shouldReceive('getServerVersion')->andReturn('8.0.4'); - $connection->shouldReceive('isMaria')->andReturn(false); - - $blueprint = clone $base; - $this->assertEquals(['alter table `users` rename column `foo` to `bar`'], $blueprint->toSql($connection, new MySqlGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $blueprint->toSql($connection, new SQLiteGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['sp_rename N\'"users"."foo"\', "bar", N\'COLUMN\''], $blueprint->toSql($connection, new SqlServerGrammar)); + $getSql = function ($grammar) { + $connection = $this->getConnection($grammar); + $connection->shouldReceive('getServerVersion')->andReturn('8.0.4'); + $connection->shouldReceive('isMaria')->andReturn(false); + + return (new Blueprint($connection, 'users', function ($table) { + $table->renameColumn('foo', 'bar'); + }))->toSql(); + }; + + $this->assertEquals(['alter table `users` rename column `foo` to `bar`'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $getSql(new SQLiteGrammar)); + $this->assertEquals(['sp_rename N\'"users"."foo"\', "bar", N\'COLUMN\''], $getSql(new SqlServerGrammar)); } public function testNativeRenameColumnOnMysql57() { - $blueprint = new Blueprint('users', function ($table) { - $table->renameColumn('name', 'title'); - $table->renameColumn('id', 'key'); - $table->renameColumn('generated', 'new_generated'); - }); - - $connection = m::mock(Connection::class); + $connection = $this->getConnection(new MySqlGrammar); $connection->shouldReceive('isMaria')->andReturn(false); $connection->shouldReceive('getServerVersion')->andReturn('5.7'); - $connection->shouldReceive('getSchemaBuilder->getColumns')->andReturn([ + $connection->getSchemaBuilder()->shouldReceive('getColumns')->andReturn([ ['name' => 'name', 'type' => 'varchar(255)', 'type_name' => 'varchar', 'nullable' => true, 'collation' => 'utf8mb4_unicode_ci', 'default' => 'foo', 'comment' => null, 'auto_increment' => false, 'generation' => null], ['name' => 'id', 'type' => 'bigint unsigned', 'type_name' => 'bigint', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => 'lorem ipsum', 'auto_increment' => true, 'generation' => null], ['name' => 'generated', 'type' => 'int', 'type_name' => 'int', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => null, 'auto_increment' => false, 'generation' => ['type' => 'stored', 'expression' => 'expression']], ]); + $blueprint = new Blueprint($connection, 'users', function ($table) { + $table->renameColumn('name', 'title'); + $table->renameColumn('id', 'key'); + $table->renameColumn('generated', 'new_generated'); + }); + $this->assertEquals([ "alter table `users` change `name` `title` varchar(255) collate 'utf8mb4_unicode_ci' null default 'foo'", "alter table `users` change `id` `key` bigint unsigned not null auto_increment comment 'lorem ipsum'", 'alter table `users` change `generated` `new_generated` int as (expression) stored not null', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $blueprint->toSql()); } public function testNativeRenameColumnOnLegacyMariaDB() { - $blueprint = new Blueprint('users', function ($table) { - $table->renameColumn('name', 'title'); - $table->renameColumn('id', 'key'); - $table->renameColumn('generated', 'new_generated'); - $table->renameColumn('foo', 'bar'); - }); - - $connection = m::mock(Connection::class); + $connection = $this->getConnection(new MariaDbGrammar); $connection->shouldReceive('isMaria')->andReturn(true); $connection->shouldReceive('getServerVersion')->andReturn('10.1.35'); - $connection->shouldReceive('getSchemaBuilder->getColumns')->andReturn([ + $connection->getSchemaBuilder()->shouldReceive('getColumns')->andReturn([ ['name' => 'name', 'type' => 'varchar(255)', 'type_name' => 'varchar', 'nullable' => true, 'collation' => 'utf8mb4_unicode_ci', 'default' => 'foo', 'comment' => null, 'auto_increment' => false, 'generation' => null], ['name' => 'id', 'type' => 'bigint unsigned', 'type_name' => 'bigint', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => 'lorem ipsum', 'auto_increment' => true, 'generation' => null], ['name' => 'generated', 'type' => 'int', 'type_name' => 'int', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => null, 'auto_increment' => false, 'generation' => ['type' => 'stored', 'expression' => 'expression']], ['name' => 'foo', 'type' => 'int', 'type_name' => 'int', 'nullable' => true, 'collation' => null, 'default' => 'NULL', 'comment' => null, 'auto_increment' => false, 'generation' => null], ]); + $blueprint = new Blueprint($connection, 'users', function ($table) { + $table->renameColumn('name', 'title'); + $table->renameColumn('id', 'key'); + $table->renameColumn('generated', 'new_generated'); + $table->renameColumn('foo', 'bar'); + }); + $this->assertEquals([ "alter table `users` change `name` `title` varchar(255) collate 'utf8mb4_unicode_ci' null default 'foo'", "alter table `users` change `id` `key` bigint unsigned not null auto_increment comment 'lorem ipsum'", 'alter table `users` change `generated` `new_generated` int as (expression) stored not null', 'alter table `users` change `foo` `bar` int null default NULL', - ], $blueprint->toSql($connection, new MariaDbGrammar)); + ], $blueprint->toSql()); } public function testDropColumn() { - $base = new Blueprint('users', function ($table) { - $table->dropColumn('foo'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; - $this->assertEquals(['alter table `users` drop `foo`'], $blueprint->toSql($connection, new MySqlGrammar)); - - $blueprint = clone $base; - $this->assertEquals(['alter table "users" drop column "foo"'], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; - $connection->shouldReceive('getServerVersion')->andReturn('3.35'); - $this->assertEquals(['alter table "users" drop column "foo"'], $blueprint->toSql($connection, new SQLiteGrammar)); - - $blueprint = clone $base; - $this->assertStringContainsString('alter table "users" drop column "foo"', $blueprint->toSql($connection, new SqlServerGrammar)[0]); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->dropColumn('foo'); + })->toSql(); + }; + + $this->assertEquals(['alter table `users` drop `foo`'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table "users" drop column "foo"'], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table "users" drop column "foo"'], $getSql(new SQLiteGrammar)); + $this->assertStringContainsString('alter table "users" drop column "foo"', $getSql(new SqlServerGrammar)[0]); } public function testMacroable() @@ -270,322 +245,288 @@ public function testMacroable() return 'bar'; }); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new MySqlGrammar, 'users', function ($table) { $table->foo(); }); - $connection = m::mock(Connection::class); - - $this->assertEquals(['bar'], $blueprint->toSql($connection, new MySqlGrammar)); + $this->assertEquals(['bar'], $blueprint->toSql()); } public function testDefaultUsingIdMorph() { - $base = new Blueprint('comments', function ($table) { - $table->morphs('commentable'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'comments', function ($table) { + $table->morphs('commentable'); + })->toSql(); + }; $this->assertEquals([ 'alter table `comments` add `commentable_type` varchar(255) not null', 'alter table `comments` add `commentable_id` bigint unsigned not null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDefaultUsingNullableIdMorph() { - $base = new Blueprint('comments', function ($table) { - $table->nullableMorphs('commentable'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'comments', function ($table) { + $table->nullableMorphs('commentable'); + })->toSql(); + }; $this->assertEquals([ 'alter table `comments` add `commentable_type` varchar(255) null', 'alter table `comments` add `commentable_id` bigint unsigned null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDefaultUsingUuidMorph() { Builder::defaultMorphKeyType('uuid'); - $base = new Blueprint('comments', function ($table) { - $table->morphs('commentable'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'comments', function ($table) { + $table->morphs('commentable'); + })->toSql(); + }; $this->assertEquals([ 'alter table `comments` add `commentable_type` varchar(255) not null', 'alter table `comments` add `commentable_id` char(36) not null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDefaultUsingNullableUuidMorph() { Builder::defaultMorphKeyType('uuid'); - $base = new Blueprint('comments', function ($table) { - $table->nullableMorphs('commentable'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'comments', function ($table) { + $table->nullableMorphs('commentable'); + })->toSql(); + }; $this->assertEquals([ 'alter table `comments` add `commentable_type` varchar(255) null', 'alter table `comments` add `commentable_id` char(36) null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDefaultUsingUlidMorph() { Builder::defaultMorphKeyType('ulid'); - $base = new Blueprint('comments', function ($table) { - $table->morphs('commentable'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'comments', function ($table) { + $table->morphs('commentable'); + })->toSql(); + }; $this->assertEquals([ 'alter table `comments` add `commentable_type` varchar(255) not null', 'alter table `comments` add `commentable_id` char(26) not null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDefaultUsingNullableUlidMorph() { Builder::defaultMorphKeyType('ulid'); - $base = new Blueprint('comments', function ($table) { - $table->nullableMorphs('commentable'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'comments', function ($table) { + $table->nullableMorphs('commentable'); + })->toSql(); + }; $this->assertEquals([ 'alter table `comments` add `commentable_type` varchar(255) null', 'alter table `comments` add `commentable_id` char(26) null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testGenerateRelationshipColumnWithIncrementalModel() { - $base = new Blueprint('posts', function ($table) { - $table->foreignIdFor('Illuminate\Foundation\Auth\User'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->foreignIdFor('Illuminate\Foundation\Auth\User'); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` add `user_id` bigint unsigned not null', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testGenerateRelationshipColumnWithUuidModel() { require_once __DIR__.'/stubs/EloquentModelUuidStub.php'; - $base = new Blueprint('posts', function ($table) { - $table->foreignIdFor('EloquentModelUuidStub'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->foreignIdFor('EloquentModelUuidStub'); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` add `eloquent_model_uuid_stub_id` char(36) not null', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testGenerateRelationshipColumnWithUlidModel() { require_once __DIR__.'/stubs/EloquentModelUlidStub.php'; - $base = new Blueprint('posts', function (Blueprint $table) { - $table->foreignIdFor('EloquentModelUlidStub'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->foreignIdFor('EloquentModelUlidStub'); + })->toSql(); + }; $this->assertEquals([ 'alter table "posts" add column "eloquent_model_ulid_stub_id" char(26) not null', - ], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; + ], $getSql(new PostgresGrammar)); $this->assertEquals([ 'alter table `posts` add `eloquent_model_ulid_stub_id` char(26) not null', - ], $blueprint->toSql($connection, new MySqlGrammar())); + ], $getSql(new MySqlGrammar)); } public function testDropRelationshipColumnWithIncrementalModel() { - $base = new Blueprint('posts', function ($table) { - $table->dropForeignIdFor('Illuminate\Foundation\Auth\User'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->dropForeignIdFor('Illuminate\Foundation\Auth\User'); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` drop foreign key `posts_user_id_foreign`', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDropRelationshipColumnWithUuidModel() { require_once __DIR__.'/stubs/EloquentModelUuidStub.php'; - $base = new Blueprint('posts', function ($table) { - $table->dropForeignIdFor('EloquentModelUuidStub'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->dropForeignIdFor('EloquentModelUuidStub'); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` drop foreign key `posts_eloquent_model_uuid_stub_id_foreign`', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDropConstrainedRelationshipColumnWithIncrementalModel() { - $base = new Blueprint('posts', function ($table) { - $table->dropConstrainedForeignIdFor('Illuminate\Foundation\Auth\User'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->dropConstrainedForeignIdFor('Illuminate\Foundation\Auth\User'); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` drop foreign key `posts_user_id_foreign`', 'alter table `posts` drop `user_id`', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDropConstrainedRelationshipColumnWithUuidModel() { require_once __DIR__.'/stubs/EloquentModelUuidStub.php'; - $base = new Blueprint('posts', function ($table) { - $table->dropConstrainedForeignIdFor('EloquentModelUuidStub'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->dropConstrainedForeignIdFor('EloquentModelUuidStub'); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` drop foreign key `posts_eloquent_model_uuid_stub_id_foreign`', 'alter table `posts` drop `eloquent_model_uuid_stub_id`', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testTinyTextColumn() { - $base = new Blueprint('posts', function ($table) { - $table->tinyText('note'); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; - $this->assertEquals([ - 'alter table `posts` add `note` tinytext not null', - ], $blueprint->toSql($connection, new MySqlGrammar)); - - $blueprint = clone $base; - $connection->shouldReceive('getServerVersion')->andReturn('3.35'); - $this->assertEquals([ - 'alter table "posts" add column "note" text not null', - ], $blueprint->toSql($connection, new SQLiteGrammar)); - - $blueprint = clone $base; - $this->assertEquals([ - 'alter table "posts" add column "note" varchar(255) not null', - ], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; - $this->assertEquals([ - 'alter table "posts" add "note" nvarchar(255) not null', - ], $blueprint->toSql($connection, new SqlServerGrammar)); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->tinyText('note'); + })->toSql(); + }; + + $this->assertEquals(['alter table `posts` add `note` tinytext not null'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table "posts" add column "note" text not null'], $getSql(new SQLiteGrammar)); + $this->assertEquals(['alter table "posts" add column "note" varchar(255) not null'], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table "posts" add "note" nvarchar(255) not null'], $getSql(new SqlServerGrammar)); } public function testTinyTextNullableColumn() { - $base = new Blueprint('posts', function ($table) { - $table->tinyText('note')->nullable(); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; - $this->assertEquals([ - 'alter table `posts` add `note` tinytext null', - ], $blueprint->toSql($connection, new MySqlGrammar)); - - $blueprint = clone $base; - $connection->shouldReceive('getServerVersion')->andReturn('3.35'); - $this->assertEquals([ - 'alter table "posts" add column "note" text', - ], $blueprint->toSql($connection, new SQLiteGrammar)); - - $blueprint = clone $base; - $this->assertEquals([ - 'alter table "posts" add column "note" varchar(255) null', - ], $blueprint->toSql($connection, new PostgresGrammar)); - - $blueprint = clone $base; - $this->assertEquals([ - 'alter table "posts" add "note" nvarchar(255) null', - ], $blueprint->toSql($connection, new SqlServerGrammar)); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->tinyText('note')->nullable(); + })->toSql(); + }; + + $this->assertEquals(['alter table `posts` add `note` tinytext null'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table "posts" add column "note" text'], $getSql(new SQLiteGrammar)); + $this->assertEquals(['alter table "posts" add column "note" varchar(255) null'], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table "posts" add "note" nvarchar(255) null'], $getSql(new SqlServerGrammar)); } public function testTableComment() { - $base = new Blueprint('posts', function (Blueprint $table) { - $table->comment('Look at my comment, it is amazing'); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->comment('Look at my comment, it is amazing'); + })->toSql(); + }; + + $this->assertEquals(['alter table `posts` comment = \'Look at my comment, it is amazing\''], $getSql(new MySqlGrammar)); + $this->assertEquals(['comment on table "posts" is \'Look at my comment, it is amazing\''], $getSql(new PostgresGrammar)); + } + + protected function getConnection(?Grammar $grammar = null) + { + $grammar ??= new MySqlGrammar; + + $builder = mock(match ($grammar::class) { + MySqlGrammar::class => MySqlBuilder::class, + PostgresGrammar::class => PostgresBuilder::class, + SQLiteGrammar::class => SQLiteBuilder::class, + SqlServerGrammar::class => SqlServerBuilder::class, + MariaDbGrammar::class => MariaDbBuilder::class, + default => Builder::class, }); - $connection = m::mock(Connection::class); + $connection = m::mock(Connection::class) + ->shouldReceive('getSchemaGrammar')->andReturn($grammar) + ->shouldReceive('getSchemaBuilder')->andReturn($builder); - $blueprint = clone $base; - $this->assertEquals([ - 'alter table `posts` comment = \'Look at my comment, it is amazing\'', - ], $blueprint->toSql($connection, new MySqlGrammar)); + if ($grammar instanceof SQLiteGrammar) { + $connection->shouldReceive('getServerVersion')->andReturn('3.35'); + } - $blueprint = clone $base; - $this->assertEquals([ - 'comment on table "posts" is \'Look at my comment, it is amazing\'', - ], $blueprint->toSql($connection, new PostgresGrammar)); + return $connection->getMock(); + } + + protected function getBlueprint( + ?Grammar $grammar = null, + string $table = '', + ?Closure $callback = null, + string $prefix = '' + ): Blueprint { + $connection = $this->getConnection($grammar); + + return new Blueprint($connection, $table, $callback, $prefix); } } diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 81c15f7aa79d..a22bf69c095f 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\ForeignIdColumnDefinition; use Illuminate\Database\Schema\Grammars\SqlServerGrammar; +use Illuminate\Database\Schema\SqlServerBuilder; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -19,19 +20,19 @@ protected function tearDown(): void public function testBasicCreateTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "users" ("id" int not null identity primary key, "email" nvarchar(255) not null)', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ @@ -39,11 +40,12 @@ public function testBasicCreateTable() 'alter table "users" add "email" nvarchar(255) not null', ], $statements); - $blueprint = new Blueprint('users'); + $conn = $this->getConnection($this->getGrammar()->setTablePrefix('prefix_')); + $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()->setTablePrefix('prefix_')); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "prefix_users" ("id" int not null identity primary key, "email" nvarchar(255) not null)', $statements[0]); @@ -51,12 +53,12 @@ public function testBasicCreateTable() public function testCreateTemporaryTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->create(); $blueprint->temporary(); $blueprint->increments('id'); $blueprint->string('email'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create table "#users" ("id" int not null identity primary key, "email" nvarchar(255) not null)', $statements[0]); @@ -64,16 +66,17 @@ public function testCreateTemporaryTable() public function testDropTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->drop(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table "users"', $statements[0]); - $blueprint = new Blueprint('users'); + $conn = $this->getConnection($this->getGrammar()->setTablePrefix('prefix_')); + $blueprint = new Blueprint($conn, 'users'); $blueprint->drop(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()->setTablePrefix('prefix_')); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop table "prefix_users"', $statements[0]); @@ -81,16 +84,17 @@ public function testDropTable() public function testDropTableIfExists() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIfExists(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('if object_id(N\'"users"\', \'U\') is not null drop table "users"', $statements[0]); - $blueprint = new Blueprint('users'); + $conn = $this->getConnection($this->getGrammar()->setTablePrefix('prefix_')); + $blueprint = new Blueprint($conn, 'users'); $blueprint->dropIfExists(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()->setTablePrefix('prefix_')); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('if object_id(N\'"prefix_users"\', \'U\') is not null drop table "prefix_users"', $statements[0]); @@ -98,23 +102,23 @@ public function testDropTableIfExists() public function testDropColumn() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertStringContainsString('alter table "users" drop column "foo"', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn(['foo', 'bar']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertStringContainsString('alter table "users" drop column "foo", "bar"', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropColumn('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertStringContainsString('alter table "users" drop column "foo", "bar"', $statements[0]); @@ -122,9 +126,9 @@ public function testDropColumn() public function testDropColumnDropsCreatesSqlToDropDefaultConstraints() { - $blueprint = new Blueprint('foo'); + $blueprint = new Blueprint($this->getConnection(), 'foo'); $blueprint->dropColumn('bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame("DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"foo\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"foo\"') AND [name] in ('bar') AND [default_object_id] <> 0;EXEC(@sql);alter table \"foo\" drop column \"bar\"", $statements[0]); @@ -132,9 +136,9 @@ public function testDropColumnDropsCreatesSqlToDropDefaultConstraints() public function testDropPrimary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropPrimary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop constraint "foo"', $statements[0]); @@ -142,9 +146,9 @@ public function testDropPrimary() public function testDropUnique() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropUnique('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "foo" on "users"', $statements[0]); @@ -152,9 +156,9 @@ public function testDropUnique() public function testDropIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropIndex('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "foo" on "users"', $statements[0]); @@ -162,9 +166,9 @@ public function testDropIndex() public function testDropSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->dropSpatialIndex(['coordinates']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('drop index "geo_coordinates_spatialindex" on "geo"', $statements[0]); @@ -172,9 +176,9 @@ public function testDropSpatialIndex() public function testDropForeign() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropForeign('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" drop constraint "foo"', $statements[0]); @@ -182,9 +186,9 @@ public function testDropForeign() public function testDropConstrainedForeignId() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropConstrainedForeignId('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('alter table "users" drop constraint "users_foo_foreign"', $statements[0]); @@ -193,9 +197,9 @@ public function testDropConstrainedForeignId() public function testDropTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertStringContainsString('alter table "users" drop column "created_at", "updated_at"', $statements[0]); @@ -203,9 +207,9 @@ public function testDropTimestamps() public function testDropTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dropTimestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertStringContainsString('alter table "users" drop column "created_at", "updated_at"', $statements[0]); @@ -213,9 +217,9 @@ public function testDropTimestampsTz() public function testDropMorphs() { - $blueprint = new Blueprint('photos'); + $blueprint = new Blueprint($this->getConnection(), 'photos'); $blueprint->dropMorphs('imageable'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('drop index "photos_imageable_type_imageable_id_index" on "photos"', $statements[0]); @@ -224,9 +228,9 @@ public function testDropMorphs() public function testRenameTable() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rename('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('sp_rename N\'"users"\', "foo"', $statements[0]); @@ -234,9 +238,9 @@ public function testRenameTable() public function testRenameIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->renameIndex('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('sp_rename N\'"users"."foo"\', "bar", N\'INDEX\'', $statements[0]); @@ -244,9 +248,9 @@ public function testRenameIndex() public function testAddingPrimaryKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->primary('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add constraint "bar" primary key ("foo")', $statements[0]); @@ -254,9 +258,9 @@ public function testAddingPrimaryKey() public function testAddingUniqueKey() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->unique('foo', 'bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create unique index "bar" on "users" ("foo")', $statements[0]); @@ -264,9 +268,9 @@ public function testAddingUniqueKey() public function testAddingIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->index(['foo', 'bar'], 'baz'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "baz" on "users" ("foo", "bar")', $statements[0]); @@ -274,9 +278,9 @@ public function testAddingIndex() public function testAddingSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->spatialIndex('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create spatial index "geo_coordinates_spatialindex" on "geo" ("coordinates")', $statements[0]); @@ -284,9 +288,9 @@ public function testAddingSpatialIndex() public function testAddingFluentSpatialIndex() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates', 'point')->spatialIndex(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame('create spatial index "geo_coordinates_spatialindex" on "geo" ("coordinates")', $statements[1]); @@ -294,9 +298,9 @@ public function testAddingFluentSpatialIndex() public function testAddingRawIndex() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rawIndex('(function(column))', 'raw_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('create index "raw_index" on "users" ((function(column)))', $statements[0]); @@ -304,9 +308,9 @@ public function testAddingRawIndex() public function testAddingIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "id" int not null identity primary key', $statements[0]); @@ -314,9 +318,9 @@ public function testAddingIncrementingID() public function testAddingSmallIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "id" smallint not null identity primary key', $statements[0]); @@ -324,9 +328,9 @@ public function testAddingSmallIncrementingID() public function testAddingMediumIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "id" int not null identity primary key', $statements[0]); @@ -334,16 +338,16 @@ public function testAddingMediumIncrementingID() public function testAddingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "id" bigint not null identity primary key', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->id('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" bigint not null identity primary key', $statements[0]); @@ -351,14 +355,14 @@ public function testAddingID() public function testAddingForeignID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignId = $blueprint->foreignId('foo'); $blueprint->foreignId('company_id')->constrained(); $blueprint->foreignId('laravel_idea_id')->constrained(); $blueprint->foreignId('team_id')->references('id')->on('teams'); $blueprint->foreignId('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignId); $this->assertSame([ @@ -376,9 +380,9 @@ public function testAddingForeignID() public function testAddingForeignIdSpecifyingIndexNameInConstraint() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->foreignId('company_id')->constrained(indexName: 'my_index'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertSame([ 'alter table "users" add "company_id" bigint not null', 'alter table "users" add constraint "my_index" foreign key ("company_id") references "companies" ("id")', @@ -387,9 +391,9 @@ public function testAddingForeignIdSpecifyingIndexNameInConstraint() public function testAddingBigIncrementingID() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "id" bigint not null identity primary key', $statements[0]); @@ -397,23 +401,23 @@ public function testAddingBigIncrementingID() public function testAddingString() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(255) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(100) not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->string('foo', 100)->nullable()->default('bar'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(100) null default \'bar\'', $statements[0]); @@ -421,9 +425,9 @@ public function testAddingString() public function testAddingText() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->text('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(max) not null', $statements[0]); @@ -431,16 +435,16 @@ public function testAddingText() public function testAddingBigInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" bigint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->bigInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" bigint not null identity primary key', $statements[0]); @@ -448,16 +452,16 @@ public function testAddingBigInteger() public function testAddingInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" int not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->integer('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" int not null identity primary key', $statements[0]); @@ -465,16 +469,16 @@ public function testAddingInteger() public function testAddingMediumInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" int not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->mediumInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" int not null identity primary key', $statements[0]); @@ -482,16 +486,16 @@ public function testAddingMediumInteger() public function testAddingTinyInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" tinyint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->tinyInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" tinyint not null identity primary key', $statements[0]); @@ -499,16 +503,16 @@ public function testAddingTinyInteger() public function testAddingSmallInteger() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" smallint not null', $statements[0]); - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->smallInteger('foo', true); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" smallint not null identity primary key', $statements[0]); @@ -516,9 +520,9 @@ public function testAddingSmallInteger() public function testAddingFloat() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->float('foo', 5); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" float(5) not null', $statements[0]); @@ -526,9 +530,9 @@ public function testAddingFloat() public function testAddingDouble() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->double('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" double precision not null', $statements[0]); @@ -536,9 +540,9 @@ public function testAddingDouble() public function testAddingDecimal() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->decimal('foo', 5, 2); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" decimal(5, 2) not null', $statements[0]); @@ -546,9 +550,9 @@ public function testAddingDecimal() public function testAddingBoolean() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->boolean('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" bit not null', $statements[0]); @@ -556,9 +560,9 @@ public function testAddingBoolean() public function testAddingEnum() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->enum('role', ['member', 'admin']); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "role" nvarchar(255) check ("role" in (N\'member\', N\'admin\')) not null', $statements[0]); @@ -566,9 +570,9 @@ public function testAddingEnum() public function testAddingJson() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->json('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(max) not null', $statements[0]); @@ -576,9 +580,9 @@ public function testAddingJson() public function testAddingJsonb() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->jsonb('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(max) not null', $statements[0]); @@ -586,9 +590,9 @@ public function testAddingJsonb() public function testAddingDate() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->date('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" date not null', $statements[0]); @@ -596,126 +600,126 @@ public function testAddingDate() public function testAddingYear() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->year('birth_year'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "birth_year" int not null', $statements[0]); } public function testAddingDateTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" datetime not null', $statements[0]); } public function testAddingDateTimeWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTime('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" datetime2(1) not null', $statements[0]); } public function testAddingDateTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" datetimeoffset not null', $statements[0]); } public function testAddingDateTimeTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->dateTimeTz('foo', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" datetimeoffset(1) not null', $statements[0]); } public function testAddingTime() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" time not null', $statements[0]); } public function testAddingTimeWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->time('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" time(1) not null', $statements[0]); } public function testAddingTimeTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" time not null', $statements[0]); } public function testAddingTimeTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timeTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" time(1) not null', $statements[0]); } public function testAddingTimestamp() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" datetime not null', $statements[0]); } public function testAddingTimestampWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamp('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" datetime2(1) not null', $statements[0]); } public function testAddingTimestampTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" datetimeoffset not null', $statements[0]); } public function testAddingTimestampTzWithPrecision() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampTz('created_at', 1); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "created_at" datetimeoffset(1) not null', $statements[0]); } public function testAddingTimestamps() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestamps(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table "users" add "created_at" datetime null', @@ -725,9 +729,9 @@ public function testAddingTimestamps() public function testAddingTimestampsTz() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->timestampsTz(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(2, $statements); $this->assertSame([ 'alter table "users" add "created_at" datetimeoffset null', @@ -737,9 +741,9 @@ public function testAddingTimestampsTz() public function testAddingRememberToken() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->rememberToken(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "remember_token" nvarchar(100) null', $statements[0]); @@ -747,9 +751,9 @@ public function testAddingRememberToken() public function testAddingBinary() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->binary('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" varbinary(max) not null', $statements[0]); @@ -757,9 +761,9 @@ public function testAddingBinary() public function testAddingUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" uniqueidentifier not null', $statements[0]); @@ -767,9 +771,9 @@ public function testAddingUuid() public function testAddingUuidDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->uuid(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "uuid" uniqueidentifier not null', $statements[0]); @@ -777,14 +781,14 @@ public function testAddingUuidDefaultsColumnName() public function testAddingForeignUuid() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $foreignId = $blueprint->foreignUuid('foo'); $blueprint->foreignUuid('company_id')->constrained(); $blueprint->foreignUuid('laravel_idea_id')->constrained(); $blueprint->foreignUuid('team_id')->references('id')->on('teams'); $blueprint->foreignUuid('team_column_id')->constrained('teams'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertInstanceOf(ForeignIdColumnDefinition::class, $foreignId); $this->assertSame([ @@ -802,9 +806,9 @@ public function testAddingForeignUuid() public function testAddingIpAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(45) not null', $statements[0]); @@ -812,9 +816,9 @@ public function testAddingIpAddress() public function testAddingIpAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->ipAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "ip_address" nvarchar(45) not null', $statements[0]); @@ -822,9 +826,9 @@ public function testAddingIpAddressDefaultsColumnName() public function testAddingMacAddress() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress('foo'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "foo" nvarchar(17) not null', $statements[0]); @@ -832,9 +836,9 @@ public function testAddingMacAddress() public function testAddingMacAddressDefaultsColumnName() { - $blueprint = new Blueprint('users'); + $blueprint = new Blueprint($this->getConnection(), 'users'); $blueprint->macAddress(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "users" add "mac_address" nvarchar(17) not null', $statements[0]); @@ -842,9 +846,9 @@ public function testAddingMacAddressDefaultsColumnName() public function testAddingGeometry() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geometry('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add "coordinates" geometry not null', $statements[0]); @@ -852,9 +856,9 @@ public function testAddingGeometry() public function testAddingGeography() { - $blueprint = new Blueprint('geo'); + $blueprint = new Blueprint($this->getConnection(), 'geo'); $blueprint->geography('coordinates'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(1, $statements); $this->assertSame('alter table "geo" add "coordinates" geography not null', $statements[0]); @@ -862,11 +866,11 @@ public function testAddingGeography() public function testAddingGeneratedColumn() { - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->computed('discounted_virtual', 'price - 5'); $blueprint->computed('discounted_stored', 'price - 5')->persisted(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ 'alter table "products" add "price" int not null', @@ -874,11 +878,11 @@ public function testAddingGeneratedColumn() 'alter table "products" add "discounted_stored" as (price - 5) persisted', ], $statements); - $blueprint = new Blueprint('products'); + $blueprint = new Blueprint($this->getConnection(), 'products'); $blueprint->integer('price'); $blueprint->computed('discounted_virtual', new Expression('price - 5')); $blueprint->computed('discounted_stored', new Expression('price - 5'))->persisted(); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql(); $this->assertCount(3, $statements); $this->assertSame([ 'alter table "products" add "price" int not null', @@ -945,13 +949,26 @@ public function testDropDatabaseIfExists() ); } - protected function getConnection() - { - return m::mock(Connection::class); + protected function getConnection( + ?SqlServerGrammar $grammar = null, + ?SqlServerBuilder $builder = null + ) { + $grammar ??= $this->getGrammar(); + $builder ??= $this->getBuilder(); + + return m::mock(Connection::class) + ->shouldReceive('getSchemaGrammar')->andReturn($grammar) + ->shouldReceive('getSchemaBuilder')->andReturn($builder) + ->getMock(); } public function getGrammar() { return new SqlServerGrammar; } + + public function getBuilder() + { + return mock(SqlServerBuilder::class); + } } diff --git a/tests/Integration/Database/DatabaseSchemaBlueprintTest.php b/tests/Integration/Database/DatabaseSchemaBlueprintTest.php index dbe7a470fade..14693c116692 100644 --- a/tests/Integration/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Integration/Database/DatabaseSchemaBlueprintTest.php @@ -2,7 +2,9 @@ namespace Illuminate\Tests\Integration\Database; +use Closure; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Grammars\Grammar; use Illuminate\Database\Schema\Grammars\MySqlGrammar; use Illuminate\Database\Schema\Grammars\PostgresGrammar; use Illuminate\Database\Schema\Grammars\SQLiteGrammar; @@ -33,12 +35,12 @@ public function testRenamingAndChangingColumnsWork() $table->string('age'); }); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new SQLiteGrammar, 'users', function ($table) { $table->renameColumn('name', 'first_name'); $table->integer('age')->change(); }); - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $queries = $blueprint->toSql(); $expected = [ 'alter table "users" rename column "name" to "first_name"', @@ -72,10 +74,7 @@ public function testRenamingColumnsWorks() public function testNativeColumnModifyingOnMySql() { - $connection = DB::connection(); - $schema = $connection->getSchemaBuilder(); - - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new MySqlGrammar, 'users', function ($table) { $table->double('amount')->nullable()->invisible()->after('name')->change(); $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->useCurrentOnUpdate()->change(); $table->enum('difficulty', ['easy', 'hard'])->default('easy')->charset('utf8mb4')->collation('unicode')->change(); @@ -92,15 +91,12 @@ public function testNativeColumnModifyingOnMySql() 'alter table `users` change `old_name` `new_name` varchar(50) not null', "alter table `users` modify `id` bigint unsigned not null auto_increment comment 'my comment' first", 'alter table `users` auto_increment = 10', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $blueprint->toSql()); } public function testNativeColumnModifyingOnPostgreSql() { - $connection = DB::connection(); - $schema = $connection->getSchemaBuilder(); - - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { $table->integer('code')->autoIncrement()->from(10)->comment('my comment')->change(); }); @@ -110,9 +106,9 @@ public function testNativeColumnModifyingOnPostgreSql() .'alter column "code" set not null', 'alter sequence users_code_seq restart with 10', 'comment on column "users"."code" is \'my comment\'', - ], $blueprint->toSql($connection, new PostgresGrammar)); + ], $blueprint->toSql()); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { $table->char('name', 40)->nullable()->default('easy')->collation('unicode')->change(); }); @@ -123,9 +119,9 @@ public function testNativeColumnModifyingOnPostgreSql() .'alter column "name" set default \'easy\', ' .'alter column "name" drop identity if exists', 'comment on column "users"."name" is NULL', - ], $blueprint->toSql($connection, new PostgresGrammar)); + ], $blueprint->toSql()); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { $table->integer('foo')->generatedAs('expression')->always()->change(); }); @@ -137,9 +133,9 @@ public function testNativeColumnModifyingOnPostgreSql() .'alter column "foo" drop identity if exists, ' .'alter column "foo" add generated always as identity (expression)', 'comment on column "users"."foo" is NULL', - ], $blueprint->toSql($connection, new PostgresGrammar)); + ], $blueprint->toSql()); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { $table->geometry('foo', 'point', 1234)->change(); }); @@ -150,9 +146,9 @@ public function testNativeColumnModifyingOnPostgreSql() .'alter column "foo" drop default, ' .'alter column "foo" drop identity if exists', 'comment on column "users"."foo" is NULL', - ], $blueprint->toSql($connection, new PostgresGrammar)); + ], $blueprint->toSql()); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { $table->timestamp('added_at', 2)->useCurrent()->storedAs(null)->change(); }); @@ -164,15 +160,12 @@ public function testNativeColumnModifyingOnPostgreSql() .'alter column "added_at" drop expression if exists, ' .'alter column "added_at" drop identity if exists', 'comment on column "users"."added_at" is NULL', - ], $blueprint->toSql($connection, new PostgresGrammar)); + ], $blueprint->toSql()); } public function testNativeColumnModifyingOnSqlServer() { - $connection = DB::connection(); - $schema = $connection->getSchemaBuilder(); - - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new SqlServerGrammar, 'users', function ($table) { $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->change(); }); @@ -180,9 +173,9 @@ public function testNativeColumnModifyingOnSqlServer() "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('added_at') AND [default_object_id] <> 0;EXEC(@sql)", 'alter table "users" alter column "added_at" datetime2(4) not null', 'alter table "users" add default CURRENT_TIMESTAMP for "added_at"', - ], $blueprint->toSql($connection, new SqlServerGrammar)); + ], $blueprint->toSql()); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new SqlServerGrammar, 'users', function ($table) { $table->char('name', 40)->nullable()->default('easy')->collation('unicode')->change(); }); @@ -190,16 +183,16 @@ public function testNativeColumnModifyingOnSqlServer() "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('name') AND [default_object_id] <> 0;EXEC(@sql)", 'alter table "users" alter column "name" nchar(40) collate unicode null', 'alter table "users" add default \'easy\' for "name"', - ], $blueprint->toSql($connection, new SqlServerGrammar)); + ], $blueprint->toSql()); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new SqlServerGrammar, 'users', function ($table) { $table->integer('foo')->change(); }); $this->assertEquals([ "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('foo') AND [default_object_id] <> 0;EXEC(@sql)", 'alter table "users" alter column "foo" int not null', - ], $blueprint->toSql($connection, new SqlServerGrammar)); + ], $blueprint->toSql()); } public function testChangingColumnWithCollationWorks() @@ -208,15 +201,15 @@ public function testChangingColumnWithCollationWorks() $table->string('age'); }); - $blueprint = new Blueprint('users', function ($table) { + $blueprint = $this->getBlueprint(new SQLiteGrammar, 'users', function ($table) { $table->integer('age')->collation('RTRIM')->change(); }); - $blueprint2 = new Blueprint('users', function ($table) { + $blueprint2 = $this->getBlueprint(new SQLiteGrammar, 'users', function ($table) { $table->integer('age')->collation('NOCASE')->change(); }); - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $queries = $blueprint->toSql(); $expected = [ 'create table "__temp__users" ("age" integer not null collate \'RTRIM\')', @@ -227,7 +220,7 @@ public function testChangingColumnWithCollationWorks() $this->assertEquals($expected, $queries); - $queries = $blueprint2->toSql(DB::connection(), new SQLiteGrammar); + $queries = $blueprint2->toSql(); $expected = [ 'create table "__temp__users" ("age" integer not null collate \'NOCASE\')', @@ -245,11 +238,11 @@ public function testChangingCharColumnsWork() $table->string('name'); }); - $blueprint = new Blueprint('users', function ($table) { - $table->char('name', 50)->change(); - }); - - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->text('changed_col')->change(); + })->toSql(); + }; $expected = [ 'create table "__temp__users" ("name" varchar not null)', @@ -258,7 +251,7 @@ public function testChangingCharColumnsWork() 'alter table "__temp__users" rename to "users"', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); } public function testChangingPrimaryAutoincrementColumnsToNonAutoincrementColumnsWork() @@ -267,11 +260,11 @@ public function testChangingPrimaryAutoincrementColumnsToNonAutoincrementColumns $table->increments('id'); }); - $blueprint = new Blueprint('users', function ($table) { - $table->binary('id')->change(); - }); - - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->binary('id')->change(); + })->toSql(); + }; $expected = [ 'create table "__temp__users" ("id" blob not null, primary key ("id"))', @@ -280,7 +273,7 @@ public function testChangingPrimaryAutoincrementColumnsToNonAutoincrementColumns 'alter table "__temp__users" rename to "users"', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); } public function testChangingDoubleColumnsWork() @@ -289,11 +282,11 @@ public function testChangingDoubleColumnsWork() $table->integer('price'); }); - $blueprint = new Blueprint('products', function ($table) { - $table->double('price')->change(); - }); - - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'products', function ($table) { + $table->double('price')->change(); + })->toSql(); + }; $expected = [ 'create table "__temp__products" ("price" double not null)', @@ -302,23 +295,23 @@ public function testChangingDoubleColumnsWork() 'alter table "__temp__products" rename to "products"', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); } public function testChangingColumnsWithDefaultWorks() { - DB::connection()->getSchemaBuilder()->create('products', function (Blueprint $table) { + DB::connection()->getSchemaBuilder()->create('products', function ($table) { $table->integer('changed_col'); $table->timestamp('timestamp_col')->useCurrent(); $table->integer('integer_col')->default(123); $table->string('string_col')->default('value'); }); - $blueprint = new Blueprint('products', function ($table) { - $table->text('changed_col')->change(); - }); - - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'products', function ($table) { + $table->text('changed_col')->change(); + })->toSql(); + }; $expected = [ 'create table "__temp__products" ("changed_col" text not null, "timestamp_col" datetime not null default CURRENT_TIMESTAMP, "integer_col" integer not null default \'123\', "string_col" varchar not null default \'value\')', @@ -327,7 +320,7 @@ public function testChangingColumnsWithDefaultWorks() 'alter table "__temp__products" rename to "products"', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); } public function testRenameIndexWorks() @@ -336,47 +329,40 @@ public function testRenameIndexWorks() $table->string('name'); $table->string('age'); }); - DB::connection()->getSchemaBuilder()->table('users', function ($table) { $table->index(['name'], 'index1'); }); - $blueprint = new Blueprint('users', function ($table) { - $table->renameIndex('index1', 'index2'); - }); - - $queries = $blueprint->toSql(DB::connection(), new SQLiteGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->renameIndex('index1', 'index2'); + })->toSql(); + }; $expected = [ 'drop index "index1"', 'create index "index2" on "users" ("name")', ]; - $this->assertEquals($expected, $queries); - - $queries = $blueprint->toSql(DB::connection(), new SqlServerGrammar); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); $expected = [ 'sp_rename N\'"users"."index1"\', "index2", N\'INDEX\'', ]; - $this->assertEquals($expected, $queries); - - $queries = $blueprint->toSql(DB::connection(), new MySqlGrammar); + $this->assertEquals($expected, $getSql(new SqlServerGrammar)); $expected = [ 'alter table `users` rename index `index1` to `index2`', ]; - $this->assertEquals($expected, $queries); - - $queries = $blueprint->toSql(DB::connection(), new PostgresGrammar); + $this->assertEquals($expected, $getSql(new MySqlGrammar)); $expected = [ 'alter index "index1" rename to "index2"', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new PostgresGrammar)); } public function testAddUniqueIndexWithoutNameWorks() @@ -385,24 +371,18 @@ public function testAddUniqueIndexWithoutNameWorks() $table->string('name')->nullable(); }); - $blueprintMySql = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique()->change(); - }); - - $queries = $blueprintMySql->toSql(DB::connection(), new MySqlGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->string('name')->nullable()->unique()->change(); + })->toSql(); + }; $expected = [ 'alter table `users` modify `name` varchar(255) null', 'alter table `users` add unique `users_name_unique`(`name`)', ]; - $this->assertEquals($expected, $queries); - - $blueprintPostgres = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique()->change(); - }); - - $queries = $blueprintPostgres->toSql(DB::connection(), new PostgresGrammar); + $this->assertEquals($expected, $getSql(new MySqlGrammar)); $expected = [ 'alter table "users" alter column "name" type varchar(255), alter column "name" drop not null, alter column "name" drop default, alter column "name" drop identity if exists', @@ -410,13 +390,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'comment on column "users"."name" is NULL', ]; - $this->assertEquals($expected, $queries); - - $blueprintSQLite = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique()->change(); - }); - - $queries = $blueprintSQLite->toSql(DB::connection(), new SQLiteGrammar); + $this->assertEquals($expected, $getSql(new PostgresGrammar)); $expected = [ 'create table "__temp__users" ("name" varchar)', @@ -426,13 +400,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'create unique index "users_name_unique" on "users" ("name")', ]; - $this->assertEquals($expected, $queries); - - $blueprintSqlServer = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique()->change(); - }); - - $queries = $blueprintSqlServer->toSql(DB::connection(), new SqlServerGrammar); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); $expected = [ "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('name') AND [default_object_id] <> 0;EXEC(@sql)", @@ -440,7 +408,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'create unique index "users_name_unique" on "users" ("name")', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new SqlServerGrammar)); } public function testAddUniqueIndexWithNameWorks() @@ -449,24 +417,18 @@ public function testAddUniqueIndexWithNameWorks() $table->string('name')->nullable(); }); - $blueprintMySql = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique('index1')->change(); - }); - - $queries = $blueprintMySql->toSql(DB::connection(), new MySqlGrammar); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->unsignedInteger('name')->nullable()->unique('index1')->change(); + })->toSql(); + }; $expected = [ - 'alter table `users` modify `name` varchar(255) null', + 'alter table `users` modify `name` int unsigned null', 'alter table `users` add unique `index1`(`name`)', ]; - $this->assertEquals($expected, $queries); - - $blueprintPostgres = new Blueprint('users', function ($table) { - $table->unsignedInteger('name')->nullable()->unique('index1')->change(); - }); - - $queries = $blueprintPostgres->toSql(DB::connection(), new PostgresGrammar); + $this->assertEquals($expected, $getSql(new MySqlGrammar)); $expected = [ 'alter table "users" alter column "name" type integer, alter column "name" drop not null, alter column "name" drop default, alter column "name" drop identity if exists', @@ -474,13 +436,7 @@ public function testAddUniqueIndexWithNameWorks() 'comment on column "users"."name" is NULL', ]; - $this->assertEquals($expected, $queries); - - $blueprintSQLite = new Blueprint('users', function ($table) { - $table->unsignedInteger('name')->nullable()->unique('index1')->change(); - }); - - $queries = $blueprintSQLite->toSql(DB::connection(), new SQLiteGrammar); + $this->assertEquals($expected, $getSql(new PostgresGrammar)); $expected = [ 'create table "__temp__users" ("name" integer)', @@ -490,13 +446,7 @@ public function testAddUniqueIndexWithNameWorks() 'create unique index "index1" on "users" ("name")', ]; - $this->assertEquals($expected, $queries); - - $blueprintSqlServer = new Blueprint('users', function ($table) { - $table->unsignedInteger('name')->nullable()->unique('index1')->change(); - }); - - $queries = $blueprintSqlServer->toSql(DB::connection(), new SqlServerGrammar); + $this->assertEquals($expected, $getSql(new SQLiteGrammar)); $expected = [ "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('name') AND [default_object_id] <> 0;EXEC(@sql)", @@ -504,7 +454,7 @@ public function testAddUniqueIndexWithNameWorks() 'create unique index "index1" on "users" ("name")', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $getSql(new SqlServerGrammar)); } public function testAddColumnNamedCreateWorks() @@ -522,46 +472,34 @@ public function testAddColumnNamedCreateWorks() public function testDropIndexOnColumnChangeWorks() { - $connection = DB::connection(); - - $connection->getSchemaBuilder()->create('users', function ($table) { + DB::connection()->getSchemaBuilder()->create('users', function ($table) { $table->string('name')->nullable(); }); - $blueprint = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique(false)->change(); - }); + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'users', function ($table) { + $table->string('name')->nullable()->unique(false)->change(); + })->toSql(); + }; $this->assertContains( 'alter table `users` drop index `users_name_unique`', - $blueprint->toSql($connection, new MySqlGrammar) + $getSql(new MySqlGrammar), ); - $blueprint = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique(false)->change(); - }); - $this->assertContains( 'alter table "users" drop constraint "users_name_unique"', - $blueprint->toSql($connection, new PostgresGrammar) + $getSql(new PostgresGrammar), ); - $blueprint = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique(false)->change(); - }); - $this->assertContains( 'drop index "users_name_unique"', - $blueprint->toSql($connection, new SQLiteGrammar) + $getSql(new SQLiteGrammar), ); - $blueprint = new Blueprint('users', function ($table) { - $table->string('name')->nullable()->unique(false)->change(); - }); - $this->assertContains( 'drop index "users_name_unique" on "users"', - $blueprint->toSql($connection, new SqlServerGrammar) + $getSql(new SqlServerGrammar), ); } @@ -595,4 +533,14 @@ public function testItEnsuresDroppingForeignKeyIsAvailable() $table->dropForeign('something'); }); } + + protected function getBlueprint( + Grammar $grammar, + string $table, + Closure $callback, + ): Blueprint { + $connection = DB::connection()->setSchemaGrammar($grammar); + + return new Blueprint($connection, $table, $callback); + } } diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index b0c1f67f3c9a..02745a02050a 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -4,7 +4,6 @@ use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; @@ -53,11 +52,11 @@ public function testChangeToTinyInteger() $table->string('test_column'); }); - $blueprint = new Blueprint('test', function (Blueprint $table) { + $blueprint = new Blueprint($this->getConnection(), 'test', function (Blueprint $table) { $table->tinyInteger('test_column')->change(); }); - $blueprint->build($this->getConnection(), new SQLiteGrammar); + $blueprint->build(); $this->assertSame('integer', Schema::getColumnType('test', 'test_column')); } @@ -73,17 +72,15 @@ public function testChangeToTextColumn() }); foreach (['tinyText', 'text', 'mediumText', 'longText'] as $type) { - $blueprint = new Blueprint('test', function ($table) use ($type) { + $blueprint = new Blueprint($this->getConnection(), 'test', function ($table) use ($type) { $table->$type('test_column')->change(); }); - $queries = $blueprint->toSql($this->getConnection(), $this->getConnection()->getSchemaGrammar()); - $uppercase = strtolower($type); $expected = ["alter table `test` modify `test_column` $uppercase not null"]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $blueprint->toSql()); } } @@ -98,17 +95,15 @@ public function testChangeTextColumnToTextColumn() }); foreach (['tinyText', 'mediumText', 'longText'] as $type) { - $blueprint = new Blueprint('test', function ($table) use ($type) { + $blueprint = new Blueprint($this->getConnection(), 'test', function ($table) use ($type) { $table->$type('test_column')->change(); }); - $queries = $blueprint->toSql($this->getConnection(), $this->getConnection()->getSchemaGrammar()); - $lowercase = strtolower($type); $expected = ["alter table `test` modify `test_column` $lowercase not null"]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $blueprint->toSql()); } } @@ -125,15 +120,13 @@ public function testModifyNullableColumn() $table->string('nullable_column_to_not_null')->nullable(); }); - $blueprint = new Blueprint('test', function ($table) { + $blueprint = new Blueprint($this->getConnection(), 'test', function ($table) { $table->text('not_null_column_to_not_null')->change(); $table->text('not_null_column_to_nullable')->nullable()->change(); $table->text('nullable_column_to_nullable')->nullable()->change(); $table->text('nullable_column_to_not_null')->change(); }); - $queries = $blueprint->toSql($this->getConnection(), $this->getConnection()->getSchemaGrammar()); - $expected = [ 'alter table `test` modify `not_null_column_to_not_null` text not null', 'alter table `test` modify `not_null_column_to_nullable` text null', @@ -141,7 +134,7 @@ public function testModifyNullableColumn() 'alter table `test` modify `nullable_column_to_not_null` text not null', ]; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $blueprint->toSql()); } public function testChangeNullableColumn() diff --git a/tests/Integration/Database/TimestampTypeTest.php b/tests/Integration/Database/TimestampTypeTest.php index 210de93546ec..e43ad1c83b87 100644 --- a/tests/Integration/Database/TimestampTypeTest.php +++ b/tests/Integration/Database/TimestampTypeTest.php @@ -59,14 +59,12 @@ public function testChangeStringColumnToTimestampColumn() $table->string('string_to_timestamp'); }); - $blueprint = new Blueprint('test', function ($table) { + $blueprint = new Blueprint($this->getConnection(), 'test', function ($table) { $table->timestamp('string_to_timestamp')->nullable()->change(); }); - $queries = $blueprint->toSql($this->getConnection(), $this->getConnection()->getSchemaGrammar()); - $expected = ['alter table `test` modify `string_to_timestamp` timestamp null']; - $this->assertEquals($expected, $queries); + $this->assertEquals($expected, $blueprint->toSql()); } } From 2f4ebf146a7e21926a4b0fed9db2b8a0d2946e98 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Wed, 4 Sep 2024 10:06:01 -0400 Subject: [PATCH 015/455] [12.x] Improved algorithm for Number::pairs() (#52641) * Update algo * Update Number.php * Update SupportNumberTest.php --- src/Illuminate/Support/Number.php | 15 ++++++++------- tests/Support/SupportNumberTest.php | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Support/Number.php b/src/Illuminate/Support/Number.php index 0b52a7912ae9..3161b38dac3f 100644 --- a/src/Illuminate/Support/Number.php +++ b/src/Illuminate/Support/Number.php @@ -235,23 +235,24 @@ public static function clamp(int|float $number, int|float $min, int|float $max) /** * Split the given number into pairs of min/max values. * - * @param int|float $to - * @param int|float $by - * @param int|float $offset + * @param int|float $to + * @param int|float $by + * @param int|float $start + * @param int|float $offset * @return array */ - public static function pairs(int|float $to, int|float $by, int|float $offset = 1) + public static function pairs(int|float $to, int|float $by, int|float $start = 0, int|float $offset = 1) { $output = []; - for ($lower = 0; $lower < $to; $lower += $by) { - $upper = $lower + $by; + for ($lower = $start; $lower < $to; $lower += $by) { + $upper = $lower + $by - $offset; if ($upper > $to) { $upper = $to; } - $output[] = [$lower + $offset, $upper]; + $output[] = [$lower, $upper]; } return $output; diff --git a/tests/Support/SupportNumberTest.php b/tests/Support/SupportNumberTest.php index cf1796bfaa58..9f2f7cb2b55b 100644 --- a/tests/Support/SupportNumberTest.php +++ b/tests/Support/SupportNumberTest.php @@ -289,8 +289,17 @@ public function testSummarize() public function testPairs() { - $this->assertSame([[1, 10], [11, 20], [21, 25]], Number::pairs(25, 10)); - $this->assertSame([[0, 10], [10, 20], [20, 25]], Number::pairs(25, 10, 0)); - $this->assertSame([[0, 2.5], [2.5, 5.0], [5.0, 7.5], [7.5, 10.0]], Number::pairs(10, 2.5, 0)); + $this->assertSame([[0, 10], [10, 20], [20, 25]], Number::pairs(25, 10, 0, 0)); + $this->assertSame([[0, 9], [10, 19], [20, 25]], Number::pairs(25, 10, 0, 1)); + $this->assertSame([[1, 11], [11, 21], [21, 25]], Number::pairs(25, 10, 1, 0)); + $this->assertSame([[1, 10], [11, 20], [21, 25]], Number::pairs(25, 10, 1, 1)); + $this->assertSame([[0, 1000], [1000, 2000], [2000, 2500]], Number::pairs(2500, 1000, 0, 0)); + $this->assertSame([[0, 999], [1000, 1999], [2000, 2500]], Number::pairs(2500, 1000, 0, 1)); + $this->assertSame([[1, 1001], [1001, 2001], [2001, 2500]], Number::pairs(2500, 1000, 1, 0)); + $this->assertSame([[1, 1000], [1001, 2000], [2001, 2500]], Number::pairs(2500, 1000, 1, 1)); + $this->assertSame([[0, 2.5], [2.5, 5.0], [5.0, 7.5], [7.5, 10.0]], Number::pairs(10, 2.5, 0, 0)); + $this->assertSame([[0, 2.0], [2.5, 4.5], [5.0, 7.0], [7.5, 9.5]], Number::pairs(10, 2.5, 0, 0.5)); + $this->assertSame([[0.5, 3.0], [3.0, 5.5], [5.5, 8.0], [8.0, 10]], Number::pairs(10, 2.5, 0.5, 0)); + $this->assertSame([[0.5, 2.5], [3.0, 5.0], [5.5, 7.5], [8.0, 10.0]], Number::pairs(10, 2.5, 0.5, 0.5)); } } From a211abdbc066a79625bb8ba5bc8f97f0d83953e7 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 4 Sep 2024 14:06:40 +0000 Subject: [PATCH 016/455] Apply fixes from StyleCI --- src/Illuminate/Support/Number.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Support/Number.php b/src/Illuminate/Support/Number.php index 3161b38dac3f..60141e719fe8 100644 --- a/src/Illuminate/Support/Number.php +++ b/src/Illuminate/Support/Number.php @@ -235,10 +235,10 @@ public static function clamp(int|float $number, int|float $min, int|float $max) /** * Split the given number into pairs of min/max values. * - * @param int|float $to - * @param int|float $by - * @param int|float $start - * @param int|float $offset + * @param int|float $to + * @param int|float $by + * @param int|float $start + * @param int|float $offset * @return array */ public static function pairs(int|float $to, int|float $by, int|float $start = 0, int|float $offset = 1) From 9d3b365c6d020947fa80575949e6478bec2a244a Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 25 Sep 2024 09:50:56 +0800 Subject: [PATCH 017/455] wip Signed-off-by: Mior Muhammad Zaki --- .github/workflows/databases-nightly.yml | 4 ++-- .github/workflows/databases.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/databases-nightly.yml b/.github/workflows/databases-nightly.yml index 12f7b87352c6..f194ed8743c6 100644 --- a/.github/workflows/databases-nightly.yml +++ b/.github/workflows/databases-nightly.yml @@ -36,7 +36,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -82,7 +82,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 diff --git a/.github/workflows/databases.yml b/.github/workflows/databases.yml index f4d0ef06d1a5..345f0420a6ac 100644 --- a/.github/workflows/databases.yml +++ b/.github/workflows/databases.yml @@ -229,7 +229,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 @@ -324,7 +324,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 From 87932fbb93522d46bacead9966206d064c0f66f4 Mon Sep 17 00:00:00 2001 From: Felipe Hertzer Date: Tue, 1 Oct 2024 00:39:41 +1000 Subject: [PATCH 018/455] Removed duplicated prefix when use dynamodb cache lock (#52986) Close #52954 This PR remove the duplicated prefix when use DynamoDB as cache drive and try to lock DynamoDB Key now: laravel_cache_laravel_cache_my-lock DynamoDB Key after: laravel_cache_my-lock --- src/Illuminate/Cache/DynamoDbStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/DynamoDbStore.php b/src/Illuminate/Cache/DynamoDbStore.php index 88c7cf3be436..555470fd97c9 100644 --- a/src/Illuminate/Cache/DynamoDbStore.php +++ b/src/Illuminate/Cache/DynamoDbStore.php @@ -412,7 +412,7 @@ public function forever($key, $value) */ public function lock($name, $seconds = 0, $owner = null) { - return new DynamoDbLock($this, $this->prefix.$name, $seconds, $owner); + return new DynamoDbLock($this, $name, $seconds, $owner); } /** From 575af330ba2cd6a3381ffc74a4c0d047d33f7c92 Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Tue, 8 Oct 2024 18:39:41 +0000 Subject: [PATCH 019/455] Update facade docblocks --- src/Illuminate/Support/Facades/Schema.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index a7feff2e7045..fccccaa2fbd1 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -4,6 +4,7 @@ /** * @method static void defaultStringLength(int $length) + * @method static void defaultTimePrecision(int|null $precision) * @method static void defaultMorphKeyType(string $type) * @method static void morphUsingUuids() * @method static void morphUsingUlids() From 7299a1d791543439b12823603db6e239bdd8dc41 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 14 Oct 2024 20:56:14 +0800 Subject: [PATCH 020/455] [12.x] Test Improvements (#53150) * Add missing docblock * Fixes new tests to be compatible with 12.x code Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Database/Schema/Blueprint.php | 1 + tests/Database/DatabaseMySqlSchemaGrammarTest.php | 2 +- tests/Database/DatabasePostgresSchemaGrammarTest.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index ac1be20d152e..845d62c38cb2 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -99,6 +99,7 @@ class Blueprint /** * Create a new schema blueprint. * + * @param \Illuminate\Database\Connection $connection * @param string $table * @param \Closure|null $callback * @param string $prefix diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index bac638d3e421..4615e419e205 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1326,7 +1326,7 @@ public function testAddingComment() public function testAddingVector() { - $blueprint = new Blueprint('embeddings'); + $blueprint = new Blueprint($this->getConnection(), 'embeddings'); $blueprint->vector('embedding', 384); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 0a7c60cb8b40..041df2b2f042 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -47,7 +47,7 @@ public function testBasicCreateTable() public function testAddingVector() { - $blueprint = new Blueprint('embeddings'); + $blueprint = new Blueprint($this->getConnection(), 'embeddings'); $blueprint->vector('embedding', 384); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); From afc86496fdc4c8b5639b56d45b29fc7dd34ccff9 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 14 Oct 2024 14:58:02 +0200 Subject: [PATCH 021/455] Change version constraint to 0.3.0 (#53146) --- src/Illuminate/Console/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 9f99189266db..fedca71068dc 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -21,7 +21,7 @@ "illuminate/macroable": "^12.0", "illuminate/support": "^12.0", "illuminate/view": "^12.0", - "laravel/prompts": "dev-l12", + "laravel/prompts": "^0.3.0", "nunomaduro/termwind": "^2.0", "symfony/console": "^7.0", "symfony/polyfill-php83": "^1.28", From c361cf9b284b084b4419755f087b89fe2dc791c3 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:42:26 +0200 Subject: [PATCH 022/455] Add generic return type to `Container::instance()` (#53161) --- src/Illuminate/Container/Container.php | 6 ++++-- src/Illuminate/Contracts/Container/Container.php | 6 ++++-- types/Container/Container.php | 10 ++++++++++ types/Contracts/Container/Container.php | 10 ++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 types/Container/Container.php create mode 100644 types/Contracts/Container/Container.php diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 58f5b89e064e..d756758d7815 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -488,9 +488,11 @@ public function extend($abstract, Closure $closure) /** * Register an existing instance as shared in the container. * + * @template TInstance + * * @param string $abstract - * @param mixed $instance - * @return mixed + * @param TInstance $instance + * @return TInstance */ public function instance($abstract, $instance) { diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index 47c5f8b55278..3273750e6a1e 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -122,9 +122,11 @@ public function extend($abstract, Closure $closure); /** * Register an existing instance as shared in the container. * + * @template TInstance + * * @param string $abstract - * @param mixed $instance - * @return mixed + * @param TInstance $instance + * @return TInstance */ public function instance($abstract, $instance); diff --git a/types/Container/Container.php b/types/Container/Container.php new file mode 100644 index 000000000000..dae598e6c3bb --- /dev/null +++ b/types/Container/Container.php @@ -0,0 +1,10 @@ +instance('request', Request::capture())); diff --git a/types/Contracts/Container/Container.php b/types/Contracts/Container/Container.php new file mode 100644 index 000000000000..3d413a586c7c --- /dev/null +++ b/types/Contracts/Container/Container.php @@ -0,0 +1,10 @@ +instance('request', Request::capture())); From 365bc10554430bbb55bcfee84b949e3882dc488f Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Tue, 15 Oct 2024 13:43:03 +0000 Subject: [PATCH 023/455] Update facade docblocks --- src/Illuminate/Support/Facades/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index 66f7f8aff318..ca01c1670f71 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -111,7 +111,7 @@ * @method static void scoped(string $abstract, \Closure|string|null $concrete = null) * @method static void scopedIf(string $abstract, \Closure|string|null $concrete = null) * @method static void extend(string $abstract, \Closure $closure) - * @method static mixed instance(string $abstract, mixed $instance) + * @method static void instance(string $abstract, void $instance) * @method static void tag(array|string $abstracts, array|mixed $tags) * @method static iterable tagged(string $tag) * @method static void alias(string $abstract, string $alias) From 42c1c843ccf03024b401cf504a6be29d9f0a7c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ola=20Val=C3=B8=20Pettersen?= Date: Wed, 16 Oct 2024 23:47:30 +0200 Subject: [PATCH 024/455] Map output of concurrecy calls to the index of the input (#53135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix test namespace. Signed-off-by: Ola Valø Pettersen * map concurrency output to array keys on input. Signed-off-by: Ola Valø Pettersen * modify forkDriver to use input index for output. Signed-off-by: Ola Valø Pettersen * comment out tests, as the package is not preset by default. Signed-off-by: Ola Valø Pettersen * Remove unnecessary PHPStan ignore comment Signed-off-by: Ola Valø Pettersen * fix comment format Signed-off-by: Ola Valø Pettersen * formatting Signed-off-by: Ola Valø Pettersen * Update ForkDriver.php --------- Signed-off-by: Ola Valø Pettersen Co-authored-by: Taylor Otwell --- src/Illuminate/Concurrency/ForkDriver.php | 9 ++++- src/Illuminate/Concurrency/ProcessDriver.php | 8 ++--- .../Concurrency/ConcurrencyTest.php | 36 ++++++++++++++++++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Concurrency/ForkDriver.php b/src/Illuminate/Concurrency/ForkDriver.php index b385e4fbf7e6..4460449c78e4 100644 --- a/src/Illuminate/Concurrency/ForkDriver.php +++ b/src/Illuminate/Concurrency/ForkDriver.php @@ -17,8 +17,15 @@ class ForkDriver implements Driver */ public function run(Closure|array $tasks): array { + $tasks = Arr::wrap($tasks); + + $keys = array_keys($tasks); + $values = array_values($tasks); + /** @phpstan-ignore class.notFound */ - return Fork::new()->run(...Arr::wrap($tasks)); + $results = Fork::new()->run(...$values); + + return array_combine($keys, $results); } /** diff --git a/src/Illuminate/Concurrency/ProcessDriver.php b/src/Illuminate/Concurrency/ProcessDriver.php index 0f4ac17363c0..9da20273a098 100644 --- a/src/Illuminate/Concurrency/ProcessDriver.php +++ b/src/Illuminate/Concurrency/ProcessDriver.php @@ -31,14 +31,14 @@ public function run(Closure|array $tasks): array $command = Application::formatCommandString('invoke-serialized-closure'); $results = $this->processFactory->pool(function (Pool $pool) use ($tasks, $command) { - foreach (Arr::wrap($tasks) as $task) { - $pool->path(base_path())->env([ + foreach (Arr::wrap($tasks) as $key => $task) { + $pool->as($key)->path(base_path())->env([ 'LARAVEL_INVOKABLE_CLOSURE' => serialize(new SerializableClosure($task)), ])->command($command); } })->start()->wait(); - return $results->collect()->map(function ($result) { + return $results->collect()->mapWithKeys(function ($result, $key) { $result = json_decode($result->output(), true); if (! $result['successful']) { @@ -47,7 +47,7 @@ public function run(Closure|array $tasks): array ); } - return unserialize($result['result']); + return [$key => unserialize($result['result'])]; })->all(); } diff --git a/tests/Integration/Concurrency/ConcurrencyTest.php b/tests/Integration/Concurrency/ConcurrencyTest.php index 76012712c375..a5745416dbc3 100644 --- a/tests/Integration/Concurrency/ConcurrencyTest.php +++ b/tests/Integration/Concurrency/ConcurrencyTest.php @@ -1,7 +1,8 @@ assertEquals(2, $first); $this->assertEquals(4, $second); } + + public function testOutputIsMappedToArrayInput() + { + $input = [ + 'first' => fn () => 1 + 1, + 'second' => fn () => 2 + 2, + ]; + + $processOutput = Concurrency::driver('process')->run($input); + + $this->assertIsArray($processOutput); + $this->assertArrayHasKey('first', $processOutput); + $this->assertArrayHasKey('second', $processOutput); + + $syncOutput = Concurrency::driver('sync')->run($input); + + $this->assertIsArray($syncOutput); + $this->assertArrayHasKey('first', $syncOutput); + $this->assertArrayHasKey('second', $syncOutput); + + /** As of now, the spatie/fork package is not included by default. + * $forkOutput = Concurrency::driver('fork')->run([ + * 'first' => fn() => 1 + 1, + * 'second' => fn() => 2 + 2, + * ]);. + * + * $this->assertIsArray($forkOutput); + * $this->assertArrayHasKey('first', $forkOutput); + * $this->assertArrayHasKey('second', $forkOutput); + * $this->assertEquals(2, $forkOutput['first']); + * $this->assertEquals(4, $forkOutput['second']); + */ + } } From 0d1e2d3d3b2e282aeaddd66ec596e578f1bf1dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B9i=20Th=E1=BA=BF=20H=E1=BA=A1nh?= Date: Thu, 24 Oct 2024 21:12:21 +0700 Subject: [PATCH 025/455] Change Illuminate\Support\Composer hasPackage to public (#53282) --- src/Illuminate/Support/Composer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Composer.php b/src/Illuminate/Support/Composer.php index 190500a4fe32..d244867cd9f6 100644 --- a/src/Illuminate/Support/Composer.php +++ b/src/Illuminate/Support/Composer.php @@ -45,7 +45,7 @@ public function __construct(Filesystem $files, $workingPath = null) * * @throw \RuntimeException */ - protected function hasPackage($package) + public function hasPackage($package) { $composer = json_decode(file_get_contents($this->findComposerFile()), true); From 4d18e661856289db04e77bc49f422dbbc96ebfaa Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 29 Oct 2024 12:36:30 -0500 Subject: [PATCH 026/455] force `Eloquent\Collection::partition` to return a base `Collection` (#53304) the way `partition` currently works is it returns an `Eloquent\Collection` of `Eloquent\Collection`s, which is technically not allowed by the generic type hints defined by the class, and also doesn't really make any logical sense for how someone would want to use this. It also causes issues in the IDE because based on the type hints it assumes ALL values of an `Eloquent\Collection` are of type `Eloquent\Model`, which is not the case for the `partition` method. what we really want is a `Support\Collection` of `Eloquent\Collection`s. we can accomplish this by first calling the `parent::partition` method to get our (illegal) result of `Eloquent\Collection`, and then converting it to a base collection to end up with the desired `Support\Collection`. --- src/Illuminate/Database/Eloquent/Collection.php | 13 +++++++++++++ tests/Database/DatabaseEloquentCollectionTest.php | 1 + 2 files changed, 14 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 022e27dcc6c2..1ae950cb9e73 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -659,6 +659,19 @@ public function pad($size, $value) return $this->toBase()->pad($size, $value); } + /** + * Partition the collection into two arrays using the given callback or key. + * + * @param (callable(TModel, TKey): bool)|TModel|string $key + * @param TModel|string|null $operator + * @param TModel|null $value + * @return \Illuminate\Support\Collection, static> + */ + public function partition($key, $operator = null, $value = null) + { + return parent::partition($key, $operator, $value)->toBase(); + } + /** * Get an array with the values of a given key. * diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index 7b9b6655980f..2e1f7290e0b0 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -553,6 +553,7 @@ public function testNonModelRelatedMethods() $this->assertEquals(BaseCollection::class, get_class($a->zip(['a', 'b'], ['c', 'd']))); $this->assertEquals(BaseCollection::class, get_class($a->countBy('foo'))); $this->assertEquals(BaseCollection::class, get_class($b->flip())); + $this->assertEquals(BaseCollection::class, get_class($a->partition('foo', '=', 'bar'))); } public function testMakeVisibleRemovesHiddenAndIncludesVisible() From a48c54205f5151cfb154009905408366638410d7 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Tue, 29 Oct 2024 17:39:58 -0300 Subject: [PATCH 027/455] [12.x] Better support for multi-dbs in the `RefreshDatabase` trait (#53231) * Tweaks the RefreshDatabase trait for better support of multi-dbs When working with multiple databases and some of them are in-memory while others are regular disk-based databases, we usually have to override some of the traits methods to make it work. Also, the database restoration process doesn't handle multiple DBs that well. With these changes, when an app needs to support multiple databases, the user will have to do a few steps: 1. Set the `$connectionsToTransact` protected property on the TestCase listing all connections they use 1. Override the `migrateDatabase` method and call all the migrate:fresh commands for all their connections Restoring the databases between tests should now be completely handled by the trait, no matter which database connection uses in-memory databases or not. * formatting --------- Co-authored-by: Taylor Otwell --- .../Foundation/Testing/RefreshDatabase.php | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/RefreshDatabase.php b/src/Illuminate/Foundation/Testing/RefreshDatabase.php index 4c4e084ab0fa..f183ef439c26 100644 --- a/src/Illuminate/Foundation/Testing/RefreshDatabase.php +++ b/src/Illuminate/Foundation/Testing/RefreshDatabase.php @@ -18,7 +18,7 @@ public function refreshDatabase() { $this->beforeRefreshingDatabase(); - if ($this->usingInMemoryDatabase()) { + if ($this->usingInMemoryDatabases()) { $this->restoreInMemoryDatabase(); } @@ -28,15 +28,29 @@ public function refreshDatabase() } /** - * Determine if an in-memory database is being used. + * Determine if any of the connections transacting is using in-memory databases. * * @return bool */ - protected function usingInMemoryDatabase() + protected function usingInMemoryDatabases() { - $default = config('database.default'); + foreach ($this->connectionsToTransact() as $name) { + if ($this->usingInMemoryDatabase($name)) { + return true; + } + } - return config("database.connections.$default.database") === ':memory:'; + return false; + } + + /** + * Determine if a given database connection is an in-memory database. + * + * @return bool + */ + protected function usingInMemoryDatabase(string $name) + { + return config("database.connections.{$name}.database") === ':memory:'; } /** @@ -63,7 +77,7 @@ protected function restoreInMemoryDatabase() protected function refreshTestDatabase() { if (! RefreshDatabaseState::$migrated) { - $this->artisan('migrate:fresh', $this->migrateFreshUsing()); + $this->migrateDatabases(); $this->app[Kernel::class]->setArtisan(null); @@ -73,6 +87,16 @@ protected function refreshTestDatabase() $this->beginDatabaseTransaction(); } + /** + * Migrate the database. + * + * @return void + */ + protected function migrateDatabases() + { + $this->artisan('migrate:fresh', $this->migrateFreshUsing()); + } + /** * Begin a database transaction on the testing database. * @@ -89,7 +113,7 @@ public function beginDatabaseTransaction() $connection->setTransactionManager($transactionsManager); - if ($this->usingInMemoryDatabase()) { + if ($this->usingInMemoryDatabase($name)) { RefreshDatabaseState::$inMemoryConnections[$name] ??= $connection->getPdo(); } @@ -121,7 +145,7 @@ public function beginDatabaseTransaction() protected function connectionsToTransact() { return property_exists($this, 'connectionsToTransact') - ? $this->connectionsToTransact : [null]; + ? $this->connectionsToTransact : [config('database.default')]; } /** From 0dfeef59bf1912df64ad096489311395c94ac298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= <11225821+shaedrich@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:35:51 +0100 Subject: [PATCH 028/455] [12.x] Validate UUID's version optionally (#53341) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Validate UUID's version optionally * StyleCI fixes * Reorder imports * Check type before length * Fix wrong variable * Symfony/uid doesn't implement version 2 * fix: :bug: Cast extracted value for identity check of match * test: :white_check_mark: Add tests for both Str::isUuid() and the uuid validation rule * style: 🎨 Fix StyleCI error Suggested-by: Vano Devium cc: Vano Devium thanks-to: Vano Devium original-patch-by: Vano Devium based-on-a-patch-by: Vano Devium based-on-patch-by: Vano Devium credit-to: Vano Devium inspired-by-patch-by: Vano Devium initial-work-by: Vano Devium inspired-by: #21672 * test: ✅ Add non-existent UUID version cases to data provider Suggested-by: Vano Devium cc: Vano Devium thanks-to: Vano Devium original-patch-by: Vano Devium based-on-a-patch-by: Vano Devium based-on-patch-by: Vano Devium credit-to: Vano Devium inspired-by-patch-by: Vano Devium initial-work-by: Vano Devium inspired-by: #21672 --- src/Illuminate/Support/Str.php | 28 +++++++++++++++++-- .../Concerns/ValidatesAttributes.php | 5 ++-- tests/Support/SupportStrTest.php | 24 ++++++++++++++++ tests/Validation/ValidationValidatorTest.php | 26 +++++++++++++++++ 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index ae75a05c16b2..0d23c49597e1 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -14,7 +14,15 @@ use Ramsey\Uuid\Generator\CombGenerator; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidFactory; +use Symfony\Component\Uid\NilUuid; use Symfony\Component\Uid\Ulid; +use Symfony\Component\Uid\UuidV1; +use Symfony\Component\Uid\UuidV3; +use Symfony\Component\Uid\UuidV4; +use Symfony\Component\Uid\UuidV5; +use Symfony\Component\Uid\UuidV6; +use Symfony\Component\Uid\UuidV7; +use Symfony\Component\Uid\UuidV8; use Throwable; use Traversable; use voku\helper\ASCII; @@ -595,15 +603,31 @@ public static function isUrl($value, array $protocols = []) * Determine if a given value is a valid UUID. * * @param mixed $value + * @param int<-1, 8>|null $version * @return bool */ - public static function isUuid($value) + public static function isUuid($value, $version = null) { if (! is_string($value)) { return false; } - return preg_match('/^[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}$/D', $value) > 0; + if ($version === null) { + return preg_match('/^[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}$/D', $value) > 0; + } + + return match ($version) { + -1, 0 => NilUuid::isValid($value), + 1 => UuidV1::isValid($value), + // 2 => UuidV2::isValid($value), // Symfony/uid doesn't implement version 2 + 3 => UuidV3::isValid($value), + 4 => UuidV4::isValid($value), + 5 => UuidV5::isValid($value), + 6 => UuidV6::isValid($value), + 7 => UuidV7::isValid($value), + 8 => UuidV8::isValid($value), + default => false, + }; } /** diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 901fcf18ab53..e26c5300797f 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -2550,11 +2550,12 @@ public function validateUlid($attribute, $value) * * @param string $attribute * @param mixed $value + * @param array> $parameters * @return bool */ - public function validateUuid($attribute, $value) + public function validateUuid($attribute, $value, $parameters) { - return Str::isUuid($value); + return Str::isUuid($value, $parameters !== null && count($parameters) === 1 ? (int) $parameters[0] : null); } /** diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 4508bf5b5e2f..fed5d2c57c4d 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -597,6 +597,12 @@ public function testIsUuidWithInvalidUuid($uuid) $this->assertFalse(Str::isUuid($uuid)); } + #[DataProvider('uuidVersionList')] + public function testIsUuidWithVersion($uuid, $version, $passes) + { + $this->assertSame(Str::isUuid($uuid, $version), $passes); + } + public function testIsJson() { $this->assertTrue(Str::isJson('1')); @@ -1306,6 +1312,24 @@ public static function invalidUuidList() ]; } + public static function uuidVersionList() + { + return [ + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', null, true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 1, false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 4, true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 42, false], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', null, true], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 1, true], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 4, false], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 42, false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', null, false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 1, false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 4, false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 42, false], + ]; + } + public static function strContainsProvider() { return [ diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 5ad5fc600a96..99814b4d481c 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -8445,6 +8445,14 @@ public function testValidateWithInvalidUuid($uuid) $this->assertFalse($v->passes()); } + #[DataProvider('uuidVersionList')] + public function testValidateWithUuidWithVersionConstraint($uuid, $rule, $passes) + { + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => $uuid], ['foo' => $rule]); + $this->assertSame($v->passes(), $passes); + } + public static function validUuidList() { return [ @@ -8477,6 +8485,24 @@ public static function invalidUuidList() ]; } + public static function uuidVersionList() + { + return [ + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid', true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:1', false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:4', true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:42', false], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid', true], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid:1', true], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid:4', false], + ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid:42', false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid', false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid:1', false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid:4', false], + ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid:42', false], + ]; + } + public function testValidateWithValidAscii() { $trans = $this->getIlluminateArrayTranslator(); From e4fcc783394be0c5d9c84a0583f6761f8b538da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= <11225821+shaedrich@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:34:07 +0100 Subject: [PATCH 029/455] [12.x] Validate UUID version 2 and max (#53368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: ✨ Add support for UUID v2 and max UUID validation * test: ✅ Add cases for every supported UUID version to data provider of UUID validation tests * style: 🎨 Fix StyleCI errors – Remove unused imports – Spacing improves: #53341 * Add missing import * style: 🎨 Remove indent from blank line * Add ramsey/uuid to composer suggestions to be able to use it for UUID version constraint validation * Update Str.php * Update Str.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Str.php | 47 ++++++++++--------- .../Concerns/ValidatesAttributes.php | 14 +++++- src/Illuminate/Validation/composer.json | 3 +- tests/Support/SupportStrTest.php | 44 +++++++++++++++-- tests/Validation/ValidationValidatorTest.php | 40 ++++++++++++++-- 5 files changed, 116 insertions(+), 32 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 0d23c49597e1..cda1f7c7fc67 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -11,18 +11,12 @@ use League\CommonMark\GithubFlavoredMarkdownConverter; use League\CommonMark\MarkdownConverter; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; +use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Generator\CombGenerator; +use Ramsey\Uuid\Rfc4122\FieldsInterface; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidFactory; -use Symfony\Component\Uid\NilUuid; use Symfony\Component\Uid\Ulid; -use Symfony\Component\Uid\UuidV1; -use Symfony\Component\Uid\UuidV3; -use Symfony\Component\Uid\UuidV4; -use Symfony\Component\Uid\UuidV5; -use Symfony\Component\Uid\UuidV6; -use Symfony\Component\Uid\UuidV7; -use Symfony\Component\Uid\UuidV8; use Throwable; use Traversable; use voku\helper\ASCII; @@ -603,7 +597,7 @@ public static function isUrl($value, array $protocols = []) * Determine if a given value is a valid UUID. * * @param mixed $value - * @param int<-1, 8>|null $version + * @param int<0, 8>|'max'|null $version * @return bool */ public static function isUuid($value, $version = null) @@ -616,18 +610,29 @@ public static function isUuid($value, $version = null) return preg_match('/^[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}$/D', $value) > 0; } - return match ($version) { - -1, 0 => NilUuid::isValid($value), - 1 => UuidV1::isValid($value), - // 2 => UuidV2::isValid($value), // Symfony/uid doesn't implement version 2 - 3 => UuidV3::isValid($value), - 4 => UuidV4::isValid($value), - 5 => UuidV5::isValid($value), - 6 => UuidV6::isValid($value), - 7 => UuidV7::isValid($value), - 8 => UuidV8::isValid($value), - default => false, - }; + $factory = new UuidFactory; + + try { + $factoryUuid = $factory->fromString($value); + } catch (InvalidUuidStringException $ex) { + return false; + } + + $fields = $factoryUuid->getFields(); + + if (! ($fields instanceof FieldsInterface)) { + return false; + } + + if ($version === 0 || $version === 'nil') { + return $fields->isNil(); + } + + if ($version === 'max') { + return $fields->isMax(); + } + + return $fields->getVersion() === $version; } /** diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index e26c5300797f..607c7b840716 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -2550,12 +2550,22 @@ public function validateUlid($attribute, $value) * * @param string $attribute * @param mixed $value - * @param array> $parameters + * @param array|'max'> $parameters * @return bool */ public function validateUuid($attribute, $value, $parameters) { - return Str::isUuid($value, $parameters !== null && count($parameters) === 1 ? (int) $parameters[0] : null); + $version = null; + + if ($parameters !== null && count($parameters) === 1) { + $version = $parameters[0]; + + if ($version !== 'max') { + $version = (int) $parameters[0]; + } + } + + return Str::isUuid($value, $version); } /** diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 74e7c1e61c17..0aae94ee07fb 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -39,7 +39,8 @@ } }, "suggest": { - "illuminate/database": "Required to use the database presence verifier (^12.0)." + "illuminate/database": "Required to use the database presence verifier (^12.0).", + "ramsey/uuid": "Required to use Validator::validateUuid() (^4.7)." }, "config": { "sort-packages": true diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index fed5d2c57c4d..f85719e6bde3 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -1315,14 +1315,50 @@ public static function invalidUuidList() public static function uuidVersionList() { return [ - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', null, true], - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 1, false], - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 4, true], - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 42, false], + ['00000000-0000-0000-0000-000000000000', null, true], + ['00000000-0000-0000-0000-000000000000', 0, true], + ['00000000-0000-0000-0000-000000000000', 1, false], + ['00000000-0000-0000-0000-000000000000', 42, false], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', null, true], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 1, true], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 4, false], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 42, false], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', null, true], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 1, false], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 2, true], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 42, false], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', null, true], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 1, false], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 3, true], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 42, false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', null, true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 1, false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 4, true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 42, false], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', null, true], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 1, false], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 5, true], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 42, false], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', null, true], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 1, false], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 6, true], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 42, false], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', null, true], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 1, false], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 7, true], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 42, false], + ['07e80a1f-1629-831f-811f-c595103c91b5', null, true], + ['07e80a1f-1629-831f-811f-c595103c91b5', 1, false], + ['07e80a1f-1629-831f-811f-c595103c91b5', 8, true], + ['07e80a1f-1629-831f-811f-c595103c91b5', 42, false], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', null, true], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 1, false], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 42, false], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'max', true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', null, true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 1, false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 4, true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 42, false], ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', null, false], ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 1, false], ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 4, false], diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 99814b4d481c..06b163fcf43c 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -8488,14 +8488,46 @@ public static function invalidUuidList() public static function uuidVersionList() { return [ - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid', true], - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:1', false], - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:4', true], - ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:42', false], + ['00000000-0000-0000-0000-000000000000', 'uuid', true], + ['00000000-0000-0000-0000-000000000000', 'uuid:0', true], + ['00000000-0000-0000-0000-000000000000', 'uuid:1', false], + ['00000000-0000-0000-0000-000000000000', 'uuid:42', false], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid', true], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid:1', true], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid:4', false], ['145a1e72-d11d-11e8-a8d5-f2801f1b9fd1', 'uuid:42', false], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 'uuid', true], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 'uuid:1', false], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 'uuid:2', true], + ['ff6f8cb0-c57d-21e1-9b21-0800200c9a66', 'uuid:42', false], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 'uuid', true], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 'uuid:1', false], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 'uuid:3', true], + ['76a4ba72-cc4e-3e1d-b52d-856382f408c3', 'uuid:42', false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid', true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:1', false], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:4', true], + ['a0a2a2d2-0b87-4a18-83f2-2529882be2de', 'uuid:42', false], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 'uuid', true], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 'uuid:1', false], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 'uuid:5', true], + ['d3b2b5a9-d433-5c58-b038-4fa13696e357', 'uuid:42', false], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 'uuid', true], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 'uuid:1', false], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 'uuid:6', true], + ['1ef97d97-b5ab-67d8-9f12-5600051f1387', 'uuid:42', false], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 'uuid', true], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 'uuid:1', false], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 'uuid:7', true], + ['0192e4b9-92eb-7aec-8707-1becfb1e3eb7', 'uuid:42', false], + ['07e80a1f-1629-831f-811f-c595103c91b5', 'uuid', true], + ['07e80a1f-1629-831f-811f-c595103c91b5', 'uuid:1', false], + ['07e80a1f-1629-831f-811f-c595103c91b5', 'uuid:8', true], + ['07e80a1f-1629-831f-811f-c595103c91b5', 'uuid:42', false], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'uuid', true], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'uuid:1', false], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'uuid:42', false], + ['FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'uuid:max', true], ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid', false], ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid:1', false], ['zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'uuid:4', false], From 61adf1a1bd3c6fe7661640b95347cdd25c7384b7 Mon Sep 17 00:00:00 2001 From: AG Date: Tue, 12 Nov 2024 18:55:38 +0400 Subject: [PATCH 030/455] [12.x] Add step parameter to LazyCollection range method (#53473) * add step in collection range * add step in collection range * add step in collection range --------- Co-authored-by: Ashot Gharakeshishyan --- src/Illuminate/Collections/Collection.php | 5 +++-- src/Illuminate/Collections/Enumerable.php | 3 ++- src/Illuminate/Collections/LazyCollection.php | 13 +++++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 219b4b051c2a..1fff70cac375 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -49,11 +49,12 @@ public function __construct($items = []) * * @param int $from * @param int $to + * @param int $step * @return static */ - public static function range($from, $to) + public static function range($from, $to, $step = 1) { - return new static(range($from, $to)); + return new static(range($from, $to, $step)); } /** diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 836d4225608b..aceca47ea56e 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -45,9 +45,10 @@ public static function times($number, ?callable $callback = null); * * @param int $from * @param int $to + * @param int $step * @return static */ - public static function range($from, $to); + public static function range($from, $to, $step = 1); /** * Wrap the given value in a collection if applicable. diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index c8fc497bbd05..5dde312a245b 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -75,17 +75,22 @@ public static function make($items = []) * * @param int $from * @param int $to + * @param int $step * @return static */ - public static function range($from, $to) + public static function range($from, $to, $step = 1) { - return new static(function () use ($from, $to) { + if ($step == 0) { + throw new InvalidArgumentException('Step value cannot be zero.'); + } + + return new static(function () use ($from, $to, $step) { if ($from <= $to) { - for (; $from <= $to; $from++) { + for (; $from <= $to; $from += abs($step)) { yield $from; } } else { - for (; $from >= $to; $from--) { + for (; $from >= $to; $from -= abs($step)) { yield $from; } } From 4b1f01f3c06c953fb37e68e12eadfb16e161333b Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 15 Nov 2024 12:42:14 +0800 Subject: [PATCH 031/455] [12.x] Test Improvements (#53524) Signed-off-by: Mior Muhammad Zaki --- .../Foundation/Testing/RefreshDatabase.php | 6 +++- .../Database/DatabaseSchemaBlueprintTest.php | 28 ++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/RefreshDatabase.php b/src/Illuminate/Foundation/Testing/RefreshDatabase.php index 5c8e43a6f544..8bd00381cc8a 100644 --- a/src/Illuminate/Foundation/Testing/RefreshDatabase.php +++ b/src/Illuminate/Foundation/Testing/RefreshDatabase.php @@ -48,8 +48,12 @@ protected function usingInMemoryDatabases() * * @return bool */ - protected function usingInMemoryDatabase(string $name) + protected function usingInMemoryDatabase(?string $name) { + if (is_null($name)) { + $name = config('database.default'); + } + return config("database.connections.{$name}.database") === ':memory:'; } diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index 1746a43ff865..a02505335f8c 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -400,34 +400,30 @@ public function testGenerateRelationshipColumnWithUlidModel() public function testGenerateRelationshipConstrainedColumn() { - $base = new Blueprint('posts', function ($table) { - $table->foreignIdFor('Illuminate\Foundation\Auth\User')->constrained(); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->foreignIdFor('Illuminate\Foundation\Auth\User')->constrained(); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` add `user_id` bigint unsigned not null', 'alter table `posts` add constraint `posts_user_id_foreign` foreign key (`user_id`) references `users` (`id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testGenerateRelationshipForModelWithNonStandardPrimaryKeyName() { - $base = new Blueprint('posts', function ($table) { - $table->foreignIdFor(User::class)->constrained(); - }); - - $connection = m::mock(Connection::class); - - $blueprint = clone $base; + $getSql = function ($grammar) { + return $this->getBlueprint($grammar, 'posts', function ($table) { + $table->foreignIdFor(User::class)->constrained(); + })->toSql(); + }; $this->assertEquals([ 'alter table `posts` add `user_internal_id` bigint unsigned not null', 'alter table `posts` add constraint `posts_user_internal_id_foreign` foreign key (`user_internal_id`) references `users` (`internal_id`)', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $getSql(new MySqlGrammar)); } public function testDropRelationshipColumnWithIncrementalModel() From 59af498c169b52b9b6ba466a147b4302f48f19cf Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 20 Nov 2024 23:02:45 +0800 Subject: [PATCH 032/455] [12.x] Avoid breaking change `RefreshDatabase::usingInMemoryDatabase()` (#53587) While we do allows BC on major release I do feel that this is not needed for the following use case. Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Foundation/Testing/RefreshDatabase.php | 2 +- tests/Integration/Queue/SerializableClosureV1QueueTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/RefreshDatabase.php b/src/Illuminate/Foundation/Testing/RefreshDatabase.php index 8bd00381cc8a..f714d7fa6433 100644 --- a/src/Illuminate/Foundation/Testing/RefreshDatabase.php +++ b/src/Illuminate/Foundation/Testing/RefreshDatabase.php @@ -48,7 +48,7 @@ protected function usingInMemoryDatabases() * * @return bool */ - protected function usingInMemoryDatabase(?string $name) + protected function usingInMemoryDatabase(?string $name = null) { if (is_null($name)) { $name = config('database.default'); diff --git a/tests/Integration/Queue/SerializableClosureV1QueueTest.php b/tests/Integration/Queue/SerializableClosureV1QueueTest.php index e22de0584256..8f72ae239060 100644 --- a/tests/Integration/Queue/SerializableClosureV1QueueTest.php +++ b/tests/Integration/Queue/SerializableClosureV1QueueTest.php @@ -17,7 +17,7 @@ class SerializableClosureV1QueueTest extends TestCase #[\Override] protected function defineEnvironment($app) { - $this->markTestSkippedWhen($this->usingInMemoryDatabase(null), 'Test does not support using :memory: database connection'); + $this->markTestSkippedWhen($this->usingInMemoryDatabase(), 'Test does not support using :memory: database connection'); tap($app->make('config'), function ($config) { $config->set([ From e5a4922e3eb2f4d1bf4f2bfc0f780e23647a0afe Mon Sep 17 00:00:00 2001 From: Caleb White Date: Wed, 27 Nov 2024 11:36:06 -0600 Subject: [PATCH 033/455] [12.x] fix: container resolution order when resolving class dependencies (#53522) * fix: container resolution order when resolving class dependencies * formatting * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Container/Container.php | 28 +++++++++++++++++--------- tests/Container/ContainerTest.php | 21 +++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index a2dcdebe144d..5776cabcd2f4 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -1110,22 +1110,32 @@ protected function resolvePrimitive(ReflectionParameter $parameter) */ protected function resolveClass(ReflectionParameter $parameter) { + $className = Util::getParameterClassName($parameter); + + // First, we check if the dependency has been explicitly bound in the container + // and if so, we will resolve it directly from there to respect any explicit + // bindings the developer has defined rather than using any default value. + if ($this->bound($className)) { + return $this->make($className); + } + + // If no binding exists, we will check if a default value has been defined for + // the parameter. If it has, we should return it to avoid overriding any of + // the developer specified default values for the constructor parameters. + if ($parameter->isDefaultValueAvailable()) { + return $parameter->getDefaultValue(); + } + try { return $parameter->isVariadic() ? $this->resolveVariadicClass($parameter) - : $this->make(Util::getParameterClassName($parameter)); + : $this->make($className); } // If we can not resolve the class instance, we will check to see if the value - // is optional, and if it is we will return the optional parameter value as - // the value of the dependency, similarly to how we do this with scalars. + // is variadic. If it is, we will return an empty array as the value of the + // dependency similarly to how we handle scalar values in this situation. catch (BindingResolutionException $e) { - if ($parameter->isDefaultValueAvailable()) { - array_pop($this->with); - - return $parameter->getDefaultValue(); - } - if ($parameter->isVariadic()) { array_pop($this->with); diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 53cf9b6713ac..767dbba68a06 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -289,6 +289,18 @@ public function testResolutionOfDefaultParameters() $this->assertSame('taylor', $instance->default); } + public function testResolutionOfClassWithDefaultParameters() + { + $container = new Container; + $instance = $container->make(ContainerClassWithDefaultValueStub::class); + $this->assertInstanceOf(ContainerConcreteStub::class, $instance->noDefault); + $this->assertSame(null, $instance->default); + + $container->bind(ContainerConcreteStub::class, fn () => new ContainerConcreteStub); + $instance = $container->make(ContainerClassWithDefaultValueStub::class); + $this->assertInstanceOf(ContainerConcreteStub::class, $instance->default); + } + public function testBound() { $container = new Container; @@ -765,6 +777,15 @@ public function __construct(ContainerConcreteStub $stub, $default = 'taylor') } } +class ContainerClassWithDefaultValueStub +{ + public function __construct( + public ?ContainerConcreteStub $noDefault, + public ?ContainerConcreteStub $default = null, + ) { + } +} + class ContainerMixedPrimitiveStub { public $first; From ca5c86a43c0112cccb4d1030f650b45004692051 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 4 Dec 2024 13:37:07 +0000 Subject: [PATCH 034/455] Apply fixes from StyleCI --- tests/Integration/Concurrency/ConcurrencyTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Concurrency/ConcurrencyTest.php b/tests/Integration/Concurrency/ConcurrencyTest.php index 60495610a110..ea84e8858f97 100644 --- a/tests/Integration/Concurrency/ConcurrencyTest.php +++ b/tests/Integration/Concurrency/ConcurrencyTest.php @@ -2,10 +2,10 @@ namespace Illuminate\Tests\Integration\Concurrency; -use Illuminate\Support\Facades\Concurrency; use Illuminate\Concurrency\ProcessDriver; use Illuminate\Foundation\Application; use Illuminate\Process\Factory as ProcessFactory; +use Illuminate\Support\Facades\Concurrency; use Orchestra\Testbench\TestCase; use PHPUnit\Framework\Attributes\RequiresOperatingSystem; From c41b4f23879f6f35f9a9f7e17f52bd4acf1dcfaf Mon Sep 17 00:00:00 2001 From: "Philip Iezzi (Pipo)" <2759561+onlime@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:56:01 +0100 Subject: [PATCH 035/455] Change the default for scheduled command emailOutput() to only send email if output exists (#53774) --- src/Illuminate/Console/Scheduling/Event.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 371e2d7018d8..741e890e17fd 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -386,7 +386,7 @@ public function appendOutputTo($location) * * @throws \LogicException */ - public function emailOutputTo($addresses, $onlyIfOutputExists = false) + public function emailOutputTo($addresses, $onlyIfOutputExists = true) { $this->ensureOutputIsBeingCaptured(); @@ -447,7 +447,7 @@ protected function ensureOutputIsBeingCaptured() * @param bool $onlyIfOutputExists * @return void */ - protected function emailOutput(Mailer $mailer, $addresses, $onlyIfOutputExists = false) + protected function emailOutput(Mailer $mailer, $addresses, $onlyIfOutputExists = true) { $text = is_file($this->output) ? file_get_contents($this->output) : ''; From d65452384e77cdc77181244399259d92f0cd6972 Mon Sep 17 00:00:00 2001 From: Kennedy Tedesco Date: Fri, 6 Dec 2024 16:06:57 -0300 Subject: [PATCH 036/455] [12.x] Add `hasMorePages()` to `CursorPaginator` contract (#53762) --- src/Illuminate/Contracts/Pagination/CursorPaginator.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Illuminate/Contracts/Pagination/CursorPaginator.php b/src/Illuminate/Contracts/Pagination/CursorPaginator.php index 49fbd2f7a5e2..7d2bcf9c3fcb 100644 --- a/src/Illuminate/Contracts/Pagination/CursorPaginator.php +++ b/src/Illuminate/Contracts/Pagination/CursorPaginator.php @@ -97,6 +97,13 @@ public function cursor(); */ public function hasPages(); + /** + * Determine if there are more items in the data source. + * + * @return bool + */ + public function hasMorePages(); + /** * Get the base path for paginator generated URLs. * From 606fe57ffd64a13727f71d4b4e9f28ffe5c9c858 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 6 Dec 2024 13:16:42 -0600 Subject: [PATCH 037/455] modernize `DatabaseTokenRepository` and make consistent with `CacheTokenRepository` (#53746) - use promoted properties - require the `expires` property to be passed in as seconds, rather than taking it as minutes and converting it. shift responsibility to calling code. --- .../Passwords/DatabaseTokenRepository.php | 68 ++----------------- .../Auth/Passwords/PasswordBrokerManager.php | 4 +- 2 files changed, 8 insertions(+), 64 deletions(-) diff --git a/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php b/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php index aae28652fc58..ba0b81a62fae 100755 --- a/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php +++ b/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php @@ -10,73 +10,17 @@ class DatabaseTokenRepository implements TokenRepositoryInterface { - /** - * The database connection instance. - * - * @var \Illuminate\Database\ConnectionInterface - */ - protected $connection; - - /** - * The Hasher implementation. - * - * @var \Illuminate\Contracts\Hashing\Hasher - */ - protected $hasher; - - /** - * The token database table. - * - * @var string - */ - protected $table; - - /** - * The hashing key. - * - * @var string - */ - protected $hashKey; - - /** - * The number of seconds a token should last. - * - * @var int - */ - protected $expires; - - /** - * Minimum number of seconds before re-redefining the token. - * - * @var int - */ - protected $throttle; - /** * Create a new token repository instance. - * - * @param \Illuminate\Database\ConnectionInterface $connection - * @param \Illuminate\Contracts\Hashing\Hasher $hasher - * @param string $table - * @param string $hashKey - * @param int $expires - * @param int $throttle - * @return void */ public function __construct( - ConnectionInterface $connection, - HasherContract $hasher, - $table, - $hashKey, - $expires = 60, - $throttle = 60, + protected ConnectionInterface $connection, + protected HasherContract $hasher, + protected string $table, + protected string $hashKey, + protected int $expires = 3600, + protected int $throttle = 60, ) { - $this->table = $table; - $this->hasher = $hasher; - $this->hashKey = $hashKey; - $this->expires = $expires * 60; - $this->connection = $connection; - $this->throttle = $throttle; } /** diff --git a/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php b/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php index c388c693df79..ea2020022971 100644 --- a/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php +++ b/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php @@ -104,8 +104,8 @@ protected function createTokenRepository(array $config) $this->app['hash'], $config['table'], $key, - $config['expire'], - $config['throttle'] ?? 0 + ($config['expire'] ?? 60) * 60, + $config['throttle'] ?? 0, ); } From c267676db2d002efeed066a010cde529f130182e Mon Sep 17 00:00:00 2001 From: Caleb White Date: Wed, 11 Dec 2024 10:42:29 -0600 Subject: [PATCH 038/455] [12.x] chore: remove support for Carbon v2 (#53825) * fix: remove carbon addReal* methods * chore: remove support for Carbon v2 --- .github/workflows/tests.yml | 9 --------- composer.json | 2 +- src/Illuminate/Session/Middleware/StartSession.php | 2 +- src/Illuminate/Support/InteractsWithTime.php | 2 +- src/Illuminate/Support/composer.json | 2 +- 5 files changed, 4 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 57bad4a14f75..ca71849701fb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,15 +64,6 @@ jobs: - name: Set Framework version run: composer config version "12.x-dev" - - name: Set Minimum PHP 8.4 Versions - uses: nick-fields/retry@v3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require nesbot/carbon:^3.4 --no-interaction --no-update - shell: bash - if: matrix.php >= 8.4 - - name: Set PHPUnit uses: nick-fields/retry@v3 with: diff --git a/composer.json b/composer.json index a806bb9c8ebf..641855e473e0 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", "monolog/monolog": "^3.0", - "nesbot/carbon": "^2.72.2|^3.4", + "nesbot/carbon": "^3.4", "nunomaduro/termwind": "^2.0", "psr/container": "^1.1.1|^2.0.1", "psr/log": "^1.0|^2.0|^3.0", diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index c6310984673f..5b8da6dda505 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -266,7 +266,7 @@ protected function getCookieExpirationDate() $config = $this->manager->getSessionConfig(); return $config['expire_on_close'] ? 0 : Date::instance( - Carbon::now()->addRealMinutes($config['lifetime']) + Carbon::now()->addMinutes($config['lifetime']) ); } diff --git a/src/Illuminate/Support/InteractsWithTime.php b/src/Illuminate/Support/InteractsWithTime.php index 6a64f12a4ce4..f1fbf27ad49b 100644 --- a/src/Illuminate/Support/InteractsWithTime.php +++ b/src/Illuminate/Support/InteractsWithTime.php @@ -35,7 +35,7 @@ protected function availableAt($delay = 0) return $delay instanceof DateTimeInterface ? $delay->getTimestamp() - : Carbon::now()->addRealSeconds($delay)->getTimestamp(); + : Carbon::now()->addSeconds($delay)->getTimestamp(); } /** diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index c794be90b0f7..3615647b281b 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -23,7 +23,7 @@ "illuminate/conditionable": "^12.0", "illuminate/contracts": "^12.0", "illuminate/macroable": "^12.0", - "nesbot/carbon": "^2.72.2|^3.4", + "nesbot/carbon": "^3.4", "voku/portable-ascii": "^2.0.2" }, "conflict": { From 1b35efa0cf43e38371b2c9d9350475fa78b616c3 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 14:11:23 -0600 Subject: [PATCH 039/455] use promoted properties for Auth events (#53847) - move comments to constructor docblocks --- src/Illuminate/Auth/Events/Attempting.php | 37 ++++--------------- src/Illuminate/Auth/Events/Authenticated.php | 26 +++---------- .../Auth/Events/CurrentDeviceLogout.php | 26 +++---------- src/Illuminate/Auth/Events/Failed.php | 37 ++++--------------- src/Illuminate/Auth/Events/Login.php | 37 ++++--------------- src/Illuminate/Auth/Events/Logout.php | 26 +++---------- .../Auth/Events/OtherDeviceLogout.php | 26 +++---------- src/Illuminate/Auth/Events/PasswordReset.php | 15 ++------ .../Auth/Events/PasswordResetLinkSent.php | 15 ++------ src/Illuminate/Auth/Events/Registered.php | 15 ++------ src/Illuminate/Auth/Events/Validated.php | 26 +++---------- src/Illuminate/Auth/Events/Verified.php | 15 ++------ 12 files changed, 70 insertions(+), 231 deletions(-) diff --git a/src/Illuminate/Auth/Events/Attempting.php b/src/Illuminate/Auth/Events/Attempting.php index e4500e33b735..ac700c9015e5 100644 --- a/src/Illuminate/Auth/Events/Attempting.php +++ b/src/Illuminate/Auth/Events/Attempting.php @@ -4,39 +4,18 @@ class Attempting { - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The credentials for the user. - * - * @var array - */ - public $credentials; - - /** - * Indicates if the user should be "remembered". - * - * @var bool - */ - public $remember; - /** * Create a new event instance. * - * @param string $guard - * @param array $credentials - * @param bool $remember + * @param string $guard The authentication guard name. + * @param array $credentials The credentials for the user. + * @param bool $remember Indicates if the user should be "remembered". * @return void */ - public function __construct($guard, #[\SensitiveParameter] $credentials, $remember) - { - $this->guard = $guard; - $this->remember = $remember; - $this->credentials = $credentials; + public function __construct( + public $guard, + #[\SensitiveParameter] public $credentials, + public $remember, + ) { } } diff --git a/src/Illuminate/Auth/Events/Authenticated.php b/src/Illuminate/Auth/Events/Authenticated.php index faefcbecba3a..c0b0db6cba32 100644 --- a/src/Illuminate/Auth/Events/Authenticated.php +++ b/src/Illuminate/Auth/Events/Authenticated.php @@ -8,30 +8,16 @@ class Authenticated { use SerializesModels; - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. * @return void */ - public function __construct($guard, $user) - { - $this->user = $user; - $this->guard = $guard; + public function __construct( + public $guard, + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/CurrentDeviceLogout.php b/src/Illuminate/Auth/Events/CurrentDeviceLogout.php index 32d31faf6448..8f2e694ffbd5 100644 --- a/src/Illuminate/Auth/Events/CurrentDeviceLogout.php +++ b/src/Illuminate/Auth/Events/CurrentDeviceLogout.php @@ -8,30 +8,16 @@ class CurrentDeviceLogout { use SerializesModels; - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. * @return void */ - public function __construct($guard, $user) - { - $this->user = $user; - $this->guard = $guard; + public function __construct( + public $guard, + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/Failed.php b/src/Illuminate/Auth/Events/Failed.php index b29940e3ae5f..32a5610053b7 100644 --- a/src/Illuminate/Auth/Events/Failed.php +++ b/src/Illuminate/Auth/Events/Failed.php @@ -4,39 +4,18 @@ class Failed { - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The user the attempter was trying to authenticate as. - * - * @var \Illuminate\Contracts\Auth\Authenticatable|null - */ - public $user; - - /** - * The credentials provided by the attempter. - * - * @var array - */ - public $credentials; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user - * @param array $credentials + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user The user the attempter was trying to authenticate as. + * @param array $credentials The credentials provided by the attempter. * @return void */ - public function __construct($guard, $user, #[\SensitiveParameter] $credentials) - { - $this->user = $user; - $this->guard = $guard; - $this->credentials = $credentials; + public function __construct( + public $guard, + public $user, + #[\SensitiveParameter] public $credentials, + ) { } } diff --git a/src/Illuminate/Auth/Events/Login.php b/src/Illuminate/Auth/Events/Login.php index 87a399eab38b..c3e2e69e9832 100644 --- a/src/Illuminate/Auth/Events/Login.php +++ b/src/Illuminate/Auth/Events/Login.php @@ -8,39 +8,18 @@ class Login { use SerializesModels; - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - - /** - * Indicates if the user should be "remembered". - * - * @var bool - */ - public $remember; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param bool $remember + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. + * @param bool $remember Indicates if the user should be "remembered". * @return void */ - public function __construct($guard, $user, $remember) - { - $this->user = $user; - $this->guard = $guard; - $this->remember = $remember; + public function __construct( + public $guard, + public $user, + public $remember, + ) { } } diff --git a/src/Illuminate/Auth/Events/Logout.php b/src/Illuminate/Auth/Events/Logout.php index c47341dc5601..e13693be67e9 100644 --- a/src/Illuminate/Auth/Events/Logout.php +++ b/src/Illuminate/Auth/Events/Logout.php @@ -8,30 +8,16 @@ class Logout { use SerializesModels; - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. * @return void */ - public function __construct($guard, $user) - { - $this->user = $user; - $this->guard = $guard; + public function __construct( + public $guard, + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/OtherDeviceLogout.php b/src/Illuminate/Auth/Events/OtherDeviceLogout.php index ea139a7b496e..5687086910ba 100644 --- a/src/Illuminate/Auth/Events/OtherDeviceLogout.php +++ b/src/Illuminate/Auth/Events/OtherDeviceLogout.php @@ -8,30 +8,16 @@ class OtherDeviceLogout { use SerializesModels; - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable $user \Illuminate\Contracts\Auth\Authenticatable * @return void */ - public function __construct($guard, $user) - { - $this->user = $user; - $this->guard = $guard; + public function __construct( + public $guard, + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/PasswordReset.php b/src/Illuminate/Auth/Events/PasswordReset.php index f57b3c947660..cb09d8a92498 100644 --- a/src/Illuminate/Auth/Events/PasswordReset.php +++ b/src/Illuminate/Auth/Events/PasswordReset.php @@ -8,21 +8,14 @@ class PasswordReset { use SerializesModels; - /** - * The user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable $user The user. * @return void */ - public function __construct($user) - { - $this->user = $user; + public function __construct( + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/PasswordResetLinkSent.php b/src/Illuminate/Auth/Events/PasswordResetLinkSent.php index 233e92db34fd..2540a2e6ee46 100644 --- a/src/Illuminate/Auth/Events/PasswordResetLinkSent.php +++ b/src/Illuminate/Auth/Events/PasswordResetLinkSent.php @@ -8,21 +8,14 @@ class PasswordResetLinkSent { use SerializesModels; - /** - * The user instance. - * - * @var \Illuminate\Contracts\Auth\CanResetPassword - */ - public $user; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\CanResetPassword $user + * @param \Illuminate\Contracts\Auth\CanResetPassword $user The user instance. * @return void */ - public function __construct($user) - { - $this->user = $user; + public function __construct( + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/Registered.php b/src/Illuminate/Auth/Events/Registered.php index f84058cf1fed..646cdaf95051 100644 --- a/src/Illuminate/Auth/Events/Registered.php +++ b/src/Illuminate/Auth/Events/Registered.php @@ -8,21 +8,14 @@ class Registered { use SerializesModels; - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. * @return void */ - public function __construct($user) - { - $this->user = $user; + public function __construct( + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/Validated.php b/src/Illuminate/Auth/Events/Validated.php index ebc3b2ce1797..5cd01a533363 100644 --- a/src/Illuminate/Auth/Events/Validated.php +++ b/src/Illuminate/Auth/Events/Validated.php @@ -8,30 +8,16 @@ class Validated { use SerializesModels; - /** - * The authentication guard name. - * - * @var string - */ - public $guard; - - /** - * The user retrieved and validated from the User Provider. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public $user; - /** * Create a new event instance. * - * @param string $guard - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard The authentication guard name. + * @param \Illuminate\Contracts\Auth\Authenticatable $user The user retrieved and validated from the User Provider. * @return void */ - public function __construct($guard, $user) - { - $this->user = $user; - $this->guard = $guard; + public function __construct( + public $guard, + public $user, + ) { } } diff --git a/src/Illuminate/Auth/Events/Verified.php b/src/Illuminate/Auth/Events/Verified.php index 1d6e4c0f3448..03c2aff12e81 100644 --- a/src/Illuminate/Auth/Events/Verified.php +++ b/src/Illuminate/Auth/Events/Verified.php @@ -8,21 +8,14 @@ class Verified { use SerializesModels; - /** - * The verified user. - * - * @var \Illuminate\Contracts\Auth\MustVerifyEmail - */ - public $user; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\MustVerifyEmail $user + * @param \Illuminate\Contracts\Auth\MustVerifyEmail $user The verified user. * @return void */ - public function __construct($user) - { - $this->user = $user; + public function __construct( + public $user, + ) { } } From 153bab92b38252266b2885ece2f239e9b80d3dc1 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 14:27:08 -0600 Subject: [PATCH 040/455] use promoted properties for Database events (#53848) - transposed comments to constructor docblock --- .../Database/Events/DatabaseBusy.php | 26 +++++-------------- .../Database/Events/DatabaseRefreshed.php | 1 - .../Database/Events/MigrationsEvent.php | 15 +++-------- .../Database/Events/ModelPruningFinished.php | 15 +++-------- .../Database/Events/ModelPruningStarting.php | 15 +++-------- .../Database/Events/ModelsPruned.php | 26 +++++-------------- .../Database/Events/NoPendingMigrations.php | 15 +++-------- .../Database/Events/StatementPrepared.php | 26 +++++-------------- 8 files changed, 34 insertions(+), 105 deletions(-) diff --git a/src/Illuminate/Database/Events/DatabaseBusy.php b/src/Illuminate/Database/Events/DatabaseBusy.php index 8e903a907535..04fc40bf3cd1 100644 --- a/src/Illuminate/Database/Events/DatabaseBusy.php +++ b/src/Illuminate/Database/Events/DatabaseBusy.php @@ -4,29 +4,15 @@ class DatabaseBusy { - /** - * The database connection name. - * - * @var string - */ - public $connectionName; - - /** - * The number of open connections. - * - * @var int - */ - public $connections; - /** * Create a new event instance. * - * @param string $connectionName - * @param int $connections + * @param string $connectionName The database connection name. + * @param int $connections The number of open connections. */ - public function __construct($connectionName, $connections) - { - $this->connectionName = $connectionName; - $this->connections = $connections; + public function __construct( + public $connectionName, + public $connections, + ) { } } diff --git a/src/Illuminate/Database/Events/DatabaseRefreshed.php b/src/Illuminate/Database/Events/DatabaseRefreshed.php index 0610269e22cd..5c9fd45bb314 100644 --- a/src/Illuminate/Database/Events/DatabaseRefreshed.php +++ b/src/Illuminate/Database/Events/DatabaseRefreshed.php @@ -17,6 +17,5 @@ public function __construct( public ?string $database = null, public bool $seeding = false, ) { - // } } diff --git a/src/Illuminate/Database/Events/MigrationsEvent.php b/src/Illuminate/Database/Events/MigrationsEvent.php index c1f465a3c202..a7d0ec1678c0 100644 --- a/src/Illuminate/Database/Events/MigrationsEvent.php +++ b/src/Illuminate/Database/Events/MigrationsEvent.php @@ -6,21 +6,14 @@ abstract class MigrationsEvent implements MigrationEventContract { - /** - * The migration method that was invoked. - * - * @var string - */ - public $method; - /** * Create a new event instance. * - * @param string $method + * @param string $method The migration method that was invoked. * @return void */ - public function __construct($method) - { - $this->method = $method; + public function __construct( + public $method, + ) { } } diff --git a/src/Illuminate/Database/Events/ModelPruningFinished.php b/src/Illuminate/Database/Events/ModelPruningFinished.php index d2701c4743c2..034c971df97a 100644 --- a/src/Illuminate/Database/Events/ModelPruningFinished.php +++ b/src/Illuminate/Database/Events/ModelPruningFinished.php @@ -4,21 +4,14 @@ class ModelPruningFinished { - /** - * The class names of the models that were pruned. - * - * @var array - */ - public $models; - /** * Create a new event instance. * - * @param array $models + * @param array $models The class names of the models that were pruned. * @return void */ - public function __construct($models) - { - $this->models = $models; + public function __construct( + public $models, + ) { } } diff --git a/src/Illuminate/Database/Events/ModelPruningStarting.php b/src/Illuminate/Database/Events/ModelPruningStarting.php index e6cc4d8426a9..7737a1442e4f 100644 --- a/src/Illuminate/Database/Events/ModelPruningStarting.php +++ b/src/Illuminate/Database/Events/ModelPruningStarting.php @@ -4,21 +4,14 @@ class ModelPruningStarting { - /** - * The class names of the models that will be pruned. - * - * @var array - */ - public $models; - /** * Create a new event instance. * - * @param array $models + * @param array $models The class names of the models that will be pruned. * @return void */ - public function __construct($models) - { - $this->models = $models; + public function __construct( + public $models + ) { } } diff --git a/src/Illuminate/Database/Events/ModelsPruned.php b/src/Illuminate/Database/Events/ModelsPruned.php index ca8bee9e0f5d..08e9f7fb0d6d 100644 --- a/src/Illuminate/Database/Events/ModelsPruned.php +++ b/src/Illuminate/Database/Events/ModelsPruned.php @@ -4,30 +4,16 @@ class ModelsPruned { - /** - * The class name of the model that was pruned. - * - * @var string - */ - public $model; - - /** - * The number of pruned records. - * - * @var int - */ - public $count; - /** * Create a new event instance. * - * @param string $model - * @param int $count + * @param string $model The class name of the model that was pruned. + * @param int $count The number of pruned records. * @return void */ - public function __construct($model, $count) - { - $this->model = $model; - $this->count = $count; + public function __construct( + public $model, + public $count, + ) { } } diff --git a/src/Illuminate/Database/Events/NoPendingMigrations.php b/src/Illuminate/Database/Events/NoPendingMigrations.php index 100f78667080..2850a7c2cbcc 100644 --- a/src/Illuminate/Database/Events/NoPendingMigrations.php +++ b/src/Illuminate/Database/Events/NoPendingMigrations.php @@ -4,21 +4,14 @@ class NoPendingMigrations { - /** - * The migration method that was called. - * - * @var string - */ - public $method; - /** * Create a new event instance. * - * @param string $method + * @param string $method The migration method that was called. * @return void */ - public function __construct($method) - { - $this->method = $method; + public function __construct( + public $method, + ) { } } diff --git a/src/Illuminate/Database/Events/StatementPrepared.php b/src/Illuminate/Database/Events/StatementPrepared.php index 2f603235da25..30b3e4bb7ebe 100644 --- a/src/Illuminate/Database/Events/StatementPrepared.php +++ b/src/Illuminate/Database/Events/StatementPrepared.php @@ -4,30 +4,16 @@ class StatementPrepared { - /** - * The database connection instance. - * - * @var \Illuminate\Database\Connection - */ - public $connection; - - /** - * The PDO statement. - * - * @var \PDOStatement - */ - public $statement; - /** * Create a new event instance. * - * @param \Illuminate\Database\Connection $connection - * @param \PDOStatement $statement + * @param \Illuminate\Database\Connection $connection The database connection instance. + * @param \PDOStatement $statement The PDO statement. * @return void */ - public function __construct($connection, $statement) - { - $this->statement = $statement; - $this->connection = $connection; + public function __construct( + public $connection, + public $statement, + ) { } } From 10e4136390e02705ac19cd9fb04a039bbebef5ba Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 16:50:29 -0600 Subject: [PATCH 041/455] use promoted properties for Console events (#53851) - move property comments to constructor docblock there is technically a small change in this commit. because the properties are `public`, even though the constructor type hints what it accepts, techically the properties could have been set to anything. this change tightens things up slightly so whether the properties are being set via the constructor or via direct property access, they **must** be the desired type. this commit also highlight a benefit of moving to promoted properties in that we don't duplicate certain code or docblocks that could accidentally become out of sync. for example, in the `CommandStarting` class, the `$input` property is hinted as `\Symfony\Component\Console\Input\InputInterface|null`, while the constructor does not allow `null`. --- .../Console/Events/ArtisanStarting.php | 15 ++---- .../Console/Events/CommandFinished.php | 48 ++++--------------- .../Console/Events/CommandStarting.php | 37 ++++---------- .../ScheduledBackgroundTaskFinished.php | 15 ++---- .../Console/Events/ScheduledTaskFailed.php | 26 +++------- .../Console/Events/ScheduledTaskFinished.php | 26 +++------- .../Console/Events/ScheduledTaskSkipped.php | 15 ++---- .../Console/Events/ScheduledTaskStarting.php | 15 ++---- 8 files changed, 46 insertions(+), 151 deletions(-) diff --git a/src/Illuminate/Console/Events/ArtisanStarting.php b/src/Illuminate/Console/Events/ArtisanStarting.php index f228ac529635..9a6e4b0b9d65 100644 --- a/src/Illuminate/Console/Events/ArtisanStarting.php +++ b/src/Illuminate/Console/Events/ArtisanStarting.php @@ -4,21 +4,14 @@ class ArtisanStarting { - /** - * The Artisan application instance. - * - * @var \Illuminate\Console\Application - */ - public $artisan; - /** * Create a new event instance. * - * @param \Illuminate\Console\Application $artisan + * @param \Illuminate\Console\Application $artisan The Artisan application instance. * @return void */ - public function __construct($artisan) - { - $this->artisan = $artisan; + public function __construct( + public $artisan, + ) { } } diff --git a/src/Illuminate/Console/Events/CommandFinished.php b/src/Illuminate/Console/Events/CommandFinished.php index ef066af31935..56438782121a 100644 --- a/src/Illuminate/Console/Events/CommandFinished.php +++ b/src/Illuminate/Console/Events/CommandFinished.php @@ -7,48 +7,20 @@ class CommandFinished { - /** - * The command name. - * - * @var string - */ - public $command; - - /** - * The console input implementation. - * - * @var \Symfony\Component\Console\Input\InputInterface|null - */ - public $input; - - /** - * The command output implementation. - * - * @var \Symfony\Component\Console\Output\OutputInterface|null - */ - public $output; - - /** - * The command exit code. - * - * @var int - */ - public $exitCode; - /** * Create a new event instance. * - * @param string $command - * @param \Symfony\Component\Console\Input\InputInterface $input - * @param \Symfony\Component\Console\Output\OutputInterface $output - * @param int $exitCode + * @param string $command The command name. + * @param \Symfony\Component\Console\Input\InputInterface $input The console input implementation. + * @param \Symfony\Component\Console\Output\OutputInterface $output The command output implementation. + * @param int $exitCode The command exit code. * @return void */ - public function __construct($command, InputInterface $input, OutputInterface $output, $exitCode) - { - $this->input = $input; - $this->output = $output; - $this->command = $command; - $this->exitCode = $exitCode; + public function __construct( + public $command, + public InputInterface $input, + public OutputInterface $output, + public $exitCode, + ) { } } diff --git a/src/Illuminate/Console/Events/CommandStarting.php b/src/Illuminate/Console/Events/CommandStarting.php index c6238b5dc3d9..e43ac6700629 100644 --- a/src/Illuminate/Console/Events/CommandStarting.php +++ b/src/Illuminate/Console/Events/CommandStarting.php @@ -7,39 +7,18 @@ class CommandStarting { - /** - * The command name. - * - * @var string - */ - public $command; - - /** - * The console input implementation. - * - * @var \Symfony\Component\Console\Input\InputInterface|null - */ - public $input; - - /** - * The command output implementation. - * - * @var \Symfony\Component\Console\Output\OutputInterface|null - */ - public $output; - /** * Create a new event instance. * - * @param string $command - * @param \Symfony\Component\Console\Input\InputInterface $input - * @param \Symfony\Component\Console\Output\OutputInterface $output + * @param string $command The command name. + * @param \Symfony\Component\Console\Input\InputInterface $input The console input implementation. + * @param \Symfony\Component\Console\Output\OutputInterface $output The command output implementation. * @return void */ - public function __construct($command, InputInterface $input, OutputInterface $output) - { - $this->input = $input; - $this->output = $output; - $this->command = $command; + public function __construct( + public $command, + public InputInterface $input, + public OutputInterface $output, + ) { } } diff --git a/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php b/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php index d9e63c2e58d5..cdc22c975169 100644 --- a/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php +++ b/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php @@ -6,21 +6,14 @@ class ScheduledBackgroundTaskFinished { - /** - * The scheduled event that ran. - * - * @var \Illuminate\Console\Scheduling\Event - */ - public $task; - /** * Create a new event instance. * - * @param \Illuminate\Console\Scheduling\Event $task + * @param \Illuminate\Console\Scheduling\Event $task The scheduled event that ran. * @return void */ - public function __construct(Event $task) - { - $this->task = $task; + public function __construct( + public Event $task, + ) { } } diff --git a/src/Illuminate/Console/Events/ScheduledTaskFailed.php b/src/Illuminate/Console/Events/ScheduledTaskFailed.php index 46857ad849a7..66aa004e9929 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskFailed.php +++ b/src/Illuminate/Console/Events/ScheduledTaskFailed.php @@ -7,30 +7,16 @@ class ScheduledTaskFailed { - /** - * The scheduled event that failed. - * - * @var \Illuminate\Console\Scheduling\Event - */ - public $task; - - /** - * The exception that was thrown. - * - * @var \Throwable - */ - public $exception; - /** * Create a new event instance. * - * @param \Illuminate\Console\Scheduling\Event $task - * @param \Throwable $exception + * @param \Illuminate\Console\Scheduling\Event $task The scheduled event that failed. + * @param \Throwable $exception The exception that was thrown. * @return void */ - public function __construct(Event $task, Throwable $exception) - { - $this->task = $task; - $this->exception = $exception; + public function __construct( + public Event $task, + public Throwable $exception, + ) { } } diff --git a/src/Illuminate/Console/Events/ScheduledTaskFinished.php b/src/Illuminate/Console/Events/ScheduledTaskFinished.php index 6146966229e9..f41896b715f2 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskFinished.php +++ b/src/Illuminate/Console/Events/ScheduledTaskFinished.php @@ -6,30 +6,16 @@ class ScheduledTaskFinished { - /** - * The scheduled event that ran. - * - * @var \Illuminate\Console\Scheduling\Event - */ - public $task; - - /** - * The runtime of the scheduled event. - * - * @var float - */ - public $runtime; - /** * Create a new event instance. * - * @param \Illuminate\Console\Scheduling\Event $task - * @param float $runtime + * @param \Illuminate\Console\Scheduling\Event $task The scheduled event that ran. + * @param float $runtime The runtime of the scheduled event. * @return void */ - public function __construct(Event $task, $runtime) - { - $this->task = $task; - $this->runtime = $runtime; + public function __construct( + public Event $task, + public $runtime, + ) { } } diff --git a/src/Illuminate/Console/Events/ScheduledTaskSkipped.php b/src/Illuminate/Console/Events/ScheduledTaskSkipped.php index cfa7141da9b7..661f8f807e36 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskSkipped.php +++ b/src/Illuminate/Console/Events/ScheduledTaskSkipped.php @@ -6,21 +6,14 @@ class ScheduledTaskSkipped { - /** - * The scheduled event being run. - * - * @var \Illuminate\Console\Scheduling\Event - */ - public $task; - /** * Create a new event instance. * - * @param \Illuminate\Console\Scheduling\Event $task + * @param \Illuminate\Console\Scheduling\Event $task The scheduled event being run. * @return void */ - public function __construct(Event $task) - { - $this->task = $task; + public function __construct( + public Event $task, + ) { } } diff --git a/src/Illuminate/Console/Events/ScheduledTaskStarting.php b/src/Illuminate/Console/Events/ScheduledTaskStarting.php index 66aaaa4c0de7..dfdf18494df4 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskStarting.php +++ b/src/Illuminate/Console/Events/ScheduledTaskStarting.php @@ -6,21 +6,14 @@ class ScheduledTaskStarting { - /** - * The scheduled event being run. - * - * @var \Illuminate\Console\Scheduling\Event - */ - public $task; - /** * Create a new event instance. * - * @param \Illuminate\Console\Scheduling\Event $task + * @param \Illuminate\Console\Scheduling\Event $task The scheduled event being run. * @return void */ - public function __construct(Event $task) - { - $this->task = $task; + public function __construct( + public Event $task, + ) { } } From 29b4ed253abe0f406078f04f3b24e1cec0139e36 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 16:50:43 -0600 Subject: [PATCH 042/455] use promoted properties for Mail events (#53852) - move property comments to constructor docblock - add type hints to `public` properties - rename `MessageSent` constructor parameter `$message` to `$sent` to match property name --- src/Illuminate/Mail/Events/MessageSending.php | 26 +++++-------------- src/Illuminate/Mail/Events/MessageSent.php | 26 +++++-------------- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/src/Illuminate/Mail/Events/MessageSending.php b/src/Illuminate/Mail/Events/MessageSending.php index 31435fb6e0e7..3353a43c26dc 100644 --- a/src/Illuminate/Mail/Events/MessageSending.php +++ b/src/Illuminate/Mail/Events/MessageSending.php @@ -6,30 +6,16 @@ class MessageSending { - /** - * The Symfony Email instance. - * - * @var \Symfony\Component\Mime\Email - */ - public $message; - - /** - * The message data. - * - * @var array - */ - public $data; - /** * Create a new event instance. * - * @param \Symfony\Component\Mime\Email $message - * @param array $data + * @param \Symfony\Component\Mime\Email $message The Symfony Email instance. + * @param array $data The message data. * @return void */ - public function __construct(Email $message, array $data = []) - { - $this->data = $data; - $this->message = $message; + public function __construct( + public Email $message, + public array $data = [], + ) { } } diff --git a/src/Illuminate/Mail/Events/MessageSent.php b/src/Illuminate/Mail/Events/MessageSent.php index 954704c14557..1634676aa02d 100644 --- a/src/Illuminate/Mail/Events/MessageSent.php +++ b/src/Illuminate/Mail/Events/MessageSent.php @@ -11,31 +11,17 @@ */ class MessageSent { - /** - * The message that was sent. - * - * @var \Illuminate\Mail\SentMessage - */ - public $sent; - - /** - * The message data. - * - * @var array - */ - public $data; - /** * Create a new event instance. * - * @param \Illuminate\Mail\SentMessage $message - * @param array $data + * @param \Illuminate\Mail\SentMessage $sent The message that was sent. + * @param array $data The message data. * @return void */ - public function __construct(SentMessage $message, array $data = []) - { - $this->sent = $message; - $this->data = $data; + public function __construct( + public SentMessage $sent, + public array $data = [], + ) { } /** From 4d4174ea4e113e847bcb1fb89a6e02432c4cbbcb Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 16:50:53 -0600 Subject: [PATCH 043/455] use promoted properties for Notification events (#53853) - move comments from properties to constructor docblock --- .../Events/BroadcastNotificationCreated.php | 37 ++++---------- .../Events/NotificationFailed.php | 48 ++++--------------- .../Events/NotificationSending.php | 37 ++++---------- .../Notifications/Events/NotificationSent.php | 48 ++++--------------- 4 files changed, 36 insertions(+), 134 deletions(-) diff --git a/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php b/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php index 44cb41019b79..2ee62c66b417 100644 --- a/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php +++ b/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php @@ -14,40 +14,19 @@ class BroadcastNotificationCreated implements ShouldBroadcast { use Queueable, SerializesModels; - /** - * The notifiable entity who received the notification. - * - * @var mixed - */ - public $notifiable; - - /** - * The notification instance. - * - * @var \Illuminate\Notifications\Notification - */ - public $notification; - - /** - * The notification data. - * - * @var array - */ - public $data = []; - /** * Create a new event instance. * - * @param mixed $notifiable - * @param \Illuminate\Notifications\Notification $notification - * @param array $data + * @param mixed $notifiable The notifiable entity who received the notification. + * @param \Illuminate\Notifications\Notification $notification The notification instance. + * @param array $data The notification data. * @return void */ - public function __construct($notifiable, $notification, $data) - { - $this->data = $data; - $this->notifiable = $notifiable; - $this->notification = $notification; + public function __construct( + public $notifiable, + public $notification, + public $data = [], + ) { } /** diff --git a/src/Illuminate/Notifications/Events/NotificationFailed.php b/src/Illuminate/Notifications/Events/NotificationFailed.php index b69e1c5485af..b550333642bc 100644 --- a/src/Illuminate/Notifications/Events/NotificationFailed.php +++ b/src/Illuminate/Notifications/Events/NotificationFailed.php @@ -9,48 +9,20 @@ class NotificationFailed { use Queueable, SerializesModels; - /** - * The notifiable entity who received the notification. - * - * @var mixed - */ - public $notifiable; - - /** - * The notification instance. - * - * @var \Illuminate\Notifications\Notification - */ - public $notification; - - /** - * The channel name. - * - * @var string - */ - public $channel; - - /** - * The data needed to process this failure. - * - * @var array - */ - public $data = []; - /** * Create a new event instance. * - * @param mixed $notifiable - * @param \Illuminate\Notifications\Notification $notification - * @param string $channel - * @param array $data + * @param mixed $notifiable The notifiable entity who received the notification. + * @param \Illuminate\Notifications\Notification $notification The notification instance. + * @param string $channel The channel name. + * @param array $data The data needed to process this failure. * @return void */ - public function __construct($notifiable, $notification, $channel, $data = []) - { - $this->data = $data; - $this->channel = $channel; - $this->notifiable = $notifiable; - $this->notification = $notification; + public function __construct( + public $notifiable, + public $notification, + public $channel, + public $data = [], + ) { } } diff --git a/src/Illuminate/Notifications/Events/NotificationSending.php b/src/Illuminate/Notifications/Events/NotificationSending.php index 6efd1d06de93..2f4972a383db 100644 --- a/src/Illuminate/Notifications/Events/NotificationSending.php +++ b/src/Illuminate/Notifications/Events/NotificationSending.php @@ -9,39 +9,18 @@ class NotificationSending { use Queueable, SerializesModels; - /** - * The notifiable entity who received the notification. - * - * @var mixed - */ - public $notifiable; - - /** - * The notification instance. - * - * @var \Illuminate\Notifications\Notification - */ - public $notification; - - /** - * The channel name. - * - * @var string - */ - public $channel; - /** * Create a new event instance. * - * @param mixed $notifiable - * @param \Illuminate\Notifications\Notification $notification - * @param string $channel + * @param mixed $notifiable The notifiable entity who received the notification. + * @param \Illuminate\Notifications\Notification $notification The notification instance. + * @param string $channel The channel name. * @return void */ - public function __construct($notifiable, $notification, $channel) - { - $this->channel = $channel; - $this->notifiable = $notifiable; - $this->notification = $notification; + public function __construct( + public $notifiable, + public $notification, + public $channel, + ) { } } diff --git a/src/Illuminate/Notifications/Events/NotificationSent.php b/src/Illuminate/Notifications/Events/NotificationSent.php index 4f09069148eb..8c7cd8190c4b 100644 --- a/src/Illuminate/Notifications/Events/NotificationSent.php +++ b/src/Illuminate/Notifications/Events/NotificationSent.php @@ -9,48 +9,20 @@ class NotificationSent { use Queueable, SerializesModels; - /** - * The notifiable entity who received the notification. - * - * @var mixed - */ - public $notifiable; - - /** - * The notification instance. - * - * @var \Illuminate\Notifications\Notification - */ - public $notification; - - /** - * The channel name. - * - * @var string - */ - public $channel; - - /** - * The channel's response. - * - * @var mixed - */ - public $response; - /** * Create a new event instance. * - * @param mixed $notifiable - * @param \Illuminate\Notifications\Notification $notification - * @param string $channel - * @param mixed $response + * @param mixed $notifiable The notifiable entity who received the notification. + * @param \Illuminate\Notifications\Notification $notification The notification instance. + * @param string $channel The channel name. + * @param mixed $response The channel's response. * @return void */ - public function __construct($notifiable, $notification, $channel, $response = null) - { - $this->channel = $channel; - $this->response = $response; - $this->notifiable = $notifiable; - $this->notification = $notification; + public function __construct( + public $notifiable, + public $notification, + public $channel, + public $response = null, + ) { } } From 83cc5f665f1bc8e07960fae516ae629abfe3f185 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 16:51:15 -0600 Subject: [PATCH 044/455] use promoted properties for Routing events (#53854) - move comments from properties to construtor docblock --- .../Routing/Events/PreparingResponse.php | 26 +++++-------------- .../Routing/Events/ResponsePrepared.php | 26 +++++-------------- .../Routing/Events/RouteMatched.php | 26 +++++-------------- src/Illuminate/Routing/Events/Routing.php | 15 +++-------- 4 files changed, 22 insertions(+), 71 deletions(-) diff --git a/src/Illuminate/Routing/Events/PreparingResponse.php b/src/Illuminate/Routing/Events/PreparingResponse.php index 2c060a02ac93..f427431fcde1 100644 --- a/src/Illuminate/Routing/Events/PreparingResponse.php +++ b/src/Illuminate/Routing/Events/PreparingResponse.php @@ -4,30 +4,16 @@ class PreparingResponse { - /** - * The request instance. - * - * @var \Symfony\Component\HttpFoundation\Request - */ - public $request; - - /** - * The response instance. - * - * @var mixed - */ - public $response; - /** * Create a new event instance. * - * @param \Symfony\Component\HttpFoundation\Request $request - * @param mixed $response + * @param \Symfony\Component\HttpFoundation\Request $request The request instance. + * @param mixed $response The response instance. * @return void */ - public function __construct($request, $response) - { - $this->request = $request; - $this->response = $response; + public function __construct( + public $request, + public $response, + ) { } } diff --git a/src/Illuminate/Routing/Events/ResponsePrepared.php b/src/Illuminate/Routing/Events/ResponsePrepared.php index 5fb866d289f4..549d9b49c77e 100644 --- a/src/Illuminate/Routing/Events/ResponsePrepared.php +++ b/src/Illuminate/Routing/Events/ResponsePrepared.php @@ -4,30 +4,16 @@ class ResponsePrepared { - /** - * The request instance. - * - * @var \Symfony\Component\HttpFoundation\Request - */ - public $request; - - /** - * The response instance. - * - * @var \Symfony\Component\HttpFoundation\Response - */ - public $response; - /** * Create a new event instance. * - * @param \Symfony\Component\HttpFoundation\Request $request - * @param \Symfony\Component\HttpFoundation\Response $response + * @param \Symfony\Component\HttpFoundation\Request $request The request instance. + * @param \Symfony\Component\HttpFoundation\Response $response The response instance. * @return void */ - public function __construct($request, $response) - { - $this->request = $request; - $this->response = $response; + public function __construct( + public $request, + public $response, + ) { } } diff --git a/src/Illuminate/Routing/Events/RouteMatched.php b/src/Illuminate/Routing/Events/RouteMatched.php index c8486071737d..eb73ee796bce 100644 --- a/src/Illuminate/Routing/Events/RouteMatched.php +++ b/src/Illuminate/Routing/Events/RouteMatched.php @@ -4,30 +4,16 @@ class RouteMatched { - /** - * The route instance. - * - * @var \Illuminate\Routing\Route - */ - public $route; - - /** - * The request instance. - * - * @var \Illuminate\Http\Request - */ - public $request; - /** * Create a new event instance. * - * @param \Illuminate\Routing\Route $route - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Routing\Route $route The route instance. + * @param \Illuminate\Http\Request $request The request instance. * @return void */ - public function __construct($route, $request) - { - $this->route = $route; - $this->request = $request; + public function __construct( + public $route, + public $request, + ) { } } diff --git a/src/Illuminate/Routing/Events/Routing.php b/src/Illuminate/Routing/Events/Routing.php index af1bb48d32bd..2bb7919eefa5 100644 --- a/src/Illuminate/Routing/Events/Routing.php +++ b/src/Illuminate/Routing/Events/Routing.php @@ -4,21 +4,14 @@ class Routing { - /** - * The request instance. - * - * @var \Illuminate\Http\Request - */ - public $request; - /** * Create a new event instance. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request The request instance. * @return void */ - public function __construct($request) - { - $this->request = $request; + public function __construct( + public $request, + ) { } } From 0a88e5007c6ec02e7e0bb3b13ccc0e68a5d5b1a7 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 11 Dec 2024 16:52:10 -0600 Subject: [PATCH 045/455] use promoted properties for Queue events (#53855) - move comments from properites to constructor docblock --- src/Illuminate/Queue/Events/JobAttempted.php | 37 +++------- .../Queue/Events/JobExceptionOccurred.php | 37 +++------- src/Illuminate/Queue/Events/JobFailed.php | 37 +++------- src/Illuminate/Queue/Events/JobPopped.php | 26 ++----- src/Illuminate/Queue/Events/JobPopping.php | 15 ++-- src/Illuminate/Queue/Events/JobProcessed.php | 26 ++----- src/Illuminate/Queue/Events/JobProcessing.php | 26 ++----- src/Illuminate/Queue/Events/JobQueued.php | 70 ++++--------------- src/Illuminate/Queue/Events/JobQueueing.php | 59 ++++------------ .../Events/JobReleasedAfterException.php | 26 ++----- .../Queue/Events/JobRetryRequested.php | 15 ++-- src/Illuminate/Queue/Events/JobTimedOut.php | 26 ++----- src/Illuminate/Queue/Events/Looping.php | 26 ++----- src/Illuminate/Queue/Events/QueueBusy.php | 37 +++------- .../Queue/Events/WorkerStopping.php | 26 ++----- 15 files changed, 108 insertions(+), 381 deletions(-) diff --git a/src/Illuminate/Queue/Events/JobAttempted.php b/src/Illuminate/Queue/Events/JobAttempted.php index 6dfa2df148ab..b2303143c77d 100644 --- a/src/Illuminate/Queue/Events/JobAttempted.php +++ b/src/Illuminate/Queue/Events/JobAttempted.php @@ -4,40 +4,19 @@ class JobAttempted { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - - /** - * Indicates if an exception occurred while processing the job. - * - * @var bool - */ - public $exceptionOccurred; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job - * @param bool $exceptionOccurred + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. + * @param bool $exceptionOccurred Indicates if an exception occurred while processing the job. * @return void */ - public function __construct($connectionName, $job, $exceptionOccurred = false) - { - $this->job = $job; - $this->connectionName = $connectionName; - $this->exceptionOccurred = $exceptionOccurred; + public function __construct( + public $connectionName, + public $job, + public $exceptionOccurred = false, + ) { } /** diff --git a/src/Illuminate/Queue/Events/JobExceptionOccurred.php b/src/Illuminate/Queue/Events/JobExceptionOccurred.php index 4bdf39226bf7..301bd524f86b 100644 --- a/src/Illuminate/Queue/Events/JobExceptionOccurred.php +++ b/src/Illuminate/Queue/Events/JobExceptionOccurred.php @@ -4,39 +4,18 @@ class JobExceptionOccurred { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - - /** - * The exception instance. - * - * @var \Throwable - */ - public $exception; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job - * @param \Throwable $exception + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. + * @param \Throwable $exception The exception instance. * @return void */ - public function __construct($connectionName, $job, $exception) - { - $this->job = $job; - $this->exception = $exception; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $job, + public $exception, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobFailed.php b/src/Illuminate/Queue/Events/JobFailed.php index d973a5039ed8..a39fdedad592 100644 --- a/src/Illuminate/Queue/Events/JobFailed.php +++ b/src/Illuminate/Queue/Events/JobFailed.php @@ -4,39 +4,18 @@ class JobFailed { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - - /** - * The exception that caused the job to fail. - * - * @var \Throwable - */ - public $exception; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job - * @param \Throwable $exception + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. + * @param \Throwable $exception The exception that caused the job to fail. * @return void */ - public function __construct($connectionName, $job, $exception) - { - $this->job = $job; - $this->exception = $exception; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $job, + public $exception, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobPopped.php b/src/Illuminate/Queue/Events/JobPopped.php index e56e11d30899..ca907a8c7dff 100644 --- a/src/Illuminate/Queue/Events/JobPopped.php +++ b/src/Illuminate/Queue/Events/JobPopped.php @@ -4,30 +4,16 @@ class JobPopped { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job|null - */ - public $job; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job|null $job + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job|null $job The job instance. * @return void */ - public function __construct($connectionName, $job) - { - $this->connectionName = $connectionName; - $this->job = $job; + public function __construct( + public $connectionName, + public $job, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobPopping.php b/src/Illuminate/Queue/Events/JobPopping.php index abb0bb41da7f..1eb5fd6970a7 100644 --- a/src/Illuminate/Queue/Events/JobPopping.php +++ b/src/Illuminate/Queue/Events/JobPopping.php @@ -4,21 +4,14 @@ class JobPopping { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - /** * Create a new event instance. * - * @param string $connectionName + * @param string $connectionName The connection name. * @return void */ - public function __construct($connectionName) - { - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobProcessed.php b/src/Illuminate/Queue/Events/JobProcessed.php index f8abefb67f57..e7b8ce17c068 100644 --- a/src/Illuminate/Queue/Events/JobProcessed.php +++ b/src/Illuminate/Queue/Events/JobProcessed.php @@ -4,30 +4,16 @@ class JobProcessed { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @return void */ - public function __construct($connectionName, $job) - { - $this->job = $job; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $job, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobProcessing.php b/src/Illuminate/Queue/Events/JobProcessing.php index 3dd97248b003..a48cc15aa195 100644 --- a/src/Illuminate/Queue/Events/JobProcessing.php +++ b/src/Illuminate/Queue/Events/JobProcessing.php @@ -4,30 +4,16 @@ class JobProcessing { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @return void */ - public function __construct($connectionName, $job) - { - $this->job = $job; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $job, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobQueued.php b/src/Illuminate/Queue/Events/JobQueued.php index 5e992238aa85..68667876bfe3 100644 --- a/src/Illuminate/Queue/Events/JobQueued.php +++ b/src/Illuminate/Queue/Events/JobQueued.php @@ -4,67 +4,25 @@ class JobQueued { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The queue name. - * - * @var string|null - */ - public $queue; - - /** - * The job ID. - * - * @var string|int|null - */ - public $id; - - /** - * The job instance. - * - * @var \Closure|string|object - */ - public $job; - - /** - * The job payload. - * - * @var string - */ - public $payload; - - /** - * The amount of time the job was delayed. - * - * @var int|null - */ - public $delay; - /** * Create a new event instance. * - * @param string $connectionName - * @param string $queue - * @param string|int|null $id - * @param \Closure|string|object $job - * @param string $payload - * @param int|null $delay + * @param string $connectionName The connection name. + * @param string $queue The queue name. + * @param string|int|null $id The job ID. + * @param \Closure|string|object $job The job instance. + * @param string $payload The job payload. + * @param int|null $delay The amount of time the job was delayed. * @return void */ - public function __construct($connectionName, $queue, $id, $job, $payload, $delay) - { - $this->connectionName = $connectionName; - $this->queue = $queue; - $this->id = $id; - $this->job = $job; - $this->payload = $payload; - $this->delay = $delay; + public function __construct( + public $connectionName, + public $queue, + public $id, + public $job, + public $payload, + public $delay, + ) { } /** diff --git a/src/Illuminate/Queue/Events/JobQueueing.php b/src/Illuminate/Queue/Events/JobQueueing.php index 6a35a64b8cca..ef97e1e71395 100644 --- a/src/Illuminate/Queue/Events/JobQueueing.php +++ b/src/Illuminate/Queue/Events/JobQueueing.php @@ -4,58 +4,23 @@ class JobQueueing { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The queue name. - * - * @var string - */ - public $queue; - - /** - * The job instance. - * - * @var \Closure|string|object - */ - public $job; - - /** - * The job payload. - * - * @var string - */ - public $payload; - - /** - * The number of seconds the job was delayed. - * - * @var int|null - */ - public $delay; - /** * Create a new event instance. * - * @param string $connectionName - * @param string $queue - * @param \Closure|string|object $job - * @param string $payload - * @param int|null $delay + * @param string $connectionName The connection name. + * @param string $queue The queue name. + * @param \Closure|string|object $job The job instance. + * @param string $payload The job payload. + * @param int|null $delay The number of seconds the job was delayed. * @return void */ - public function __construct($connectionName, $queue, $job, $payload, $delay) - { - $this->connectionName = $connectionName; - $this->queue = $queue; - $this->job = $job; - $this->payload = $payload; - $this->delay = $delay; + public function __construct( + public $connectionName, + public $queue, + public $job, + public $payload, + public $delay, + ) { } /** diff --git a/src/Illuminate/Queue/Events/JobReleasedAfterException.php b/src/Illuminate/Queue/Events/JobReleasedAfterException.php index 4600c0b14bd3..b2271ed4134a 100644 --- a/src/Illuminate/Queue/Events/JobReleasedAfterException.php +++ b/src/Illuminate/Queue/Events/JobReleasedAfterException.php @@ -4,30 +4,16 @@ class JobReleasedAfterException { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @return void */ - public function __construct($connectionName, $job) - { - $this->job = $job; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $job, + ) { } } diff --git a/src/Illuminate/Queue/Events/JobRetryRequested.php b/src/Illuminate/Queue/Events/JobRetryRequested.php index 9b9809f63950..99bd8d40c38f 100644 --- a/src/Illuminate/Queue/Events/JobRetryRequested.php +++ b/src/Illuminate/Queue/Events/JobRetryRequested.php @@ -4,13 +4,6 @@ class JobRetryRequested { - /** - * The job instance. - * - * @var \stdClass - */ - public $job; - /** * The decoded job payload. * @@ -21,12 +14,12 @@ class JobRetryRequested /** * Create a new event instance. * - * @param \stdClass $job + * @param \stdClass $job The job instance. * @return void */ - public function __construct($job) - { - $this->job = $job; + public function __construct( + public $job, + ) { } /** diff --git a/src/Illuminate/Queue/Events/JobTimedOut.php b/src/Illuminate/Queue/Events/JobTimedOut.php index c36dea5352e3..2b5e43650df0 100644 --- a/src/Illuminate/Queue/Events/JobTimedOut.php +++ b/src/Illuminate/Queue/Events/JobTimedOut.php @@ -4,30 +4,16 @@ class JobTimedOut { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The job instance. - * - * @var \Illuminate\Contracts\Queue\Job - */ - public $job; - /** * Create a new event instance. * - * @param string $connectionName - * @param \Illuminate\Contracts\Queue\Job $job + * @param string $connectionName The connection name. + * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @return void */ - public function __construct($connectionName, $job) - { - $this->job = $job; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $job, + ) { } } diff --git a/src/Illuminate/Queue/Events/Looping.php b/src/Illuminate/Queue/Events/Looping.php index f9538e4c504f..f8056e453afa 100644 --- a/src/Illuminate/Queue/Events/Looping.php +++ b/src/Illuminate/Queue/Events/Looping.php @@ -4,30 +4,16 @@ class Looping { - /** - * The connection name. - * - * @var string - */ - public $connectionName; - - /** - * The queue name. - * - * @var string - */ - public $queue; - /** * Create a new event instance. * - * @param string $connectionName - * @param string $queue + * @param string $connectionName The connection name. + * @param string $queue The queue name. * @return void */ - public function __construct($connectionName, $queue) - { - $this->queue = $queue; - $this->connectionName = $connectionName; + public function __construct( + public $connectionName, + public $queue, + ) { } } diff --git a/src/Illuminate/Queue/Events/QueueBusy.php b/src/Illuminate/Queue/Events/QueueBusy.php index 684dec4ea08a..a563ec0545fc 100644 --- a/src/Illuminate/Queue/Events/QueueBusy.php +++ b/src/Illuminate/Queue/Events/QueueBusy.php @@ -4,39 +4,18 @@ class QueueBusy { - /** - * The connection name. - * - * @var string - */ - public $connection; - - /** - * The queue name. - * - * @var string - */ - public $queue; - - /** - * The size of the queue. - * - * @var int - */ - public $size; - /** * Create a new event instance. * - * @param string $connection - * @param string $queue - * @param int $size + * @param string $connection The connection name. + * @param string $queue The queue name. + * @param int $size The size of the queue. * @return void */ - public function __construct($connection, $queue, $size) - { - $this->connection = $connection; - $this->queue = $queue; - $this->size = $size; + public function __construct( + public $connection, + public $queue, + public $size, + ) { } } diff --git a/src/Illuminate/Queue/Events/WorkerStopping.php b/src/Illuminate/Queue/Events/WorkerStopping.php index ccebb3cbb01a..6d862bac3c25 100644 --- a/src/Illuminate/Queue/Events/WorkerStopping.php +++ b/src/Illuminate/Queue/Events/WorkerStopping.php @@ -4,30 +4,16 @@ class WorkerStopping { - /** - * The worker exit status. - * - * @var int - */ - public $status; - - /** - * The worker options. - * - * @var \Illuminate\Queue\WorkerOptions|null - */ - public $workerOptions; - /** * Create a new event instance. * - * @param int $status - * @param \Illuminate\Queue\WorkerOptions|null $workerOptions + * @param int $status The worker exit status. + * @param \Illuminate\Queue\WorkerOptions|null $workerOptions The worker options. * @return void */ - public function __construct($status = 0, $workerOptions = null) - { - $this->status = $status; - $this->workerOptions = $workerOptions; + public function __construct( + public $status = 0, + public $workerOptions = null + ) { } } From 98987e05efb247c77f14820dec6ce32962015ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= <11225821+shaedrich@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:30:36 +0100 Subject: [PATCH 046/455] [12.x] Restore database token repository property documentation (#53908) * Restore DatabaseTokenRepository property documentation * Add data types * Fix StyleCI * Fix overfixing * Fix spacing * Update DatabaseTokenRepository.php * Update DatabaseTokenRepository.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php b/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php index ba0b81a62fae..935b93c2f8b6 100755 --- a/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php +++ b/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php @@ -12,6 +12,9 @@ class DatabaseTokenRepository implements TokenRepositoryInterface { /** * Create a new token repository instance. + * + * @param int $expires The number of seconds a token should remain valid. + * @param int $throttle Minimum number of seconds before the user can generate new password reset tokens. */ public function __construct( protected ConnectionInterface $connection, From 8660d95f77aa8a2776d5e7282cfe77ac8e55e541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= <11225821+shaedrich@users.noreply.github.com> Date: Mon, 16 Dec 2024 18:14:29 +0100 Subject: [PATCH 047/455] Use reject() instead of a negated filter() (#53925) --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/Traits/EnumeratesValues.php | 4 ++-- src/Illuminate/Database/Eloquent/Collection.php | 2 +- src/Illuminate/Foundation/Testing/DatabaseTruncation.php | 2 +- .../resources/exceptions/renderer/components/trace.blade.php | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 7d2bcdadc180..150ccbe8b749 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -86,7 +86,7 @@ public function lazy() public function median($key = null) { $values = (isset($key) ? $this->pluck($key) : $this) - ->filter(fn ($item) => ! is_null($item)) + ->reject(fn ($item) => is_null($item)) ->sort()->values(); $count = $values->count(); diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 010924f67633..10a55498edf2 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -457,7 +457,7 @@ public function min($callback = null) $callback = $this->valueRetriever($callback); return $this->map(fn ($value) => $callback($value)) - ->filter(fn ($value) => ! is_null($value)) + ->reject(fn ($value) => is_null($value)) ->reduce(fn ($result, $value) => is_null($result) || $value < $result ? $value : $result); } @@ -471,7 +471,7 @@ public function max($callback = null) { $callback = $this->valueRetriever($callback); - return $this->filter(fn ($value) => ! is_null($value))->reduce(function ($result, $item) use ($callback) { + return $this->reject(fn ($value) => is_null($value))->reduce(function ($result, $item) use ($callback) { $value = $callback($item); return is_null($result) || $value > $result ? $value : $result; diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 1ae950cb9e73..e4a151275a5f 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -824,7 +824,7 @@ public function toQuery() $class = get_class($model); - if ($this->filter(fn ($model) => ! $model instanceof $class)->isNotEmpty()) { + if ($this->reject(fn ($model) => $model instanceof $class)->isNotEmpty()) { throw new LogicException('Unable to create query for collection with mixed types.'); } diff --git a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php index 3f2c95cd637e..8e31985e21fb 100644 --- a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php +++ b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php @@ -95,7 +95,7 @@ function (Collection $tables, array $tablesToTruncate) { function (Collection $tables) use ($connection, $name) { $exceptTables = $this->exceptTables($connection, $name); - return $tables->filter(fn (array $table) => ! $this->tableExistsIn($table, $exceptTables)); + return $tables->reject(fn (array $table) => $this->tableExistsIn($table, $exceptTables)); } ) ->each(function (array $table) use ($connection) { diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/components/trace.blade.php b/src/Illuminate/Foundation/resources/exceptions/renderer/components/trace.blade.php index 1930737be2db..3c0b2ddb6760 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/components/trace.blade.php +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/components/trace.blade.php @@ -69,7 +69,7 @@ class="w-full text-left dark:border-gray-900" - @if (! $frame->isFromVendor() && $exception->frames()->slice($loop->index + 1)->filter(fn ($frame) => ! $frame->isFromVendor())->isEmpty()) + @if (! $frame->isFromVendor() && $exception->frames()->slice($loop->index + 1)->reject(fn ($frame) => $frame->isFromVendor())->isEmpty()) @if ($exception->frames()->slice($loop->index + 1)->count())
From bacbc4b279fa56220d8e98fecb466bbdd72a8348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= <11225821+shaedrich@users.noreply.github.com> Date: Mon, 16 Dec 2024 18:15:01 +0100 Subject: [PATCH 048/455] [12.x] Use first-class callable syntax to improve static analysis (#53924) * Use first-class callable syntax to improve static analysis * Fix syntax error * Revert first-class callable syntax for possibly non-existing methods --- src/Illuminate/Cache/CacheManager.php | 2 +- src/Illuminate/Cache/TagSet.php | 6 +++--- src/Illuminate/Collections/Collection.php | 2 +- .../Collections/Traits/EnumeratesValues.php | 2 +- .../Console/Scheduling/ScheduleListCommand.php | 2 +- src/Illuminate/Database/Grammar.php | 6 +++--- src/Illuminate/Database/Query/Builder.php | 4 ++-- src/Illuminate/Database/Schema/Builder.php | 4 ++-- src/Illuminate/Foundation/AliasLoader.php | 2 +- .../Foundation/Console/RouteListCommand.php | 4 ++-- .../Foundation/Exceptions/Renderer/Listener.php | 2 +- src/Illuminate/Foundation/Http/FormRequest.php | 2 +- src/Illuminate/Http/Middleware/TrustProxies.php | 2 +- src/Illuminate/Mail/Mailable.php | 2 +- .../Notifications/Messages/SimpleMessage.php | 4 ++-- .../Redis/Connections/PacksPhpRedisValues.php | 2 +- .../Redis/Connectors/PhpRedisConnector.php | 2 +- src/Illuminate/Routing/Router.php | 2 +- src/Illuminate/Support/ConfigurationUrlParser.php | 4 ++-- src/Illuminate/Support/Str.php | 4 ++-- .../Support/Testing/Fakes/ExceptionHandlerFake.php | 4 ++-- src/Illuminate/Testing/TestComponent.php | 4 ++-- src/Illuminate/Testing/TestResponse.php | 12 ++++++------ src/Illuminate/Testing/TestView.php | 4 ++-- src/Illuminate/Validation/Rules/File.php | 2 +- src/Illuminate/Validation/ValidationRuleParser.php | 2 +- src/Illuminate/Validation/Validator.php | 4 ++-- .../View/Compilers/Concerns/CompilesComponents.php | 2 +- src/Illuminate/View/FileViewFinder.php | 2 +- 29 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index 5ae5b6a3358b..6f15b122b2a4 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -332,7 +332,7 @@ protected function setEventDispatcher(Repository $repository) */ public function refreshEventDispatcher() { - array_map([$this, 'setEventDispatcher'], $this->stores); + array_map($this->setEventDispatcher(...), $this->stores); } /** diff --git a/src/Illuminate/Cache/TagSet.php b/src/Illuminate/Cache/TagSet.php index 471dc679ce5f..8be559d849ae 100644 --- a/src/Illuminate/Cache/TagSet.php +++ b/src/Illuminate/Cache/TagSet.php @@ -40,7 +40,7 @@ public function __construct(Store $store, array $names = []) */ public function reset() { - array_walk($this->names, [$this, 'resetTag']); + array_walk($this->names, $this->resetTag(...)); } /** @@ -63,7 +63,7 @@ public function resetTag($name) */ public function flush() { - array_walk($this->names, [$this, 'flushTag']); + array_walk($this->names, $this->flushTag(...)); } /** @@ -93,7 +93,7 @@ public function getNamespace() */ protected function tagIds() { - return array_map([$this, 'tagId'], $this->names); + return array_map($this->tagId(...), $this->names); } /** diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 150ccbe8b749..4532891ec4c1 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -232,7 +232,7 @@ public function doesntContain($key, $operator = null, $value = null) public function crossJoin(...$lists) { return new static(Arr::crossJoin( - $this->items, ...array_map([$this, 'getArrayableItems'], $lists) + $this->items, ...array_map($this->getArrayableItems(...), $lists) )); } diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 10a55498edf2..d70529a08aa8 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -412,7 +412,7 @@ public function mapToGroups(callable $callback) { $groups = $this->mapToDictionary($callback); - return $groups->map([$this, 'make']); + return $groups->map($this->make(...)); } /** diff --git a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php index cf42dc795f00..68758440888b 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php @@ -86,7 +86,7 @@ public function handle(Schedule $schedule) */ private function getCronExpressionSpacing($events) { - $rows = $events->map(fn ($event) => array_map('mb_strlen', preg_split("/\s+/", $event->expression))); + $rows = $events->map(fn ($event) => array_map(mb_strlen(...), preg_split("/\s+/", $event->expression))); return (new Collection($rows[0] ?? []))->keys()->map(fn ($key) => $rows->max($key))->all(); } diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 8dd9bc353ef4..28c1a2f10f24 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -33,7 +33,7 @@ abstract class Grammar */ public function wrapArray(array $values) { - return array_map([$this, 'wrap'], $values); + return array_map($this->wrap(...), $values); } /** @@ -186,7 +186,7 @@ protected function isJsonSelector($value) */ public function columnize(array $columns) { - return implode(', ', array_map([$this, 'wrap'], $columns)); + return implode(', ', array_map($this->wrap(...), $columns)); } /** @@ -197,7 +197,7 @@ public function columnize(array $columns) */ public function parameterize(array $values) { - return implode(', ', array_map([$this, 'parameter'], $values)); + return implode(', ', array_map($this->parameter(...), $values)); } /** diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 7c1aee90b66f..95c12734391e 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -4220,7 +4220,7 @@ public function addBinding($value, $type = 'where') if (is_array($value)) { $this->bindings[$type] = array_values(array_map( - [$this, 'castBinding'], + $this->castBinding(...), array_merge($this->bindings[$type], $value), )); } else { @@ -4270,7 +4270,7 @@ public function cleanBindings(array $bindings) ->reject(function ($binding) { return $binding instanceof ExpressionContract; }) - ->map([$this, 'castBinding']) + ->map($this->castBinding(...)) ->values() ->all(); } diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 387eb618f23a..38cadfbd2794 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -239,7 +239,7 @@ public function getTypes() public function hasColumn($table, $column) { return in_array( - strtolower($column), array_map('strtolower', $this->getColumnListing($table)) + strtolower($column), array_map(strtolower(...), $this->getColumnListing($table)) ); } @@ -252,7 +252,7 @@ public function hasColumn($table, $column) */ public function hasColumns($table, array $columns) { - $tableColumns = array_map('strtolower', $this->getColumnListing($table)); + $tableColumns = array_map(strtolower(...), $this->getColumnListing($table)); foreach ($columns as $column) { if (! in_array(strtolower($column), $tableColumns)) { diff --git a/src/Illuminate/Foundation/AliasLoader.php b/src/Illuminate/Foundation/AliasLoader.php index 5146e443be97..d46748598d5a 100755 --- a/src/Illuminate/Foundation/AliasLoader.php +++ b/src/Illuminate/Foundation/AliasLoader.php @@ -164,7 +164,7 @@ public function register() */ protected function prependToLoaderStack() { - spl_autoload_register([$this, 'load'], true, true); + spl_autoload_register($this->load(...), true, true); } /** diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index d54aceb26456..929003613c52 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -299,7 +299,7 @@ protected function getHeaders() */ protected function getColumns() { - return array_map('strtolower', $this->headers); + return array_map(strtolower(...), $this->headers); } /** @@ -320,7 +320,7 @@ protected function parseColumns(array $columns) } } - return array_map('strtolower', $results); + return array_map(strtolower(...), $results); } /** diff --git a/src/Illuminate/Foundation/Exceptions/Renderer/Listener.php b/src/Illuminate/Foundation/Exceptions/Renderer/Listener.php index 325fad4c20ac..d5a71b7d9178 100644 --- a/src/Illuminate/Foundation/Exceptions/Renderer/Listener.php +++ b/src/Illuminate/Foundation/Exceptions/Renderer/Listener.php @@ -28,7 +28,7 @@ class Listener */ public function registerListeners(Dispatcher $events) { - $events->listen(QueryExecuted::class, [$this, 'onQueryExecuted']); + $events->listen(QueryExecuted::class, $this->onQueryExecuted(...)); $events->listen([JobProcessing::class, JobProcessed::class], function () { $this->queries = []; diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 87a1e2048555..7c746f24c2f2 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -86,7 +86,7 @@ protected function getValidatorInstance() $factory = $this->container->make(ValidationFactory::class); if (method_exists($this, 'validator')) { - $validator = $this->container->call([$this, 'validator'], compact('factory')); + $validator = $this->container->call($this->validator(...), compact('factory')); } else { $validator = $this->createDefaultValidator($factory); } diff --git a/src/Illuminate/Http/Middleware/TrustProxies.php b/src/Illuminate/Http/Middleware/TrustProxies.php index 0a13ff79a361..6b1b6765dc43 100644 --- a/src/Illuminate/Http/Middleware/TrustProxies.php +++ b/src/Illuminate/Http/Middleware/TrustProxies.php @@ -77,7 +77,7 @@ protected function setTrustedProxyIpAddresses(Request $request) } $trustedIps = is_string($trustedIps) - ? array_map('trim', explode(',', $trustedIps)) + ? array_map(trim(...), explode(',', $trustedIps)) : $trustedIps; if (is_array($trustedIps)) { diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 70ccb3477d00..287118726b94 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -1415,7 +1415,7 @@ public function assertDontSeeInHtml($string, $escape = true) */ public function assertSeeInOrderInHtml($strings, $escape = true) { - $strings = $escape ? array_map('e', $strings) : $strings; + $strings = $escape ? array_map(e(...), $strings) : $strings; [$html, $text] = $this->renderForAssertions(); diff --git a/src/Illuminate/Notifications/Messages/SimpleMessage.php b/src/Illuminate/Notifications/Messages/SimpleMessage.php index 254fd78ee137..82985aab0ecb 100644 --- a/src/Illuminate/Notifications/Messages/SimpleMessage.php +++ b/src/Illuminate/Notifications/Messages/SimpleMessage.php @@ -236,10 +236,10 @@ protected function formatLine($line) } if (is_array($line)) { - return implode(' ', array_map('trim', $line)); + return implode(' ', array_map(trim(...), $line)); } - return trim(implode(' ', array_map('trim', preg_split('/\\r\\n|\\r|\\n/', $line ?? '')))); + return trim(implode(' ', array_map(trim(...), preg_split('/\\r\\n|\\r|\\n/', $line ?? '')))); } /** diff --git a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php index 4d27ff59aebd..6e337f4fe926 100644 --- a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php +++ b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php @@ -42,7 +42,7 @@ public function pack(array $values): array } if ($this->supportsPacking()) { - return array_map([$this->client, '_pack'], $values); + return array_map($this->client->_pack(...), $values); } if ($this->compressed()) { diff --git a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php index 06618a2ff118..2103155af9e9 100644 --- a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php +++ b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php @@ -51,7 +51,7 @@ public function connectToCluster(array $config, array $clusterOptions, array $op $options = array_merge($options, $clusterOptions, Arr::pull($config, 'options', [])); return new PhpRedisClusterConnection($this->createRedisClusterInstance( - array_map([$this, 'buildClusterConnectionString'], $config), $options + array_map($this->buildClusterConnectionString(...), $config), $options )); } diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 3665d910aa34..d10c0dff463f 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -306,7 +306,7 @@ public function view($uri, $view, $data = [], $status = 200, array $headers = [] */ public function match($methods, $uri, $action = null) { - return $this->addRoute(array_map('strtoupper', (array) $methods), $uri, $action); + return $this->addRoute(array_map(strtoupper(...), (array) $methods), $uri, $action); } /** diff --git a/src/Illuminate/Support/ConfigurationUrlParser.php b/src/Illuminate/Support/ConfigurationUrlParser.php index a1b933709236..b841b65e41c6 100644 --- a/src/Illuminate/Support/ConfigurationUrlParser.php +++ b/src/Illuminate/Support/ConfigurationUrlParser.php @@ -42,7 +42,7 @@ public function parseConfiguration($config) $rawComponents = $this->parseUrl($url); $decodedComponents = $this->parseStringsToNativeTypes( - array_map('rawurldecode', $rawComponents) + array_map(rawurldecode(...), $rawComponents) ); return array_merge( @@ -151,7 +151,7 @@ protected function parseUrl($url) protected function parseStringsToNativeTypes($value) { if (is_array($value)) { - return array_map([$this, 'parseStringsToNativeTypes'], $value); + return array_map($this->parseStringsToNativeTypes(...), $value); } if (! is_string($value)) { diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 0d6e784f47e1..a217f9cf003d 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -1406,8 +1406,8 @@ public static function headline($value) $parts = explode(' ', $value); $parts = count($parts) > 1 - ? array_map([static::class, 'title'], $parts) - : array_map([static::class, 'title'], static::ucsplit(implode('_', $parts))); + ? array_map(static::title(...), $parts) + : array_map(static::title(...), static::ucsplit(implode('_', $parts))); $collapsed = static::replace(['-', '_', ' '], '_', implode('_', $parts)); diff --git a/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php b/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php index f359d6c185bc..67b0a65e8214 100644 --- a/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php +++ b/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php @@ -73,7 +73,7 @@ public function assertReported(Closure|string $exception) if (is_string($exception)) { Assert::assertTrue( - in_array($exception, array_map('get_class', $this->reported), true), + in_array($exception, array_map(get_class(...), $this->reported), true), $message, ); @@ -135,7 +135,7 @@ public function assertNothingReported() $this->reported, sprintf( 'The following exceptions were reported: %s.', - implode(', ', array_map('get_class', $this->reported)), + implode(', ', array_map(get_class(...), $this->reported)), ), ); } diff --git a/src/Illuminate/Testing/TestComponent.php b/src/Illuminate/Testing/TestComponent.php index 0965789b3854..62874d50ee21 100644 --- a/src/Illuminate/Testing/TestComponent.php +++ b/src/Illuminate/Testing/TestComponent.php @@ -61,7 +61,7 @@ public function assertSee($value, $escape = true) */ public function assertSeeInOrder(array $values, $escape = true) { - $values = $escape ? array_map('e', $values) : $values; + $values = $escape ? array_map(e(...), $values) : $values; PHPUnit::assertThat($values, new SeeInOrder($this->rendered)); @@ -93,7 +93,7 @@ public function assertSeeText($value, $escape = true) */ public function assertSeeTextInOrder(array $values, $escape = true) { - $values = $escape ? array_map('e', $values) : $values; + $values = $escape ? array_map(e(...), $values) : $values; PHPUnit::assertThat($values, new SeeInOrder(strip_tags($this->rendered))); diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 87c50d0ad44c..268dd2bbbe4b 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -567,7 +567,7 @@ public function assertSee($value, $escape = true) { $value = Arr::wrap($value); - $values = $escape ? array_map('e', $value) : $value; + $values = $escape ? array_map(e(...), $value) : $value; foreach ($values as $value) { PHPUnit::withResponse($this)->assertStringContainsString((string) $value, $this->getContent()); @@ -596,7 +596,7 @@ public function assertSeeHtml($value) */ public function assertSeeInOrder(array $values, $escape = true) { - $values = $escape ? array_map('e', $values) : $values; + $values = $escape ? array_map(e(...), $values) : $values; PHPUnit::withResponse($this)->assertThat($values, new SeeInOrder($this->getContent())); @@ -625,7 +625,7 @@ public function assertSeeText($value, $escape = true) { $value = Arr::wrap($value); - $values = $escape ? array_map('e', $value) : $value; + $values = $escape ? array_map(e(...), $value) : $value; $content = strip_tags($this->getContent()); @@ -645,7 +645,7 @@ public function assertSeeText($value, $escape = true) */ public function assertSeeTextInOrder(array $values, $escape = true) { - $values = $escape ? array_map('e', $values) : $values; + $values = $escape ? array_map(e(...), $values) : $values; PHPUnit::withResponse($this)->assertThat($values, new SeeInOrder(strip_tags($this->getContent()))); @@ -663,7 +663,7 @@ public function assertDontSee($value, $escape = true) { $value = Arr::wrap($value); - $values = $escape ? array_map('e', $value) : $value; + $values = $escape ? array_map(e(...), $value) : $value; foreach ($values as $value) { PHPUnit::withResponse($this)->assertStringNotContainsString((string) $value, $this->getContent()); @@ -694,7 +694,7 @@ public function assertDontSeeText($value, $escape = true) { $value = Arr::wrap($value); - $values = $escape ? array_map('e', $value) : $value; + $values = $escape ? array_map(e(...), $value) : $value; $content = strip_tags($this->getContent()); diff --git a/src/Illuminate/Testing/TestView.php b/src/Illuminate/Testing/TestView.php index a31a814ab402..acbb7435efa2 100644 --- a/src/Illuminate/Testing/TestView.php +++ b/src/Illuminate/Testing/TestView.php @@ -144,7 +144,7 @@ public function assertSee($value, $escape = true) */ public function assertSeeInOrder(array $values, $escape = true) { - $values = $escape ? array_map('e', $values) : $values; + $values = $escape ? array_map(e(...), $values) : $values; PHPUnit::assertThat($values, new SeeInOrder($this->rendered)); @@ -176,7 +176,7 @@ public function assertSeeText($value, $escape = true) */ public function assertSeeTextInOrder(array $values, $escape = true) { - $values = $escape ? array_map('e', $values) : $values; + $values = $escape ? array_map(e(...), $values) : $values; PHPUnit::assertThat($values, new SeeInOrder(strip_tags($this->rendered))); diff --git a/src/Illuminate/Validation/Rules/File.php b/src/Illuminate/Validation/Rules/File.php index 63928e33c48e..00cbc6a39465 100644 --- a/src/Illuminate/Validation/Rules/File.php +++ b/src/Illuminate/Validation/Rules/File.php @@ -277,7 +277,7 @@ protected function buildValidationRules() $rules = array_merge($rules, $this->buildMimetypes()); if (! empty($this->allowedExtensions)) { - $rules[] = 'extensions:'.implode(',', array_map('strtolower', $this->allowedExtensions)); + $rules[] = 'extensions:'.implode(',', array_map(strtolower(...), $this->allowedExtensions)); } $rules[] = match (true) { diff --git a/src/Illuminate/Validation/ValidationRuleParser.php b/src/Illuminate/Validation/ValidationRuleParser.php index 0119b6d3a803..7001b17cc7e3 100644 --- a/src/Illuminate/Validation/ValidationRuleParser.php +++ b/src/Illuminate/Validation/ValidationRuleParser.php @@ -96,7 +96,7 @@ protected function explodeExplicitRule($rule, $attribute) } return array_map( - [$this, 'prepareRule'], + $this->prepareRule(...), $rule, array_fill((int) array_key_first($rule), count($rule), $attribute) ); diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 66708190202c..900bdb3698a0 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -1304,7 +1304,7 @@ public function stopOnFirstFailure($stopOnFirstFailure = true) public function addExtensions(array $extensions) { if ($extensions) { - $keys = array_map([Str::class, 'snake'], array_keys($extensions)); + $keys = array_map(Str::snake(...), array_keys($extensions)); $extensions = array_combine($keys, array_values($extensions)); } @@ -1391,7 +1391,7 @@ public function addDependentExtension($rule, $extension) public function addReplacers(array $replacers) { if ($replacers) { - $keys = array_map([Str::class, 'snake'], array_keys($replacers)); + $keys = array_map(Str::snake(...), array_keys($replacers)); $replacers = array_combine($keys, array_values($replacers)); } diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php index 56d1399e85dc..22076c87bfc4 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php @@ -25,7 +25,7 @@ trait CompilesComponents protected function compileComponent($expression) { [$component, $alias, $data] = str_contains($expression, ',') - ? array_map('trim', explode(',', trim($expression, '()'), 3)) + ['', '', ''] + ? array_map(trim(...), explode(',', trim($expression, '()'), 3)) + ['', '', ''] : [trim($expression, '()'), '', '']; $component = trim($component, '\'"'); diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index c2f49bd68bde..917661d96bf2 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -53,7 +53,7 @@ class FileViewFinder implements ViewFinderInterface public function __construct(Filesystem $files, array $paths, ?array $extensions = null) { $this->files = $files; - $this->paths = array_map([$this, 'resolvePath'], $paths); + $this->paths = array_map($this->resolvePath(...), $paths); if (isset($extensions)) { $this->extensions = $extensions; From 8383bea1bbd87c54bf08d928934a78a03fb3c08e Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 18 Dec 2024 13:22:53 -0600 Subject: [PATCH 049/455] [12.x] add type declarations for Console Events (#53947) * add type declarations for Console Events the added types match the existing constructor docblocks * minor styling * handle nullable `getCommand()` and `getName()` both the `CommandStarting` and `CommandFinished` require a string to be passed as the first argument, so we need to account for nullable scenarios. --- src/Illuminate/Console/Events/ArtisanStarting.php | 4 +++- src/Illuminate/Console/Events/CommandFinished.php | 4 ++-- src/Illuminate/Console/Events/CommandStarting.php | 2 +- src/Illuminate/Console/Events/ScheduledTaskFinished.php | 2 +- src/Illuminate/Foundation/Console/Kernel.php | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Console/Events/ArtisanStarting.php b/src/Illuminate/Console/Events/ArtisanStarting.php index 9a6e4b0b9d65..15f044979de7 100644 --- a/src/Illuminate/Console/Events/ArtisanStarting.php +++ b/src/Illuminate/Console/Events/ArtisanStarting.php @@ -2,6 +2,8 @@ namespace Illuminate\Console\Events; +use Illuminate\Console\Application; + class ArtisanStarting { /** @@ -11,7 +13,7 @@ class ArtisanStarting * @return void */ public function __construct( - public $artisan, + public Application $artisan, ) { } } diff --git a/src/Illuminate/Console/Events/CommandFinished.php b/src/Illuminate/Console/Events/CommandFinished.php index 56438782121a..d2f229224c0f 100644 --- a/src/Illuminate/Console/Events/CommandFinished.php +++ b/src/Illuminate/Console/Events/CommandFinished.php @@ -17,10 +17,10 @@ class CommandFinished * @return void */ public function __construct( - public $command, + public string $command, public InputInterface $input, public OutputInterface $output, - public $exitCode, + public int $exitCode, ) { } } diff --git a/src/Illuminate/Console/Events/CommandStarting.php b/src/Illuminate/Console/Events/CommandStarting.php index e43ac6700629..f8d56bcc8a35 100644 --- a/src/Illuminate/Console/Events/CommandStarting.php +++ b/src/Illuminate/Console/Events/CommandStarting.php @@ -16,7 +16,7 @@ class CommandStarting * @return void */ public function __construct( - public $command, + public string $command, public InputInterface $input, public OutputInterface $output, ) { diff --git a/src/Illuminate/Console/Events/ScheduledTaskFinished.php b/src/Illuminate/Console/Events/ScheduledTaskFinished.php index f41896b715f2..1b73e6424680 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskFinished.php +++ b/src/Illuminate/Console/Events/ScheduledTaskFinished.php @@ -15,7 +15,7 @@ class ScheduledTaskFinished */ public function __construct( public Event $task, - public $runtime, + public float $runtime, ) { } } diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index 165855b80132..7a119cf85bab 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -163,13 +163,13 @@ public function rerouteSymfonyCommandEvents() $this->symfonyDispatcher->addListener(ConsoleEvents::COMMAND, function (ConsoleCommandEvent $event) { $this->events->dispatch( - new CommandStarting($event->getCommand()->getName(), $event->getInput(), $event->getOutput()) + new CommandStarting($event->getCommand()?->getName() ?? '', $event->getInput(), $event->getOutput()) ); }); $this->symfonyDispatcher->addListener(ConsoleEvents::TERMINATE, function (ConsoleTerminateEvent $event) { $this->events->dispatch( - new CommandFinished($event->getCommand()->getName(), $event->getInput(), $event->getOutput(), $event->getExitCode()) + new CommandFinished($event->getCommand()?->getName() ?? '', $event->getInput(), $event->getOutput(), $event->getExitCode()) ); }); } From bf16f38a3767819343b4ddacf6b61ebbf55c9d23 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 18 Dec 2024 15:34:35 -0600 Subject: [PATCH 050/455] [12.x] use type declaration on property (#53970) * use type declaration on property also use promoted property * restore comment --- src/Illuminate/Bus/Events/BatchDispatched.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Bus/Events/BatchDispatched.php b/src/Illuminate/Bus/Events/BatchDispatched.php index b9a161adb48c..2f654ad365b5 100644 --- a/src/Illuminate/Bus/Events/BatchDispatched.php +++ b/src/Illuminate/Bus/Events/BatchDispatched.php @@ -6,21 +6,14 @@ class BatchDispatched { - /** - * The batch instance. - * - * @var \Illuminate\Bus\Batch - */ - public $batch; - /** * Create a new event instance. * - * @param \Illuminate\Bus\Batch $batch + * @param \Illuminate\Bus\Batch $batch The batch instance. * @return void */ - public function __construct(Batch $batch) - { - $this->batch = $batch; + public function __construct( + public Batch $batch, + ) { } } From 91c72ac412dc7bc2b7c587c90fcac274185afb33 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 27 Dec 2024 05:38:33 +0800 Subject: [PATCH 051/455] [12.x] Update Symfony and PHPUnit dependencies (#54019) * Uses Symfony 7.2 Signed-off-by: Mior Muhammad Zaki * Remove support for PHPUnit 10 Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- .github/workflows/tests.yml | 4 +- composer.json | 43 +++++++++---------- 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 | 2 +- src/Illuminate/Filesystem/composer.json | 8 ++-- src/Illuminate/Http/composer.json | 6 +-- src/Illuminate/Mail/composer.json | 8 ++-- src/Illuminate/Process/composer.json | 2 +- src/Illuminate/Queue/composer.json | 2 +- src/Illuminate/Routing/composer.json | 8 ++-- src/Illuminate/Session/composer.json | 4 +- .../Support/Process/PhpExecutableFinder.php | 22 ---------- src/Illuminate/Support/composer.json | 6 +-- src/Illuminate/Support/functions.php | 2 +- src/Illuminate/Validation/composer.json | 4 +- tests/Mail/MailManagerTest.php | 22 ++-------- 19 files changed, 59 insertions(+), 96 deletions(-) delete mode 100644 src/Illuminate/Support/Process/PhpExecutableFinder.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ca71849701fb..33f7860f4cd6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,7 +40,7 @@ jobs: fail-fast: true matrix: php: [8.2, 8.3, 8.4] - phpunit: ['10.5.12', '11.3.2'] + phpunit: ['11.3.6'] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - PHPUnit ${{ matrix.phpunit }} - ${{ matrix.stability }} @@ -103,7 +103,7 @@ jobs: fail-fast: true matrix: php: [8.2, 8.3, 8.4] - phpunit: ['10.5', '11.0.1'] + phpunit: ['11.3.6'] stability: [prefer-lowest, prefer-stable] exclude: - php: 8.4 diff --git a/composer.json b/composer.json index 5c02f0e2aafd..7faba7bedc01 100644 --- a/composer.json +++ b/composer.json @@ -44,18 +44,18 @@ "psr/log": "^1.0|^2.0|^3.0", "psr/simple-cache": "^1.0|^2.0|^3.0", "ramsey/uuid": "^4.7", - "symfony/console": "^7.0.3", - "symfony/error-handler": "^7.0.3", - "symfony/finder": "^7.0.3", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", "symfony/http-foundation": "^7.2.0", - "symfony/http-kernel": "^7.0.3", - "symfony/mailer": "^7.0.3", - "symfony/mime": "^7.0.3", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", "symfony/polyfill-php83": "^1.31", - "symfony/process": "^7.0.3", - "symfony/routing": "^7.0.3", - "symfony/uid": "^7.0.3", - "symfony/var-dumper": "^7.0.3", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", "tijsverkoyen/css-to-inline-styles": "^2.2.5", "vlucas/phpdotenv": "^5.6.1", "voku/portable-ascii": "^2.0.2" @@ -114,16 +114,15 @@ "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^1.11.5", - "phpunit/phpunit": "^10.5.35|^11.3.6", + "phpunit/phpunit": "^11.3.6", "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", - "symfony/cache": "^7.0.3", - "symfony/http-client": "^7.0.3", - "symfony/psr-http-message-bridge": "^7.0.3", - "symfony/translation": "^7.0.3" + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" }, "conflict": { - "mockery/mockery": "1.6.8", "tightenco/collect": "<5.5.33" }, "provide": { @@ -193,12 +192,12 @@ "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 (^6.0|^7.0).", "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^7.0).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^7.0).", - "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.0).", - "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.0).", - "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.0).", - "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.0)." + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." }, "config": { "sort-packages": true, diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index e49aea9fb3bd..b1a44ef6d451 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -40,7 +40,7 @@ "illuminate/database": "Required to use the database cache driver (^12.0).", "illuminate/filesystem": "Required to use the file cache driver (^12.0).", "illuminate/redis": "Required to use the redis cache driver (^12.0).", - "symfony/cache": "Required to use PSR-6 cache bridge (^7.0)." + "symfony/cache": "Required to use PSR-6 cache bridge (^7.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index b1e2c2a0c0ad..ab98b8ee456a 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -34,7 +34,7 @@ } }, "suggest": { - "symfony/var-dumper": "Required to use the dump method (^7.0)." + "symfony/var-dumper": "Required to use the dump method (^7.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index e81f50dcc98a..82fe11336e8a 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -23,9 +23,9 @@ "illuminate/view": "^12.0", "laravel/prompts": "^0.3.0", "nunomaduro/termwind": "^2.0", - "symfony/console": "^7.0.3", + "symfony/console": "^7.2.0", "symfony/polyfill-php83": "^1.31", - "symfony/process": "^7.0.3" + "symfony/process": "^7.2.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 52a214d54fc7..7184c3d2e351 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -20,8 +20,8 @@ "illuminate/contracts": "^12.0", "illuminate/macroable": "^12.0", "illuminate/support": "^12.0", - "symfony/http-foundation": "^7.0.3", - "symfony/http-kernel": "^7.0.3" + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index b85d6cfb26ad..65829cdf56f3 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -42,7 +42,7 @@ "illuminate/events": "Required to use the observers with Eloquent (^12.0).", "illuminate/filesystem": "Required to use the migrations (^12.0).", "illuminate/pagination": "Required to paginate the result set (^12.0).", - "symfony/finder": "Required to use Eloquent model factories (^7.0)." + "symfony/finder": "Required to use Eloquent model factories (^7.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 47f55ba50b77..8e4352665cb4 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -19,7 +19,7 @@ "illuminate/contracts": "^12.0", "illuminate/macroable": "^12.0", "illuminate/support": "^12.0", - "symfony/finder": "^7.0.3" + "symfony/finder": "^7.2.0" }, "autoload": { "psr-4": { @@ -38,14 +38,14 @@ "ext-fileinfo": "Required to use the Filesystem class.", "ext-ftp": "Required to use the Flysystem FTP driver.", "ext-hash": "Required to use the Filesystem class.", - "illuminate/http": "Required for handling uploaded files (^7.0).", + "illuminate/http": "Required for handling uploaded files (^7.2).", "league/flysystem": "Required to use the Flysystem local driver (^3.25.1).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^7.0).", - "symfony/mime": "Required to enable support for guessing extensions (^7.0)." + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/mime": "Required to enable support for guessing extensions (^7.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 6b29fa16f303..0ab2371d7c50 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -23,10 +23,10 @@ "illuminate/macroable": "^12.0", "illuminate/session": "^12.0", "illuminate/support": "^12.0", - "symfony/http-foundation": "^7.0.3", - "symfony/http-kernel": "^7.0.3", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", "symfony/polyfill-php83": "^1.31", - "symfony/mime": "^7.0.3" + "symfony/mime": "^7.2.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 45c26cfc862c..cf28958fdcad 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -22,7 +22,7 @@ "illuminate/support": "^12.0", "league/commonmark": "^2.6", "psr/log": "^1.0|^2.0|^3.0", - "symfony/mailer": "^7.0.3", + "symfony/mailer": "^7.2.0", "tijsverkoyen/css-to-inline-styles": "^2.2.5" }, "autoload": { @@ -38,9 +38,9 @@ "suggest": { "aws/aws-sdk-php": "Required to use the SES mail driver (^3.322.9).", "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", - "symfony/http-client": "Required to use the Symfony API mail transports (^7.0).", - "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.0).", - "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.0)." + "symfony/http-client": "Required to use the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Process/composer.json b/src/Illuminate/Process/composer.json index fb7ed5f9bb65..0f2a57773644 100644 --- a/src/Illuminate/Process/composer.json +++ b/src/Illuminate/Process/composer.json @@ -19,7 +19,7 @@ "illuminate/contracts": "^11.0", "illuminate/macroable": "^11.0", "illuminate/support": "^11.0", - "symfony/process": "^7.0.3" + "symfony/process": "^7.2.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 60776ba5d58b..ee32be673acb 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -25,7 +25,7 @@ "illuminate/support": "^12.0", "laravel/serializable-closure": "^1.3|^2.0", "ramsey/uuid": "^4.7", - "symfony/process": "^7.0.3" + "symfony/process": "^7.2.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 95f0f3bae206..1f7e2281463f 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -25,9 +25,9 @@ "illuminate/pipeline": "^12.0", "illuminate/session": "^12.0", "illuminate/support": "^12.0", - "symfony/http-foundation": "^7.0.3", - "symfony/http-kernel": "^7.0.3", - "symfony/routing": "^7.0.3" + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/routing": "^7.2.0" }, "autoload": { "psr-4": { @@ -42,7 +42,7 @@ "suggest": { "illuminate/console": "Required to use the make commands (^12.0).", "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", - "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.0)." + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." }, "config": { "sort-packages": true, diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 5fcc10efc4d0..c19e6cbe5081 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -21,8 +21,8 @@ "illuminate/contracts": "^12.0", "illuminate/filesystem": "^12.0", "illuminate/support": "^12.0", - "symfony/finder": "^7.0.3", - "symfony/http-foundation": "^7.0.3" + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Support/Process/PhpExecutableFinder.php b/src/Illuminate/Support/Process/PhpExecutableFinder.php deleted file mode 100644 index e1b4cff04697..000000000000 --- a/src/Illuminate/Support/Process/PhpExecutableFinder.php +++ /dev/null @@ -1,22 +0,0 @@ -find('php', false, [implode(DIRECTORY_SEPARATOR, [$herdPath, 'bin'])]); - } - - return parent::find($includeArgs); - } -} diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index be6b7606158f..553714a15594 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -52,9 +52,9 @@ "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.6).", "league/uri": "Required to use the Uri class (^7.5.1).", "ramsey/uuid": "Required to use Str::uuid() (^4.7).", - "symfony/process": "Required to use the Composer class (^7.0).", - "symfony/uid": "Required to use Str::ulid() (^7.0).", - "symfony/var-dumper": "Required to use the dd function (^7.0).", + "symfony/process": "Required to use the Composer class (^7.2).", + "symfony/uid": "Required to use Str::ulid() (^7.2).", + "symfony/var-dumper": "Required to use the dd function (^7.2).", "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.6.1)." }, "config": { diff --git a/src/Illuminate/Support/functions.php b/src/Illuminate/Support/functions.php index 3fc76f87151e..133ca6ac5e6a 100644 --- a/src/Illuminate/Support/functions.php +++ b/src/Illuminate/Support/functions.php @@ -4,7 +4,7 @@ use Illuminate\Support\Defer\DeferredCallback; use Illuminate\Support\Defer\DeferredCallbackCollection; -use Illuminate\Support\Process\PhpExecutableFinder; +use Symfony\Component\Process\PhpExecutableFinder; if (! function_exists('Illuminate\Support\defer')) { /** diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 0aae94ee07fb..93a4c2e071dc 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -25,8 +25,8 @@ "illuminate/macroable": "^12.0", "illuminate/support": "^12.0", "illuminate/translation": "^12.0", - "symfony/http-foundation": "^7.0", - "symfony/mime": "^7.0" + "symfony/http-foundation": "^7.2", + "symfony/mime": "^7.2" }, "autoload": { "psr-4": { diff --git a/tests/Mail/MailManagerTest.php b/tests/Mail/MailManagerTest.php index 43d974a2e254..0a77128c650c 100644 --- a/tests/Mail/MailManagerTest.php +++ b/tests/Mail/MailManagerTest.php @@ -50,11 +50,7 @@ public function testMailUrlConfig($scheme, $port) $this->assertSame('127.0.0.2', $transport->getStream()->getHost()); $this->assertSame($port, $transport->getStream()->getPort()); $this->assertSame($port === 465, $transport->getStream()->isTLS()); - - if (method_exists($transport, 'isAutoTls')) { - // Only available from Symfony Mailer 7.1 - $this->assertTrue($transport->isAutoTls()); - } + $this->assertTrue($transport->isAutoTls()); } #[TestWith([null, 5876])] @@ -79,11 +75,7 @@ public function testMailUrlConfigWithAutoTls($scheme, $port) $this->assertSame('127.0.0.2', $transport->getStream()->getHost()); $this->assertSame($port, $transport->getStream()->getPort()); $this->assertSame($port === 465, $transport->getStream()->isTLS()); - - if (method_exists($transport, 'isAutoTls')) { - // Only available from Symfony Mailer 7.1 - $this->assertTrue($transport->isAutoTls()); - } + $this->assertTrue($transport->isAutoTls()); } #[TestWith([null, 5876])] @@ -107,14 +99,8 @@ public function testMailUrlConfigWithAutoTlsDisabled($scheme, $port) $this->assertSame('pwd', $transport->getPassword()); $this->assertSame('127.0.0.2', $transport->getStream()->getHost()); $this->assertSame($port, $transport->getStream()->getPort()); - - if (method_exists($transport, 'isAutoTls')) { - // Only available from Symfony Mailer 7.1 - $this->assertFalse($transport->isAutoTls()); - $this->assertSame($port === 465 && $scheme !== 'smtp', $transport->getStream()->isTLS()); - } else { - $this->assertSame($port === 465, $transport->getStream()->isTLS()); - } + $this->assertFalse($transport->isAutoTls()); + $this->assertSame($port === 465 && $scheme !== 'smtp', $transport->getStream()->isTLS()); } public function testBuild() From f0bf46db8617016793aa5d47c37205bfd4ff155f Mon Sep 17 00:00:00 2001 From: Jamie York Date: Fri, 27 Dec 2024 20:58:00 +0000 Subject: [PATCH 052/455] when() accept callable first parameter (#54005) --- src/Illuminate/Collections/helpers.php | 2 ++ tests/Support/SupportHelpersTest.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Illuminate/Collections/helpers.php b/src/Illuminate/Collections/helpers.php index 6d691f5e3091..55844559e711 100644 --- a/src/Illuminate/Collections/helpers.php +++ b/src/Illuminate/Collections/helpers.php @@ -248,6 +248,8 @@ function value($value, ...$args) */ function when($condition, $value, $default = null) { + $condition = $condition instanceof Closure ? $condition() : $condition; + if ($condition) { return value($value, $condition); } diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index ee4c09a73101..55fef4e85369 100644 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -134,6 +134,8 @@ public function testWhen() $this->assertEquals('False', when([], 'True', 'False')); // Empty Array = Falsy $this->assertTrue(when(true, fn ($value) => $value, fn ($value) => ! $value)); // lazy evaluation $this->assertTrue(when(false, fn ($value) => $value, fn ($value) => ! $value)); // lazy evaluation + $this->assertEquals('Hello', when(fn () => true, 'Hello')); // lazy evaluation condition + $this->assertEquals('World', when(fn () => false, 'Hello', 'World')); // lazy evaluation condition } public function testFilled() From b5280f034d33b3a6b70c52ee2205a8801db60a87 Mon Sep 17 00:00:00 2001 From: Amir Mohammad Najmi <71878858+amirmohammadnajmi@users.noreply.github.com> Date: Mon, 30 Dec 2024 19:31:10 +0330 Subject: [PATCH 053/455] Add test for collapse in collections (#54032) --- tests/Support/SupportCollectionTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index beaa1f84109d..134c35b7539b 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -1735,8 +1735,26 @@ public function testUniqueStrict($collection) #[DataProvider('collectionClassProvider')] public function testCollapse($collection) { + // Normal case: a two-dimensional array with different elements $data = new $collection([[$object1 = new stdClass], [$object2 = new stdClass]]); $this->assertEquals([$object1, $object2], $data->collapse()->all()); + + // Case including numeric and string elements + $data = new $collection([[1], [2], [3], ['foo', 'bar'], new $collection(['baz', 'boom'])]); + $this->assertEquals([1, 2, 3, 'foo', 'bar', 'baz', 'boom'], $data->collapse()->all()); + + // Case with empty two-dimensional arrays + $data = new $collection([[], [], []]); + $this->assertEquals([], $data->collapse()->all()); + + // Case with both empty arrays and arrays with elements + $data = new $collection([[], [1, 2], [], ['foo', 'bar']]); + $this->assertEquals([1, 2, 'foo', 'bar'], $data->collapse()->all()); + + // Case including collections and arrays + $collection = new $collection(['baz', 'boom']); + $data = new $collection([[1], [2], [3], ['foo', 'bar'], $collection]); + $this->assertEquals([1, 2, 3, 'foo', 'bar', 'baz', 'boom'], $data->collapse()->all()); } #[DataProvider('collectionClassProvider')] From 06c33e3fcf109643b11433677c360aa73107e743 Mon Sep 17 00:00:00 2001 From: Amir Mohammad Najmi <71878858+amirmohammadnajmi@users.noreply.github.com> Date: Thu, 2 Jan 2025 19:19:02 +0330 Subject: [PATCH 054/455] [12.x] Add test for benchmark utilities (#54055) * Add test for benchmark utilities * fix style code * fix style code --- tests/Support/SupportBenchmarkTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/Support/SupportBenchmarkTest.php diff --git a/tests/Support/SupportBenchmarkTest.php b/tests/Support/SupportBenchmarkTest.php new file mode 100644 index 000000000000..f155971cd827 --- /dev/null +++ b/tests/Support/SupportBenchmarkTest.php @@ -0,0 +1,24 @@ +assertIsNumeric(Benchmark::measure(fn () => 1 + 1)); + + $this->assertIsArray(Benchmark::measure([ + 'first' => fn () => 1 + 1, + 'second' => fn () => 2 + 2, + ], 3)); + } + + public function testValue(): void + { + $this->assertIsArray(Benchmark::value(fn () => 1 + 1)); + } +} From 91f90686b61ab8fca751dcae90e85c875a27f115 Mon Sep 17 00:00:00 2001 From: Frederik Sauer Date: Mon, 6 Jan 2025 16:14:18 +0100 Subject: [PATCH 055/455] [12.x] Fix once() cache when used in extended static class (#54094) * Fix once() cache when used in extended static class * Update Onceable.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Onceable.php | 6 +++++- tests/Support/OnceTest.php | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Onceable.php b/src/Illuminate/Support/Onceable.php index 137fc34e3308..0e01406fdcdf 100644 --- a/src/Illuminate/Support/Onceable.php +++ b/src/Illuminate/Support/Onceable.php @@ -66,10 +66,14 @@ protected static function hashFromTrace(array $trace, callable $callable) $callable instanceof Closure ? (new ReflectionClosure($callable))->getClosureUsedVariables() : [], ); + $class = $callable instanceof Closure ? (new ReflectionClosure($callable))->getClosureCalledClass()?->getName() : null; + + $class ??= isset($trace[1]['class']) ? $trace[1]['class'] : null; + return hash('xxh128', sprintf( '%s@%s%s:%s (%s)', $trace[0]['file'], - isset($trace[1]['class']) ? ($trace[1]['class'].'@') : '', + $class ? $class.'@' : '', $trace[1]['function'], $trace[0]['line'], serialize($uses), diff --git a/tests/Support/OnceTest.php b/tests/Support/OnceTest.php index 907e7316c884..3e35cfd00e13 100644 --- a/tests/Support/OnceTest.php +++ b/tests/Support/OnceTest.php @@ -363,6 +363,14 @@ public function null() $this->assertSame($instance->null(), $instance->null()); $this->assertSame(1, $instance->i); } + + public function testExtendedStaticClassOnceCalls() + { + $first = MyClass::staticRand(); + $second = MyExtendedClass::staticRand(); + + $this->assertNotSame($first, $second); + } } $letter = 'a'; @@ -392,3 +400,7 @@ public function callRand() return once(fn () => $this->rand()); } } + +class MyExtendedClass extends MyClass +{ +} From 7691c66ddd1c6c00d21b37ba1a68bdcf1b1114cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Wed, 8 Jan 2025 00:20:05 +0100 Subject: [PATCH 056/455] $ignoreQuery closure support (#54104) --- src/Illuminate/Routing/UrlGenerator.php | 28 +++++++++++++++-------- tests/Routing/RoutingUrlGeneratorTest.php | 6 +++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index fff8ffd5eb44..b2c7a32c30ab 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -419,10 +419,10 @@ public function temporarySignedRoute($name, $expiration, $parameters = [], $abso * * @param \Illuminate\Http\Request $request * @param bool $absolute - * @param array $ignoreQuery + * @param \Closure|array $ignoreQuery * @return bool */ - public function hasValidSignature(Request $request, $absolute = true, array $ignoreQuery = []) + public function hasValidSignature(Request $request, $absolute = true, Closure|array $ignoreQuery = []) { return $this->hasCorrectSignature($request, $absolute, $ignoreQuery) && $this->signatureHasNotExpired($request); @@ -432,10 +432,10 @@ public function hasValidSignature(Request $request, $absolute = true, array $ign * Determine if the given request has a valid signature for a relative URL. * * @param \Illuminate\Http\Request $request - * @param array $ignoreQuery + * @param \Closure|array $ignoreQuery * @return bool */ - public function hasValidRelativeSignature(Request $request, array $ignoreQuery = []) + public function hasValidRelativeSignature(Request $request, Closure|array $ignoreQuery = []) { return $this->hasValidSignature($request, false, $ignoreQuery); } @@ -445,17 +445,27 @@ public function hasValidRelativeSignature(Request $request, array $ignoreQuery = * * @param \Illuminate\Http\Request $request * @param bool $absolute - * @param array $ignoreQuery + * @param \Closure|array $ignoreQuery * @return bool */ - public function hasCorrectSignature(Request $request, $absolute = true, array $ignoreQuery = []) + public function hasCorrectSignature(Request $request, $absolute = true, Closure|array $ignoreQuery = []) { - $ignoreQuery[] = 'signature'; - $url = $absolute ? $request->url() : '/'.$request->path(); $queryString = (new Collection(explode('&', (string) $request->server->get('QUERY_STRING')))) - ->reject(fn ($parameter) => in_array(Str::before($parameter, '='), $ignoreQuery)) + ->reject(function ($parameter) use ($ignoreQuery) { + $parameter = Str::before($parameter, '='); + + if ($parameter === 'signature') { + return true; + } + + if ($ignoreQuery instanceof Closure) { + return $ignoreQuery($parameter); + } + + return in_array($parameter, $ignoreQuery); + }) ->join('&'); $original = rtrim($url.'?'.$queryString, '?'); diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index b9ada1ce07bd..a0f01672125a 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -803,6 +803,12 @@ public function testSignedUrl() $request = Request::create($url->signedRoute('foo').'?tampered=true'); $this->assertFalse($url->hasValidSignature($request)); + + $request = Request::create($url->signedRoute('foo').'&tampered=true'); + + $this->assertTrue($url->hasValidSignature($request, ignoreQuery: ['tampered'])); + + $this->assertTrue($url->hasValidSignature($request, ignoreQuery: fn ($parameter) => $parameter === 'tampered')); } public function testSignedUrlImplicitModelBinding() From 6c3a5a06fce981d03d82c3f67b1c5c67e039205f Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Tue, 7 Jan 2025 23:20:35 +0000 Subject: [PATCH 057/455] Update facade docblocks --- src/Illuminate/Support/Facades/URL.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/URL.php b/src/Illuminate/Support/Facades/URL.php index 8e5af244b1db..8dddb0d16a95 100755 --- a/src/Illuminate/Support/Facades/URL.php +++ b/src/Illuminate/Support/Facades/URL.php @@ -16,9 +16,9 @@ * @method static string formatScheme(bool|null $secure = null) * @method static string signedRoute(\BackedEnum|string $name, mixed $parameters = [], \DateTimeInterface|\DateInterval|int|null $expiration = null, bool $absolute = true) * @method static string temporarySignedRoute(\BackedEnum|string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], bool $absolute = true) - * @method static bool hasValidSignature(\Illuminate\Http\Request $request, bool $absolute = true, array $ignoreQuery = []) - * @method static bool hasValidRelativeSignature(\Illuminate\Http\Request $request, array $ignoreQuery = []) - * @method static bool hasCorrectSignature(\Illuminate\Http\Request $request, bool $absolute = true, array $ignoreQuery = []) + * @method static bool hasValidSignature(\Illuminate\Http\Request $request, bool $absolute = true, \Closure|array $ignoreQuery = []) + * @method static bool hasValidRelativeSignature(\Illuminate\Http\Request $request, \Closure|array $ignoreQuery = []) + * @method static bool hasCorrectSignature(\Illuminate\Http\Request $request, bool $absolute = true, \Closure|array $ignoreQuery = []) * @method static bool signatureHasNotExpired(\Illuminate\Http\Request $request) * @method static string route(\BackedEnum|string $name, mixed $parameters = [], bool $absolute = true) * @method static string toRoute(\Illuminate\Routing\Route $route, mixed $parameters, bool $absolute) From 941c439f2b5551a810ad69e5315bfbe5ff13e0ee Mon Sep 17 00:00:00 2001 From: Will Rowe Date: Tue, 7 Jan 2025 18:44:43 -0500 Subject: [PATCH 058/455] Make `dropForeignIdFor` method complementary to `foreignIdFor` (#54102) * Update tests to properly assert that only the column is dropped * Drop the column instead of the foreign key --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- tests/Database/DatabaseSchemaBlueprintTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 2cf09470f666..729a7dce67ef 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -531,7 +531,7 @@ public function dropForeignIdFor($model, $column = null) $model = new $model; } - return $this->dropForeign([$column ?: $model->getForeignKey()]); + return $this->dropColumn($column ?: $model->getForeignKey()); } /** diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index 999097891f34..55e64b7d77a6 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -444,7 +444,7 @@ public function testDropRelationshipColumnWithIncrementalModel() }; $this->assertEquals([ - 'alter table `posts` drop foreign key `posts_user_id_foreign`', + 'alter table `posts` drop `user_id`', ], $getSql(new MySqlGrammar)); } @@ -457,7 +457,7 @@ public function testDropRelationshipColumnWithUuidModel() }; $this->assertEquals([ - 'alter table `posts` drop foreign key `posts_model_using_uuid_id_foreign`', + 'alter table `posts` drop `model_using_uuid_id`', ], $getSql(new MySqlGrammar)); } From 70bbb85174c3e3a22b6f8e928ecd1e0a4ac4b55c Mon Sep 17 00:00:00 2001 From: Will Rowe Date: Thu, 9 Jan 2025 15:02:59 -0500 Subject: [PATCH 059/455] Allow scoped disks to be scoped from other scoped disks (#54124) * Add failing test * If the parent config has a prefix append the prefix to it * Update FilesystemManager.php --------- Co-authored-by: Taylor Otwell --- .../Filesystem/FilesystemManager.php | 11 ++++++- tests/Filesystem/FilesystemManagerTest.php | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index dfdab7c6e7f8..d4d4be8e8136 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -298,7 +298,16 @@ public function createScopedDriver(array $config) return $this->build(tap( is_string($config['disk']) ? $this->getConfig($config['disk']) : $config['disk'], function (&$parent) use ($config) { - $parent['prefix'] = $config['prefix']; + if (empty($parent['prefix'])) { + $parent['prefix'] = $config['prefix']; + } else { + $separator = $parent['directory_separator'] ?? DIRECTORY_SEPARATOR; + + $parentPrefix = rtrim($parent['prefix'], $separator); + $scopedPrefix = ltrim($config['prefix'], $separator); + + $parent['prefix'] = "{$parentPrefix}{$separator}{$scopedPrefix}"; + } if (isset($config['visibility'])) { $parent['visibility'] = $config['visibility']; diff --git a/tests/Filesystem/FilesystemManagerTest.php b/tests/Filesystem/FilesystemManagerTest.php index 8850c5557a06..4bc8e0545a73 100644 --- a/tests/Filesystem/FilesystemManagerTest.php +++ b/tests/Filesystem/FilesystemManagerTest.php @@ -99,6 +99,38 @@ public function testCanBuildScopedDisks() } } + public function testCanBuildScopedDiskFromScopedDisk() + { + try { + $filesystem = new FilesystemManager(tap(new Application, function ($app) { + $app['config'] = [ + 'filesystems.disks.local' => [ + 'driver' => 'local', + 'root' => 'root-to-be-scoped', + ], + 'filesystems.disks.scoped-from-root' => [ + 'driver' => 'scoped', + 'disk' => 'local', + 'prefix' => 'scoped-from-root-prefix', + ], + ]; + })); + + $root = $filesystem->disk('local'); + $nestedScoped = $filesystem->build([ + 'driver' => 'scoped', + 'disk' => 'scoped-from-root', + 'prefix' => 'nested-scoped-prefix', + ]); + + $nestedScoped->put('dirname/filename.txt', 'file content'); + $this->assertEquals('file content', $root->get('scoped-from-root-prefix/nested-scoped-prefix/dirname/filename.txt')); + $root->deleteDirectory('scoped-from-root-prefix'); + } finally { + rmdir(__DIR__.'/../../root-to-be-scoped'); + } + } + #[RequiresOperatingSystem('Linux|Darwin')] public function testCanBuildScopedDisksWithVisibility() { From 9ee1432fbd531128156458a22d75c6f0dd4bd636 Mon Sep 17 00:00:00 2001 From: Amir Mohammad Najmi <71878858+amirmohammadnajmi@users.noreply.github.com> Date: Wed, 15 Jan 2025 22:55:13 +0330 Subject: [PATCH 060/455] Add test for Util::getParameterClassName() (#54209) --- tests/Container/UtilTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Container/UtilTest.php b/tests/Container/UtilTest.php index b467e533432a..928e07ad8841 100644 --- a/tests/Container/UtilTest.php +++ b/tests/Container/UtilTest.php @@ -4,6 +4,7 @@ use Illuminate\Container\Util; use PHPUnit\Framework\TestCase; +use ReflectionParameter; use stdClass; class UtilTest extends TestCase @@ -40,4 +41,15 @@ public function testArrayWrap() $this->assertEquals([$obj], Util::arrayWrap($obj)); $this->assertSame($obj, Util::arrayWrap($obj)[0]); } + + public function testGetParameterClassName() + { + $parameter = new ReflectionParameter(function (stdClass $foo) { + }, 0); + $this->assertSame('stdClass', Util::getParameterClassName($parameter)); + + $parameter = new ReflectionParameter(function (string $foo) { + }, 0); + $this->assertNull(Util::getParameterClassName($parameter)); + } } From 8961a43738f63e1b773d4a3d1ac0679ee3f027a1 Mon Sep 17 00:00:00 2001 From: Fabrice Planchette Date: Fri, 17 Jan 2025 16:16:16 +0100 Subject: [PATCH 061/455] Improve eloquent attach parameter consistency (#54225) --- .../Relations/Concerns/InteractsWithPivotTable.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 034a7d7c8630..77e4a48c0bef 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -260,21 +260,21 @@ protected function updateExistingPivotUsingCustomClass($id, array $attributes, $ /** * Attach a model to the parent. * - * @param mixed $id + * @param mixed $ids * @param array $attributes * @param bool $touch * @return void */ - public function attach($id, array $attributes = [], $touch = true) + public function attach($ids, array $attributes = [], $touch = true) { if ($this->using) { - $this->attachUsingCustomClass($id, $attributes); + $this->attachUsingCustomClass($ids, $attributes); } else { // Here we will insert the attachment records into the pivot table. Once we have // inserted the records, we will touch the relationships if necessary and the // function will return. We can parse the IDs before inserting the records. $this->newPivotStatement()->insert($this->formatAttachRecords( - $this->parseIds($id), $attributes + $this->parseIds($ids), $attributes )); } @@ -286,14 +286,14 @@ public function attach($id, array $attributes = [], $touch = true) /** * Attach a model to the parent using a custom class. * - * @param mixed $id + * @param mixed $ids * @param array $attributes * @return void */ - protected function attachUsingCustomClass($id, array $attributes) + protected function attachUsingCustomClass($ids, array $attributes) { $records = $this->formatAttachRecords( - $this->parseIds($id), $attributes + $this->parseIds($ids), $attributes ); foreach ($records as $record) { From 86c3dffd04accbd799eeecdda416be59f0ad6d10 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Thu, 23 Jan 2025 02:37:00 +0330 Subject: [PATCH 062/455] [12.x] Enhance multi-database support (#54274) * enhance multi-schema support * formatting * formatting * formatting * formatting * formatting * formatting * Update SchemaBuilderSchemaNameTest.php * formatting * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Connection.php | 12 +- .../Console/DatabaseInspectionCommand.php | 16 -- .../Database/Console/ShowCommand.php | 7 +- .../Database/Console/TableCommand.php | 22 +- src/Illuminate/Database/Grammar.php | 9 +- .../Database/Query/Grammars/SQLiteGrammar.php | 6 +- .../Query/Grammars/SqlServerGrammar.php | 5 +- .../Query/Processors/PostgresProcessor.php | 1 + .../Database/Query/Processors/Processor.php | 25 ++- .../Query/Processors/SQLiteProcessor.php | 2 +- src/Illuminate/Database/Schema/Builder.php | 125 +++++++++-- .../Database/Schema/Grammars/Grammar.php | 109 +++++++++- .../Database/Schema/Grammars/MySqlGrammar.php | 79 ++++--- .../Schema/Grammars/PostgresGrammar.php | 66 ++++-- .../Schema/Grammars/SQLiteGrammar.php | 160 ++++++++++---- .../Schema/Grammars/SqlServerGrammar.php | 81 +++---- .../Database/Schema/MySqlBuilder.php | 122 ++--------- .../Database/Schema/PostgresBuilder.php | 199 ++---------------- .../Database/Schema/PostgresSchemaState.php | 2 +- .../Database/Schema/SQLiteBuilder.php | 83 ++++++-- .../Database/Schema/SqlServerBuilder.php | 122 +---------- .../Foundation/Testing/DatabaseTruncation.php | 14 +- src/Illuminate/Support/Facades/DB.php | 2 +- src/Illuminate/Support/Facades/Schema.php | 12 +- .../DatabaseMariaDbSchemaBuilderTest.php | 2 +- .../DatabaseMySQLSchemaBuilderTest.php | 2 +- .../Database/DatabasePostgresBuilderTest.php | 18 +- .../DatabasePostgresSchemaBuilderTest.php | 7 +- tests/Database/DatabaseQueryBuilderTest.php | 31 ++- .../DatabaseSQLiteSchemaGrammarTest.php | 95 ++++++++- .../Database/DatabaseSchemaBlueprintTest.php | 22 ++ tests/Database/DatabaseSchemaBuilderTest.php | 5 +- .../DatabaseSqlServerSchemaGrammarTest.php | 29 ++- .../Testing/DatabaseTruncationTest.php | 97 ++++----- .../Database/SchemaBuilderSchemaNameTest.php | 183 ++++++++++++++-- .../Sqlite/DatabaseSchemaBlueprintTest.php | 23 +- .../Sqlite/SchemaBuilderSchemaNameTest.php | 11 + .../Database/Sqlite/SchemaStateTest.php | 2 +- 38 files changed, 1061 insertions(+), 747 deletions(-) create mode 100644 tests/Integration/Database/Sqlite/SchemaBuilderSchemaNameTest.php diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 64f2eb25bf2b..8dd7213117c4 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1650,17 +1650,19 @@ public function withTablePrefix(Grammar $grammar) * Execute the given callback without table prefix. * * @param \Closure $callback - * @return void + * @return mixed */ - public function withoutTablePrefix(Closure $callback): void + public function withoutTablePrefix(Closure $callback): mixed { $tablePrefix = $this->getTablePrefix(); $this->setTablePrefix(''); - $callback($this); - - $this->setTablePrefix($tablePrefix); + try { + return $callback($this); + } finally { + $this->setTablePrefix($tablePrefix); + } } /** diff --git a/src/Illuminate/Database/Console/DatabaseInspectionCommand.php b/src/Illuminate/Database/Console/DatabaseInspectionCommand.php index 00fc9257690e..8faab04147ab 100644 --- a/src/Illuminate/Database/Console/DatabaseInspectionCommand.php +++ b/src/Illuminate/Database/Console/DatabaseInspectionCommand.php @@ -47,20 +47,4 @@ protected function getConfigFromDatabase($database) return Arr::except(config('database.connections.'.$database), ['password']); } - - /** - * Remove the table prefix from a table name, if it exists. - * - * @param \Illuminate\Database\ConnectionInterface $connection - * @param string $table - * @return string - */ - protected function withoutTablePrefix(ConnectionInterface $connection, string $table) - { - $prefix = $connection->getTablePrefix(); - - return str_starts_with($table, $prefix) - ? substr($table, strlen($prefix)) - : $table; - } } diff --git a/src/Illuminate/Database/Console/ShowCommand.php b/src/Illuminate/Database/Console/ShowCommand.php index 3abc69bbe83e..64c80572b927 100644 --- a/src/Illuminate/Database/Console/ShowCommand.php +++ b/src/Illuminate/Database/Console/ShowCommand.php @@ -8,7 +8,6 @@ use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Number; -use Illuminate\Support\Stringable; use Symfony\Component\Console\Attribute\AsCommand; #[AsCommand(name: 'db:show')] @@ -80,9 +79,10 @@ protected function tables(ConnectionInterface $connection, Builder $schema) return (new Collection($schema->getTables()))->map(fn ($table) => [ 'table' => $table['name'], 'schema' => $table['schema'], + 'schema_qualified_name' => $table['schema_qualified_name'], 'size' => $table['size'], 'rows' => $this->option('counts') - ? ($connection->table($table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name'])->count()) + ? $connection->withoutTablePrefix(fn ($connection) => $connection->table($table['schema_qualified_name'])->count()) : null, 'engine' => $table['engine'], 'collation' => $table['collation'], @@ -100,11 +100,10 @@ protected function tables(ConnectionInterface $connection, Builder $schema) protected function views(ConnectionInterface $connection, Builder $schema) { return (new Collection($schema->getViews())) - ->reject(fn ($view) => (new Stringable($view['name']))->startsWith(['pg_catalog', 'information_schema', 'spt_'])) ->map(fn ($view) => [ 'view' => $view['name'], 'schema' => $view['schema'], - 'rows' => $connection->table($view['schema'] ? $view['schema'].'.'.$view['name'] : $view['name'])->count(), + 'rows' => $connection->withoutTablePrefix(fn ($connection) => $connection->table($view['schema_qualified_name'])->count()), ]); } diff --git a/src/Illuminate/Database/Console/TableCommand.php b/src/Illuminate/Database/Console/TableCommand.php index ccde5c29680c..fde40a78f8a3 100644 --- a/src/Illuminate/Database/Console/TableCommand.php +++ b/src/Illuminate/Database/Console/TableCommand.php @@ -39,10 +39,8 @@ class TableCommand extends DatabaseInspectionCommand public function handle(ConnectionResolverInterface $connections) { $connection = $connections->connection($this->input->getOption('database')); - $schema = $connection->getSchemaBuilder(); - $tables = (new Collection($schema->getTables())) - ->keyBy(fn ($table) => $table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name']) - ->all(); + $tables = (new Collection($connection->getSchemaBuilder()->getTables())) + ->keyBy('schema_qualified_name')->all(); $tableName = $this->argument('table') ?: select( 'Which table would you like to inspect?', @@ -57,16 +55,22 @@ public function handle(ConnectionResolverInterface $connections) return 1; } - $tableName = ($table['schema'] ? $table['schema'].'.' : '').$this->withoutTablePrefix($connection, $table['name']); + [$columns, $indexes, $foreignKeys] = $connection->withoutTablePrefix(function ($connection) use ($table) { + $schema = $connection->getSchemaBuilder(); + $tableName = $table['schema_qualified_name']; - $columns = $this->columns($schema, $tableName); - $indexes = $this->indexes($schema, $tableName); - $foreignKeys = $this->foreignKeys($schema, $tableName); + return [ + $this->columns($schema, $tableName), + $this->indexes($schema, $tableName), + $this->foreignKeys($schema, $tableName), + ]; + }); $data = [ 'table' => [ 'schema' => $table['schema'], 'name' => $table['name'], + 'schema_qualified_name' => $table['schema_qualified_name'], 'columns' => count($columns), 'size' => $table['size'], 'comment' => $table['comment'], @@ -205,7 +209,7 @@ protected function displayForCli(array $data) $this->newLine(); - $this->components->twoColumnDetail(''.($table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name']).'', $table['comment'] ? ''.$table['comment'].'' : null); + $this->components->twoColumnDetail(''.$table['schema_qualified_name'].'', $table['comment'] ? ''.$table['comment'].'' : null); $this->components->twoColumnDetail('Columns', $table['columns']); if (! is_null($table['size'])) { diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 28c1a2f10f24..187d1348ad30 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -40,9 +40,10 @@ public function wrapArray(array $values) * Wrap a table in keyword identifiers. * * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param string|null $prefix * @return string */ - public function wrapTable($table) + public function wrapTable($table, $prefix = null) { if ($this->isExpression($table)) { return $this->getValue($table); @@ -55,18 +56,20 @@ public function wrapTable($table) return $this->wrapAliasedTable($table); } + $prefix ??= $this->tablePrefix; + // If the table being wrapped has a custom schema name specified, we need to // prefix the last segment as the table name then wrap each segment alone // and eventually join them both back together using the dot connector. if (str_contains($table, '.')) { - $table = substr_replace($table, '.'.$this->tablePrefix, strrpos($table, '.'), 1); + $table = substr_replace($table, '.'.$prefix, strrpos($table, '.'), 1); return (new Collection(explode('.', $table))) ->map($this->wrapValue(...)) ->implode('.'); } - return $this->wrapValue($this->tablePrefix.$table); + return $this->wrapValue($prefix.$table); } /** diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index 0999f4ec6f86..6dc65a07c034 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -439,8 +439,12 @@ protected function compileDeleteWithJoinsOrLimit(Builder $query) */ public function compileTruncate(Builder $query) { + [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($query->from); + + $schema = $schema ? $this->wrapValue($schema).'.' : ''; + return [ - 'delete from sqlite_sequence where name = ?' => [$this->getTablePrefix().$query->from], + 'delete from '.$schema.'sqlite_sequence where name = ?' => [$this->getTablePrefix().$table], 'delete from '.$this->wrapTable($query->from) => [], ]; } diff --git a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php index ff1ac5cd3e68..0b2dd381c1ab 100755 --- a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php @@ -557,12 +557,13 @@ protected function wrapJsonBooleanValue($value) * Wrap a table in keyword identifiers. * * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param string|null $prefix * @return string */ - public function wrapTable($table) + public function wrapTable($table, $prefix = null) { if (! $this->isExpression($table)) { - return $this->wrapTableValuedFunction(parent::wrapTable($table)); + return $this->wrapTableValuedFunction(parent::wrapTable($table, $prefix)); } return $this->getValue($table); diff --git a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php index 80babf37fb6b..bedf9a4213ef 100755 --- a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php +++ b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php @@ -44,6 +44,7 @@ public function processTypes($results) return [ 'name' => $result->name, 'schema' => $result->schema, + 'schema_qualified_name' => $result->schema.'.'.$result->name, 'implicit' => (bool) $result->implicit, 'type' => match (strtolower($result->type)) { 'b' => 'base', diff --git a/src/Illuminate/Database/Query/Processors/Processor.php b/src/Illuminate/Database/Query/Processors/Processor.php index 936e6245b170..c2b1e8b782e9 100755 --- a/src/Illuminate/Database/Query/Processors/Processor.php +++ b/src/Illuminate/Database/Query/Processors/Processor.php @@ -36,6 +36,25 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu return is_numeric($id) ? (int) $id : $id; } + /** + * Process the results of a schemas query. + * + * @param array $results + * @return array + */ + public function processSchemas($results) + { + return array_map(function ($result) { + $result = (object) $result; + + return [ + 'name' => $result->name, + 'path' => $result->path ?? null, // SQLite Only... + 'default' => (bool) $result->default, + ]; + }, $results); + } + /** * Process the results of a tables query. * @@ -49,7 +68,8 @@ public function processTables($results) return [ 'name' => $result->name, - 'schema' => $result->schema ?? null, // PostgreSQL and SQL Server + 'schema' => $result->schema ?? null, + 'schema_qualified_name' => isset($result->schema) ? $result->schema.'.'.$result->name : $result->name, 'size' => isset($result->size) ? (int) $result->size : null, 'comment' => $result->comment ?? null, // MySQL and PostgreSQL 'collation' => $result->collation ?? null, // MySQL only @@ -71,7 +91,8 @@ public function processViews($results) return [ 'name' => $result->name, - 'schema' => $result->schema ?? null, // PostgreSQL and SQL Server + 'schema' => $result->schema ?? null, + 'schema_qualified_name' => isset($result->schema) ? $result->schema.'.'.$result->name : $result->name, 'definition' => $result->definition, ]; }, $results); diff --git a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php index dadeaeb467ad..7062c2cd1d7b 100644 --- a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php +++ b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php @@ -104,7 +104,7 @@ public function processForeignKeys($results) return [ 'name' => null, 'columns' => explode(',', $result->columns), - 'foreign_schema' => null, + 'foreign_schema' => $result->foreign_schema, 'foreign_table' => $result->foreign_table, 'foreign_columns' => explode(',', $result->foreign_columns), 'on_update' => strtolower($result->on_update), diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 38cadfbd2794..a42f9f28802b 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -147,6 +147,18 @@ public function dropDatabaseIfExists($name) throw new LogicException('This database driver does not support dropping databases.'); } + /** + * Get the schemas that belong to the connection. + * + * @return array + */ + public function getSchemas() + { + return $this->connection->getPostProcessor()->processSchemas( + $this->connection->selectFromWriteConnection($this->grammar->compileSchemas()) + ); + } + /** * Determine if the given table exists. * @@ -155,9 +167,15 @@ public function dropDatabaseIfExists($name) */ public function hasTable($table) { + [$schema, $table] = $this->parseSchemaAndTable($table); + $table = $this->connection->getTablePrefix().$table; - foreach ($this->getTables() as $value) { + if ($sql = $this->grammar->compileTableExists($schema, $table)) { + return (bool) $this->connection->scalar($sql); + } + + foreach ($this->getTables($schema ?? $this->getCurrentSchemaName()) as $value) { if (strtolower($table) === strtolower($value['name'])) { return true; } @@ -174,9 +192,11 @@ public function hasTable($table) */ public function hasView($view) { + [$schema, $view] = $this->parseSchemaAndTable($view); + $view = $this->connection->getTablePrefix().$view; - foreach ($this->getViews() as $value) { + foreach ($this->getViews($schema ?? $this->getCurrentSchemaName()) as $value) { if (strtolower($view) === strtolower($value['name'])) { return true; } @@ -186,47 +206,57 @@ public function hasView($view) } /** - * Get the tables that belong to the database. + * Get the tables that belong to the connection. * + * @param string|string[]|null $schema * @return array */ - public function getTables() + public function getTables($schema = null) { return $this->connection->getPostProcessor()->processTables( - $this->connection->selectFromWriteConnection($this->grammar->compileTables()) + $this->connection->selectFromWriteConnection($this->grammar->compileTables($schema)) ); } /** - * Get the names of the tables that belong to the database. + * Get the names of the tables that belong to the connection. * + * @param string|string[]|null $schema + * @param bool $schemaQualified * @return array */ - public function getTableListing() + public function getTableListing($schema = null, $schemaQualified = true) { - return array_column($this->getTables(), 'name'); + return array_column( + $this->getTables($schema), + $schemaQualified ? 'schema_qualified_name' : 'name' + ); } /** - * Get the views that belong to the database. + * Get the views that belong to the connection. * + * @param string|string[]|null $schema * @return array */ - public function getViews() + public function getViews($schema = null) { return $this->connection->getPostProcessor()->processViews( - $this->connection->selectFromWriteConnection($this->grammar->compileViews()) + $this->connection->selectFromWriteConnection($this->grammar->compileViews($schema)) ); } /** - * Get the user-defined types that belong to the database. + * Get the user-defined types that belong to the connection. * + * @param string|string[]|null $schema * @return array */ - public function getTypes() + public function getTypes($schema = null) { - throw new LogicException('This database driver does not support user-defined types.'); + return $this->connection->getPostProcessor()->processTypes( + $this->connection->selectFromWriteConnection($this->grammar->compileTypes($schema)) + ); } /** @@ -333,10 +363,14 @@ public function getColumnListing($table) */ public function getColumns($table) { + [$schema, $table] = $this->parseSchemaAndTable($table); + $table = $this->connection->getTablePrefix().$table; return $this->connection->getPostProcessor()->processColumns( - $this->connection->selectFromWriteConnection($this->grammar->compileColumns($table)) + $this->connection->selectFromWriteConnection( + $this->grammar->compileColumns($schema, $table) + ) ); } @@ -348,10 +382,14 @@ public function getColumns($table) */ public function getIndexes($table) { + [$schema, $table] = $this->parseSchemaAndTable($table); + $table = $this->connection->getTablePrefix().$table; return $this->connection->getPostProcessor()->processIndexes( - $this->connection->selectFromWriteConnection($this->grammar->compileIndexes($table)) + $this->connection->selectFromWriteConnection( + $this->grammar->compileIndexes($schema, $table) + ) ); } @@ -400,10 +438,14 @@ public function hasIndex($table, $index, $type = null) */ public function getForeignKeys($table) { + [$schema, $table] = $this->parseSchemaAndTable($table); + $table = $this->connection->getTablePrefix().$table; return $this->connection->getPostProcessor()->processForeignKeys( - $this->connection->selectFromWriteConnection($this->grammar->compileForeignKeys($table)) + $this->connection->selectFromWriteConnection( + $this->grammar->compileForeignKeys($schema, $table) + ) ); } @@ -597,6 +639,55 @@ protected function createBlueprint($table, ?Closure $callback = null) return Container::getInstance()->make(Blueprint::class, compact('connection', 'table', 'callback', 'prefix')); } + /** + * Get the names of the current schemas for the connection. + * + * @return string[]|null + */ + public function getCurrentSchemaListing() + { + return null; + } + + /** + * Get the default schema name for the connection. + * + * @return string|null + */ + public function getCurrentSchemaName() + { + return $this->getCurrentSchemaListing()[0] ?? null; + } + + /** + * Parse the given database object reference and extract the schema and table. + * + * @param string $reference + * @param string|bool|null $withDefaultSchema + * @return array + */ + public function parseSchemaAndTable($reference, $withDefaultSchema = null) + { + $segments = explode('.', $reference); + + if (count($segments) > 2) { + throw new InvalidArgumentException( + "Using three-part references is not supported, you may use `Schema::connection('{$segments[0]}')` instead." + ); + } + + $table = $segments[1] ?? $segments[0]; + + $schema = match (true) { + isset($segments[1]) => $segments[0], + is_string($withDefaultSchema) => $withDefaultSchema, + $withDefaultSchema => $this->getCurrentSchemaName(), + default => null, + }; + + return [$schema, $table]; + } + /** * Get the database connection instance. * diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index b21fcf23b65d..fd78be04e96c 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -64,6 +64,109 @@ public function compileDropDatabaseIfExists($name) throw new LogicException('This database driver does not support dropping databases.'); } + /** + * Compile the query to determine the schemas. + * + * @return string + */ + public function compileSchemas() + { + throw new RuntimeException('This database driver does not support retrieving schemas.'); + } + + /** + * Compile the query to determine if the given table exists. + * + * @param string|null $schema + * @param string $table + * @return string|null + */ + public function compileTableExists($schema, $table) + { + // + } + + /** + * Compile the query to determine the tables. + * + * @param string|string[]|null $schema + * @return string + * + * @throws \RuntimeException + */ + public function compileTables($schema) + { + throw new RuntimeException('This database driver does not support retrieving tables.'); + } + + /** + * Compile the query to determine the views. + * + * @param string|string[]|null $schema + * @return string + * + * @throws \RuntimeException + */ + public function compileViews($schema) + { + throw new RuntimeException('This database driver does not support retrieving views.'); + } + + /** + * Compile the query to determine the user-defined types. + * + * @param string|string[]|null $schema + * @return string + * + * @throws \RuntimeException + */ + public function compileTypes($schema) + { + throw new RuntimeException('This database driver does not support retrieving user-defined types.'); + } + + /** + * Compile the query to determine the columns. + * + * @param string|null $schema + * @param string $table + * @return string + * + * @throws \RuntimeException + */ + public function compileColumns($schema, $table) + { + throw new RuntimeException('This database driver does not support retrieving columns.'); + } + + /** + * Compile the query to determine the indexes. + * + * @param string|null $schema + * @param string $table + * @return string + * + * @throws \RuntimeException + */ + public function compileIndexes($schema, $table) + { + throw new RuntimeException('This database driver does not support retrieving indexes.'); + } + + /** + * Compile the query to determine the foreign keys. + * + * @param string|null $schema + * @param string $table + * @return string + * + * @throws \RuntimeException + */ + public function compileForeignKeys($schema, $table) + { + throw new RuntimeException('This database driver does not support retrieving foreign keys.'); + } + /** * Compile a rename column command. * @@ -343,12 +446,14 @@ public function prefixArray($prefix, array $values) * Wrap a table in keyword identifiers. * * @param mixed $table + * @param string|null $prefix * @return string */ - public function wrapTable($table) + public function wrapTable($table, $prefix = null) { return parent::wrapTable( - $table instanceof Blueprint ? $table->getTable() : $table + $table instanceof Blueprint ? $table->getTable() : $table, + $prefix ); } diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 456210c08da7..5012fa4d48d3 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -77,19 +77,31 @@ public function compileDropDatabaseIfExists($name) ); } + /** + * Compile the query to determine the schemas. + * + * @return string + */ + public function compileSchemas() + { + return 'select schema_name as name, schema_name = schema() as `default` from information_schema.schemata where ' + .$this->compileSchemaWhereClause(null, 'schema_name') + .' order by schema_name'; + } + /** * Compile the query to determine if the given table exists. * - * @param string $database + * @param string|null $schema * @param string $table * @return string */ - public function compileTableExists($database, $table) + public function compileTableExists($schema, $table) { return sprintf( 'select exists (select 1 from information_schema.tables where ' ."table_schema = %s and table_name = %s and table_type in ('BASE TABLE', 'SYSTEM VERSIONED')) as `exists`", - $this->quoteString($database), + $schema ? $this->quoteString($schema) : 'schema()', $this->quoteString($table) ); } @@ -97,44 +109,59 @@ public function compileTableExists($database, $table) /** * Compile the query to determine the tables. * - * @param string $database + * @param string|string[]|null $schema * @return string */ - public function compileTables($database) + public function compileTables($schema) { return sprintf( - 'select table_name as `name`, (data_length + index_length) as `size`, ' + 'select table_name as `name`, table_schema as `schema`, (data_length + index_length) as `size`, ' .'table_comment as `comment`, engine as `engine`, table_collation as `collation` ' - ."from information_schema.tables where table_schema = %s and table_type in ('BASE TABLE', 'SYSTEM VERSIONED') " - .'order by table_name', - $this->quoteString($database) + ."from information_schema.tables where table_type in ('BASE TABLE', 'SYSTEM VERSIONED') and " + .$this->compileSchemaWhereClause($schema, 'table_schema') + .' order by table_schema, table_name', + $this->quoteString($schema) ); } /** * Compile the query to determine the views. * - * @param string $database + * @param string|string[]|null $schema * @return string */ - public function compileViews($database) + public function compileViews($schema) { - return sprintf( - 'select table_name as `name`, view_definition as `definition` ' - .'from information_schema.views where table_schema = %s ' - .'order by table_name', - $this->quoteString($database) - ); + return 'select table_name as `name`, table_schema as `schema`, view_definition as `definition` ' + .'from information_schema.views where ' + .$this->compileSchemaWhereClause($schema, 'table_schema') + .' order by table_schema, table_name'; + } + + /** + * Compile the query to compare the schema. + * + * @param string|string[]|null $schema + * @param string $column + * @return string + */ + protected function compileSchemaWhereClause($schema, $column) + { + return $column.(match (true) { + ! empty($schema) && is_array($schema) => ' in ('.$this->quoteString($schema).')', + ! empty($schema) => ' = '.$this->quoteString($schema), + default => " not in ('information_schema', 'mysql', 'ndbinfo', 'performance_schema', 'sys')", + }); } /** * Compile the query to determine the columns. * - * @param string $database + * @param string|null $schema * @param string $table * @return string */ - public function compileColumns($database, $table) + public function compileColumns($schema, $table) { return sprintf( 'select column_name as `name`, data_type as `type_name`, column_type as `type`, ' @@ -143,7 +170,7 @@ public function compileColumns($database, $table) .'generation_expression as `expression`, extra as `extra` ' .'from information_schema.columns where table_schema = %s and table_name = %s ' .'order by ordinal_position asc', - $this->quoteString($database), + $schema ? $this->quoteString($schema) : 'schema()', $this->quoteString($table) ); } @@ -151,18 +178,18 @@ public function compileColumns($database, $table) /** * Compile the query to determine the indexes. * - * @param string $database + * @param string|null $schema * @param string $table * @return string */ - public function compileIndexes($database, $table) + public function compileIndexes($schema, $table) { return sprintf( 'select index_name as `name`, group_concat(column_name order by seq_in_index) as `columns`, ' .'index_type as `type`, not non_unique as `unique` ' .'from information_schema.statistics where table_schema = %s and table_name = %s ' .'group by index_name, index_type, non_unique', - $this->quoteString($database), + $schema ? $this->quoteString($schema) : 'schema()', $this->quoteString($table) ); } @@ -170,11 +197,11 @@ public function compileIndexes($database, $table) /** * Compile the query to determine the foreign keys. * - * @param string $database + * @param string|null $schema * @param string $table * @return string */ - public function compileForeignKeys($database, $table) + public function compileForeignKeys($schema, $table) { return sprintf( 'select kc.constraint_name as `name`, ' @@ -188,7 +215,7 @@ public function compileForeignKeys($database, $table) .'on kc.constraint_schema = rc.constraint_schema and kc.constraint_name = rc.constraint_name ' .'where kc.table_schema = %s and kc.table_name = %s and kc.referenced_table_name is not null ' .'group by kc.constraint_name, kc.referenced_table_schema, kc.referenced_table_name, rc.update_rule, rc.delete_rule', - $this->quoteString($database), + $schema ? $this->quoteString($schema) : 'schema()', $this->quoteString($table) ); } diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index c9a579fdad2e..8a2ccb2cff1a 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -69,10 +69,22 @@ public function compileDropDatabaseIfExists($name) ); } + /** + * Compile the query to determine the schemas. + * + * @return string + */ + public function compileSchemas() + { + return 'select nspname as name, nspname = current_schema() as "default" from pg_namespace where ' + .$this->compileSchemaWhereClause(null, 'nspname') + .' order by nspname'; + } + /** * Compile the query to determine if the given table exists. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -81,7 +93,7 @@ public function compileTableExists($schema, $table) return sprintf( 'select exists (select 1 from pg_class c, pg_namespace n where ' ."n.nspname = %s and c.relname = %s and c.relkind in ('r', 'p') and n.oid = c.relnamespace)", - $this->quoteString($schema), + $schema ? $this->quoteString($schema) : 'current_schema()', $this->quoteString($table) ); } @@ -89,32 +101,38 @@ public function compileTableExists($schema, $table) /** * Compile the query to determine the tables. * + * @param string|string[]|null $schema * @return string */ - public function compileTables() + public function compileTables($schema) { return 'select c.relname as name, n.nspname as schema, pg_total_relation_size(c.oid) as size, ' ."obj_description(c.oid, 'pg_class') as comment from pg_class c, pg_namespace n " - ."where c.relkind in ('r', 'p') and n.oid = c.relnamespace and n.nspname not in ('pg_catalog', 'information_schema') " - .'order by c.relname'; + ."where c.relkind in ('r', 'p') and n.oid = c.relnamespace and " + .$this->compileSchemaWhereClause($schema, 'n.nspname') + .' order by n.nspname, c.relname'; } /** * Compile the query to determine the views. * + * @param string|string[]|null $schema * @return string */ - public function compileViews() + public function compileViews($schema) { - return "select viewname as name, schemaname as schema, definition from pg_views where schemaname not in ('pg_catalog', 'information_schema') order by viewname"; + return 'select viewname as name, schemaname as schema, definition from pg_views where ' + .$this->compileSchemaWhereClause($schema, 'schemaname') + .' order by schemaname, viewname'; } /** * Compile the query to determine the user-defined types. * + * @param string|string[]|null $schema * @return string */ - public function compileTypes() + public function compileTypes($schema) { return 'select t.typname as name, n.nspname as schema, t.typtype as type, t.typcategory as category, ' ."((t.typinput = 'array_in'::regproc and t.typoutput = 'array_out'::regproc) or t.typtype = 'm') as implicit " @@ -123,14 +141,30 @@ public function compileTypes() .'left join pg_type el on el.oid = t.typelem ' .'left join pg_class ce on ce.oid = el.typrelid ' ."where ((t.typrelid = 0 and (ce.relkind = 'c' or ce.relkind is null)) or c.relkind = 'c') " - ."and not exists (select 1 from pg_depend d where d.objid in (t.oid, t.typelem) and d.deptype = 'e') " - ."and n.nspname not in ('pg_catalog', 'information_schema')"; + ."and not exists (select 1 from pg_depend d where d.objid in (t.oid, t.typelem) and d.deptype = 'e') and " + .$this->compileSchemaWhereClause($schema, 'n.nspname'); + } + + /** + * Compile the query to compare the schema. + * + * @param string|string[]|null $schema + * @param string $column + * @return string + */ + protected function compileSchemaWhereClause($schema, $column) + { + return $column.(match (true) { + ! empty($schema) && is_array($schema) => ' in ('.$this->quoteString($schema).')', + ! empty($schema) => ' = '.$this->quoteString($schema), + default => " <> 'information_schema' and $column not like 'pg\_%'", + }); } /** * Compile the query to determine the columns. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -147,14 +181,14 @@ public function compileColumns($schema, $table) .'where c.relname = %s and n.nspname = %s and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid and n.oid = c.relnamespace ' .'order by a.attnum', $this->quoteString($table), - $this->quoteString($schema) + $schema ? $this->quoteString($schema) : 'current_schema()' ); } /** * Compile the query to determine the indexes. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -173,14 +207,14 @@ public function compileIndexes($schema, $table) .'where tc.relname = %s and tn.nspname = %s ' .'group by ic.relname, am.amname, i.indisunique, i.indisprimary', $this->quoteString($table), - $this->quoteString($schema) + $schema ? $this->quoteString($schema) : 'current_schema()' ); } /** * Compile the query to determine the foreign keys. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -203,7 +237,7 @@ public function compileForeignKeys($schema, $table) ."where c.contype = 'f' and tc.relname = %s and tn.nspname = %s " .'group by c.conname, fn.nspname, fc.relname, c.confupdtype, c.confdeltype', $this->quoteString($table), - $this->quoteString($schema) + $schema ? $this->quoteString($schema) : 'current_schema()' ); } diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index b40f6cf1f755..dc37b26d5730 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -47,15 +47,17 @@ public function getAlterCommands(Connection $connection) /** * Compile the query to determine the SQL text that describes the given object. * + * @param string|null $schema * @param string $name * @param string $type * @return string */ - public function compileSqlCreateStatement($name, $type = 'table') + public function compileSqlCreateStatement($schema, $name, $type = 'table') { - return sprintf('select "sql" from sqlite_master where type = %s and name = %s', + return sprintf('select "sql" from %s.sqlite_master where type = %s and name = %s', + $this->wrapValue($schema ?? 'main'), $this->quoteString($type), - $this->quoteString(str_replace('.', '__', $name)) + $this->quoteString($name) ); } @@ -69,95 +71,155 @@ public function compileDbstatExists() return "select exists (select 1 from pragma_compile_options where compile_options = 'ENABLE_DBSTAT_VTAB') as enabled"; } + /** + * Compile the query to determine the schemas. + * + * @return string + */ + public function compileSchemas() + { + return 'select name, file as path, name = \'main\' as "default" from pragma_database_list order by name'; + } + /** * Compile the query to determine if the given table exists. * + * @param string|null $schema * @param string $table * @return string */ - public function compileTableExists($table) + public function compileTableExists($schema, $table) { return sprintf( - 'select exists (select 1 from sqlite_master where name = %s and type = \'table\') as "exists"', - $this->quoteString(str_replace('.', '__', $table)) + 'select exists (select 1 from %s.sqlite_master where name = %s and type = \'table\') as "exists"', + $this->wrapValue($schema ?? 'main'), + $this->quoteString($table) ); } /** * Compile the query to determine the tables. * + * @param string|string[]|null $schema * @param bool $withSize * @return string */ - public function compileTables($withSize = false) + public function compileTables($schema, $withSize = false) + { + return 'select tl.name as name, tl.schema as schema' + .($withSize ? ', (select sum(s.pgsize) ' + .'from (select tl.name as name union select il.name as name from pragma_index_list(tl.name, tl.schema) as il) as es ' + .'join dbstat(tl.schema) as s on s.name = es.name) as size' : '') + .' from pragma_table_list as tl where' + .(match (true) { + ! empty($schema) && is_array($schema) => ' tl.schema in ('.$this->quoteString($schema).') and', + ! empty($schema) => ' tl.schema = '.$this->quoteString($schema).' and', + default => '', + }) + ." tl.type in ('table', 'virtual') and tl.name not like 'sqlite\_%' escape '\' " + .'order by tl.schema, tl.name'; + } + + /** + * Compile the query for legacy versions of SQLite to determine the tables. + * + * @param string|string[]|null $schema + * @param bool $withSize + * @return string + */ + public function compileLegacyTables($schema, $withSize = false) { return $withSize - ? 'select m.tbl_name as name, sum(s.pgsize) as size from sqlite_master as m ' - .'join dbstat as s on s.name = m.name ' - ."where m.type in ('table', 'index') and m.tbl_name not like 'sqlite_%' " - .'group by m.tbl_name ' - .'order by m.tbl_name' - : "select name from sqlite_master where type = 'table' and name not like 'sqlite_%' order by name"; + ? sprintf( + 'select m.tbl_name as name, %s as schema, sum(s.pgsize) as size from %s.sqlite_master as m ' + .'join dbstat(%s) as s on s.name = m.name ' + ."where m.type in ('table', 'index') and m.tbl_name not like 'sqlite\_%%' escape '\' " + .'group by m.tbl_name ' + .'order by m.tbl_name', + $this->quoteString($schema), + $this->wrapValue($schema), + $this->quoteString($schema) + ) + : sprintf( + 'select name, %s as schema from %s.sqlite_master ' + ."where type = 'table' and name not like 'sqlite\_%%' escape '\' order by name", + $this->quoteString($schema), + $this->wrapValue($schema) + ); } /** * Compile the query to determine the views. * + * @param string $schema * @return string */ - public function compileViews() + public function compileViews($schema) { - return "select name, sql as definition from sqlite_master where type = 'view' order by name"; + return sprintf( + "select name, %s as schema, sql as definition from %s.sqlite_master where type = 'view' order by name", + $this->quoteString($schema), + $this->wrapValue($schema) + ); } /** * Compile the query to determine the columns. * + * @param string|null $schema * @param string $table * @return string */ - public function compileColumns($table) + public function compileColumns($schema, $table) { return sprintf( 'select name, type, not "notnull" as "nullable", dflt_value as "default", pk as "primary", hidden as "extra" ' - .'from pragma_table_xinfo(%s) order by cid asc', - $this->quoteString(str_replace('.', '__', $table)) + .'from pragma_table_xinfo(%s, %s) order by cid asc', + $this->quoteString($table), + $this->quoteString($schema ?? 'main') ); } /** * Compile the query to determine the indexes. * + * @param string|null $schema * @param string $table * @return string */ - public function compileIndexes($table) + public function compileIndexes($schema, $table) { return sprintf( 'select \'primary\' as name, group_concat(col) as columns, 1 as "unique", 1 as "primary" ' - .'from (select name as col from pragma_table_info(%s) where pk > 0 order by pk, cid) group by name ' + .'from (select name as col from pragma_table_xinfo(%s, %s) where pk > 0 order by pk, cid) group by name ' .'union select name, group_concat(col) as columns, "unique", origin = \'pk\' as "primary" ' - .'from (select il.*, ii.name as col from pragma_index_list(%s) il, pragma_index_info(il.name) ii order by il.seq, ii.seqno) ' + .'from (select il.*, ii.name as col from pragma_index_list(%s, %s) il, pragma_index_info(il.name, %s) ii order by il.seq, ii.seqno) ' .'group by name, "unique", "primary"', - $table = $this->quoteString(str_replace('.', '__', $table)), - $table + $table = $this->quoteString($table), + $schema = $this->quoteString($schema ?? 'main'), + $table, + $schema, + $schema ); } /** * Compile the query to determine the foreign keys. * + * @param string|null $schema * @param string $table * @return string */ - public function compileForeignKeys($table) + public function compileForeignKeys($schema, $table) { return sprintf( - 'select group_concat("from") as columns, "table" as foreign_table, ' + 'select group_concat("from") as columns, %s as foreign_schema, "table" as foreign_table, ' .'group_concat("to") as foreign_columns, on_update, on_delete ' - .'from (select * from pragma_foreign_key_list(%s) order by id desc, seq) ' + .'from (select * from pragma_foreign_key_list(%s, %s) order by id desc, seq) ' .'group by id, "table", on_update, on_delete', - $this->quoteString(str_replace('.', '__', $table)) + $schema = $this->quoteString($schema ?? 'main'), + $this->quoteString($table), + $schema ); } @@ -292,7 +354,8 @@ public function compileAlter(Blueprint $blueprint, Fluent $command, Connection $ ->map(fn ($index) => $this->{'compile'.ucfirst($index->name)}($blueprint, $index)) ->all(); - $tempTable = $this->wrap('__temp__'.$blueprint->getPrefix().$blueprint->getTable()); + [, $tableName] = $connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); + $tempTable = $this->wrapTable($blueprint, '__temp__'.$connection->getTablePrefix()); $table = $this->wrapTable($blueprint); $columnNames = implode(', ', $columnNames); @@ -308,7 +371,7 @@ public function compileAlter(Blueprint $blueprint, Fluent $command, Connection $ ), sprintf('insert into %s (%s) select %s from %s', $tempTable, $columnNames, $columnNames, $table), sprintf('drop table %s', $table), - sprintf('alter table %s rename to %s', $tempTable, $table), + sprintf('alter table %s rename to %s', $tempTable, $this->wrapTable($tableName)), ], $indexes, [$foreignKeyConstraintsEnabled ? $this->compileEnableForeignKeyConstraints() : null])); } @@ -348,9 +411,12 @@ public function compilePrimary(Blueprint $blueprint, Fluent $command) */ public function compileUnique(Blueprint $blueprint, Fluent $command) { - return sprintf('create unique index %s on %s (%s)', + [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); + + return sprintf('create unique index %s%s on %s (%s)', + $schema ? $this->wrapValue($schema).'.' : '', $this->wrap($command->index), - $this->wrapTable($blueprint), + $this->wrapTable($table), $this->columnize($command->columns) ); } @@ -364,9 +430,12 @@ public function compileUnique(Blueprint $blueprint, Fluent $command) */ public function compileIndex(Blueprint $blueprint, Fluent $command) { - return sprintf('create index %s on %s (%s)', + [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); + + return sprintf('create index %s%s on %s (%s)', + $schema ? $this->wrapValue($schema).'.' : '', $this->wrap($command->index), - $this->wrapTable($blueprint), + $this->wrapTable($table), $this->columnize($command->columns) ); } @@ -424,21 +493,27 @@ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) /** * Compile the SQL needed to drop all tables. * + * @param string|null $schema * @return string */ - public function compileDropAllTables() + public function compileDropAllTables($schema = null) { - return "delete from sqlite_master where type in ('table', 'index', 'trigger')"; + return sprintf("delete from %s.sqlite_master where type in ('table', 'index', 'trigger')", + $this->wrapValue($schema ?? 'main') + ); } /** * Compile the SQL needed to drop all views. * + * @param string|null $schema * @return string */ - public function compileDropAllViews() + public function compileDropAllViews($schema = null) { - return "delete from sqlite_master where type in ('view')"; + return sprintf("delete from %s.sqlite_master where type in ('view')", + $this->wrapValue($schema ?? 'main') + ); } /** @@ -495,9 +570,7 @@ public function compileDropPrimary(Blueprint $blueprint, Fluent $command) */ public function compileDropUnique(Blueprint $blueprint, Fluent $command) { - $index = $this->wrap($command->index); - - return "drop index {$index}"; + return $this->compileDropIndex($blueprint, $command); } /** @@ -509,9 +582,12 @@ public function compileDropUnique(Blueprint $blueprint, Fluent $command) */ public function compileDropIndex(Blueprint $blueprint, Fluent $command) { - $index = $this->wrap($command->index); + [$schema] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); - return "drop index {$index}"; + return sprintf('drop index %s%s', + $schema ? $this->wrapValue($schema).'.' : '', + $this->wrap($command->index) + ); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 81258f2e1036..6333b23e6118 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -37,16 +37,6 @@ class SqlServerGrammar extends Grammar */ protected $fluentCommands = ['Default']; - /** - * Compile a query to determine the name of the default schema. - * - * @return string - */ - public function compileDefaultSchema() - { - return 'select schema_name()'; - } - /** * Compile a create database command. * @@ -76,6 +66,17 @@ public function compileDropDatabaseIfExists($name) ); } + /** + * Compile the query to determine the schemas. + * + * @return string + */ + public function compileSchemas() + { + return 'select name, iif(schema_id = schema_id(), 1, 0) as [default] from sys.schemas ' + ."where name not in ('information_schema', 'sys') and name not like 'db[_]%' order by name"; + } + /** * Compile the query to determine if the given table exists. * @@ -94,34 +95,56 @@ public function compileTableExists($schema, $table) /** * Compile the query to determine the tables. * + * @param string|string[]|null $schema * @return string */ - public function compileTables() + public function compileTables($schema) { return 'select t.name as name, schema_name(t.schema_id) as [schema], sum(u.total_pages) * 8 * 1024 as size ' .'from sys.tables as t ' .'join sys.partitions as p on p.object_id = t.object_id ' .'join sys.allocation_units as u on u.container_id = p.hobt_id ' - .'group by t.name, t.schema_id ' - .'order by t.name'; + ."where t.is_ms_shipped = 0 and t.name <> 'sysdiagrams'" + .$this->compileSchemaWhereClause($schema, 'schema_name(t.schema_id)') + .' group by t.name, t.schema_id ' + .'order by [schema], t.name'; } /** * Compile the query to determine the views. * + * @param string|string[]|null $schema * @return string */ - public function compileViews() + public function compileViews($schema) { return 'select name, schema_name(v.schema_id) as [schema], definition from sys.views as v ' .'inner join sys.sql_modules as m on v.object_id = m.object_id ' - .'order by name'; + .'where v.is_ms_shipped = 0' + .$this->compileSchemaWhereClause($schema, 'schema_name(v.schema_id)') + .' order by [schema], name'; + } + + /** + * Compile the query to compare the schema. + * + * @param string|string[]|null $schema + * @param string $column + * @return string + */ + protected function compileSchemaWhereClause($schema, $column) + { + return match (true) { + ! empty($schema) && is_array($schema) => " and $column in (".$this->quoteString($schema).')', + ! empty($schema) => " and $column = ".$this->quoteString($schema), + default => '', + }; } /** * Compile the query to determine the columns. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -151,7 +174,7 @@ public function compileColumns($schema, $table) /** * Compile the query to determine the indexes. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -175,7 +198,7 @@ public function compileIndexes($schema, $table) /** * Compile the query to determine the foreign keys. * - * @param string $schema + * @param string|null $schema * @param string $table * @return string */ @@ -212,9 +235,10 @@ public function compileForeignKeys($schema, $table) */ public function compileCreate(Blueprint $blueprint, Fluent $command) { - $columns = implode(', ', $this->getColumns($blueprint)); - - return 'create table '.$this->wrapTable($blueprint)." ($columns)"; + return sprintf('create table %s (%s)', + $this->wrapTable($blueprint, $blueprint->temporary ? '#'.$this->connection->getTablePrefix() : null), + implode(', ', $this->getColumns($blueprint)) + ); } /** @@ -1040,21 +1064,6 @@ protected function modifyPersisted(Blueprint $blueprint, Fluent $column) } } - /** - * Wrap a table in keyword identifiers. - * - * @param \Illuminate\Database\Schema\Blueprint|\Illuminate\Contracts\Database\Query\Expression|string $table - * @return string - */ - public function wrapTable($table) - { - if ($table instanceof Blueprint && $table->temporary) { - $this->setTablePrefix('#'); - } - - return parent::wrapTable($table); - } - /** * Quote the given string literal. * diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index 842130503595..b55f324b69e1 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -30,102 +30,6 @@ public function dropDatabaseIfExists($name) ); } - /** - * Determine if the given table exists. - * - * @param string $table - * @return bool - */ - public function hasTable($table) - { - $table = $this->connection->getTablePrefix().$table; - - $database = $this->connection->getDatabaseName(); - - return (bool) $this->connection->scalar( - $this->grammar->compileTableExists($database, $table) - ); - } - - /** - * Get the tables for the database. - * - * @return array - */ - public function getTables() - { - return $this->connection->getPostProcessor()->processTables( - $this->connection->selectFromWriteConnection( - $this->grammar->compileTables($this->connection->getDatabaseName()) - ) - ); - } - - /** - * Get the views for the database. - * - * @return array - */ - public function getViews() - { - return $this->connection->getPostProcessor()->processViews( - $this->connection->selectFromWriteConnection( - $this->grammar->compileViews($this->connection->getDatabaseName()) - ) - ); - } - - /** - * Get the columns for a given table. - * - * @param string $table - * @return array - */ - public function getColumns($table) - { - $table = $this->connection->getTablePrefix().$table; - - $results = $this->connection->selectFromWriteConnection( - $this->grammar->compileColumns($this->connection->getDatabaseName(), $table) - ); - - return $this->connection->getPostProcessor()->processColumns($results); - } - - /** - * Get the indexes for a given table. - * - * @param string $table - * @return array - */ - public function getIndexes($table) - { - $table = $this->connection->getTablePrefix().$table; - - return $this->connection->getPostProcessor()->processIndexes( - $this->connection->selectFromWriteConnection( - $this->grammar->compileIndexes($this->connection->getDatabaseName(), $table) - ) - ); - } - - /** - * Get the foreign keys for a given table. - * - * @param string $table - * @return array - */ - public function getForeignKeys($table) - { - $table = $this->connection->getTablePrefix().$table; - - return $this->connection->getPostProcessor()->processForeignKeys( - $this->connection->selectFromWriteConnection( - $this->grammar->compileForeignKeys($this->connection->getDatabaseName(), $table) - ) - ); - } - /** * Drop all tables from the database. * @@ -133,7 +37,7 @@ public function getForeignKeys($table) */ public function dropAllTables() { - $tables = array_column($this->getTables(), 'name'); + $tables = $this->getTableListing($this->getCurrentSchemaListing()); if (empty($tables)) { return; @@ -141,11 +45,13 @@ public function dropAllTables() $this->disableForeignKeyConstraints(); - $this->connection->statement( - $this->grammar->compileDropAllTables($tables) - ); - - $this->enableForeignKeyConstraints(); + try { + $this->connection->statement( + $this->grammar->compileDropAllTables($tables) + ); + } finally { + $this->enableForeignKeyConstraints(); + } } /** @@ -155,7 +61,7 @@ public function dropAllTables() */ public function dropAllViews() { - $views = array_column($this->getViews(), 'name'); + $views = array_column($this->getViews($this->getCurrentSchemaListing()), 'schema_qualified_name'); if (empty($views)) { return; @@ -165,4 +71,14 @@ public function dropAllViews() $this->grammar->compileDropAllViews($views) ); } + + /** + * Get the names of current schemas for the connection. + * + * @return string[]|null + */ + public function getCurrentSchemaListing() + { + return [$this->connection->getDatabaseName()]; + } } diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index b39486c0e5a6..f8b88d5b003a 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -3,13 +3,10 @@ namespace Illuminate\Database\Schema; use Illuminate\Database\Concerns\ParsesSearchPath; -use InvalidArgumentException; class PostgresBuilder extends Builder { - use ParsesSearchPath { - parseSearchPath as baseParseSearchPath; - } + use ParsesSearchPath; /** * Create a database in the schema. @@ -37,57 +34,6 @@ public function dropDatabaseIfExists($name) ); } - /** - * Determine if the given table exists. - * - * @param string $table - * @return bool - */ - public function hasTable($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - return (bool) $this->connection->scalar( - $this->grammar->compileTableExists($schema, $table) - ); - } - - /** - * Determine if the given view exists. - * - * @param string $view - * @return bool - */ - public function hasView($view) - { - [$schema, $view] = $this->parseSchemaAndTable($view); - - $view = $this->connection->getTablePrefix().$view; - - foreach ($this->getViews() as $value) { - if (strtolower($view) === strtolower($value['name']) - && strtolower($schema) === strtolower($value['schema'])) { - return true; - } - } - - return false; - } - - /** - * Get the user-defined types that belong to the database. - * - * @return array - */ - public function getTypes() - { - return $this->connection->getPostProcessor()->processTypes( - $this->connection->selectFromWriteConnection($this->grammar->compileTypes()) - ); - } - /** * Drop all tables from the database. * @@ -99,14 +45,9 @@ public function dropAllTables() $excludedTables = $this->connection->getConfig('dont_drop') ?? ['spatial_ref_sys']; - $schemas = $this->getSchemas(); - - foreach ($this->getTables() as $table) { - $qualifiedName = $table['schema'].'.'.$table['name']; - - if (in_array($table['schema'], $schemas) && - empty(array_intersect([$table['name'], $qualifiedName], $excludedTables))) { - $tables[] = $qualifiedName; + foreach ($this->getTables($this->getCurrentSchemaListing()) as $table) { + if (empty(array_intersect([$table['name'], $table['schema_qualified_name']], $excludedTables))) { + $tables[] = $table['schema_qualified_name']; } } @@ -126,15 +67,7 @@ public function dropAllTables() */ public function dropAllViews() { - $views = []; - - $schemas = $this->getSchemas(); - - foreach ($this->getViews() as $view) { - if (in_array($view['schema'], $schemas)) { - $views[] = $view['schema'].'.'.$view['name']; - } - } + $views = array_column($this->getViews($this->getCurrentSchemaListing()), 'schema_qualified_name'); if (empty($views)) { return; @@ -155,14 +88,12 @@ public function dropAllTypes() $types = []; $domains = []; - $schemas = $this->getSchemas(); - - foreach ($this->getTypes() as $type) { - if (! $type['implicit'] && in_array($type['schema'], $schemas)) { + foreach ($this->getTypes($this->getCurrentSchemaListing()) as $type) { + if (! $type['implicit']) { if ($type['type'] === 'domain') { - $domains[] = $type['schema'].'.'.$type['name']; + $domains[] = $type['schema_qualified_name']; } else { - $types[] = $type['schema'].'.'.$type['name']; + $types[] = $type['schema_qualified_name']; } } } @@ -177,111 +108,19 @@ public function dropAllTypes() } /** - * Get the columns for a given table. - * - * @param string $table - * @return array - */ - public function getColumns($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - $results = $this->connection->selectFromWriteConnection( - $this->grammar->compileColumns($schema, $table) - ); - - return $this->connection->getPostProcessor()->processColumns($results); - } - - /** - * Get the indexes for a given table. - * - * @param string $table - * @return array - */ - public function getIndexes($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - return $this->connection->getPostProcessor()->processIndexes( - $this->connection->selectFromWriteConnection($this->grammar->compileIndexes($schema, $table)) - ); - } - - /** - * Get the foreign keys for a given table. - * - * @param string $table - * @return array - */ - public function getForeignKeys($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - return $this->connection->getPostProcessor()->processForeignKeys( - $this->connection->selectFromWriteConnection($this->grammar->compileForeignKeys($schema, $table)) - ); - } - - /** - * Get the schemas for the connection. + * Get the current schemas for the connection. * - * @return array + * @return string[] */ - public function getSchemas() + public function getCurrentSchemaListing() { - return $this->parseSearchPath( - $this->connection->getConfig('search_path') ?: $this->connection->getConfig('schema') ?: 'public' + return array_map( + fn ($schema) => $schema === '$user' ? $this->connection->getConfig('username') : $schema, + $this->parseSearchPath( + $this->connection->getConfig('search_path') + ?: $this->connection->getConfig('schema') + ?: 'public' + ) ); } - - /** - * Parse the database object reference and extract the schema and table. - * - * @param string $reference - * @return array - */ - public function parseSchemaAndTable($reference) - { - $parts = explode('.', $reference); - - if (count($parts) > 2) { - $database = $parts[0]; - - throw new InvalidArgumentException("Using three-part reference is not supported, you may use `Schema::connection('$database')` instead."); - } - - // 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 = $this->getSchemas()[0]; - - if (count($parts) === 2) { - $schema = $parts[0]; - array_shift($parts); - } - - return [$schema, $parts[0]]; - } - - /** - * Parse the "search_path" configuration value into an array. - * - * @param string|array|null $searchPath - * @return array - */ - protected function parseSearchPath($searchPath) - { - return array_map(function ($schema) { - return $schema === '$user' - ? $this->connection->getConfig('username') - : $schema; - }, $this->baseParseSearchPath($searchPath)); - } } diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index a96894128b1d..25da812e61c5 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -59,7 +59,7 @@ public function load($path) */ protected function getMigrationTable(): string { - [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($this->migrationTable); + [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($this->migrationTable, withDefaultSchema: true); return $schema.'.'.$this->connection->getTablePrefix().$table; } diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 25111ebd3905..af49bae8126e 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Schema; use Illuminate\Database\QueryException; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\File; class SQLiteBuilder extends Builder @@ -32,39 +33,59 @@ public function dropDatabaseIfExists($name) } /** - * Determine if the given table exists. + * Get the tables that belong to the connection. * - * @param string $table - * @return bool + * @param string|string[]|null $schema + * @return array */ - public function hasTable($table) + public function getTables($schema = null) { - $table = $this->connection->getTablePrefix().$table; + try { + $withSize = $this->connection->scalar($this->grammar->compileDbstatExists()); + } catch (QueryException) { + $withSize = false; + } + + if (version_compare($this->connection->getServerVersion(), '3.37.0', '<')) { + $schema ??= array_column($this->getSchemas(), 'name'); + + $tables = []; - return (bool) $this->connection->scalar( - $this->grammar->compileTableExists($table) + foreach (Arr::wrap($schema) as $name) { + $tables = array_merge($tables, $this->connection->selectFromWriteConnection( + $this->grammar->compileLegacyTables($name, $withSize) + )); + } + + return $this->connection->getPostProcessor()->processTables($tables); + } + + return $this->connection->getPostProcessor()->processTables( + $this->connection->selectFromWriteConnection( + $this->grammar->compileTables($schema, $withSize) + ) ); } /** - * Get the tables for the database. + * Get the views that belong to the connection. * - * @param bool $withSize + * @param string|string[]|null $schema * @return array */ - public function getTables($withSize = true) + public function getViews($schema = null) { - if ($withSize) { - try { - $withSize = $this->connection->scalar($this->grammar->compileDbstatExists()); - } catch (QueryException $e) { - $withSize = false; - } + $schema ??= array_column($this->getSchemas(), 'name'); + + $views = []; + + foreach (Arr::wrap($schema) as $name) { + $views = array_merge($views, $this->connection->selectFromWriteConnection( + $this->grammar->compileViews($name) + )); } - return $this->connection->getPostProcessor()->processTables( - $this->connection->selectFromWriteConnection($this->grammar->compileTables($withSize)) - ); + return $this->connection->getPostProcessor()->processViews($views); } /** @@ -75,11 +96,13 @@ public function getTables($withSize = true) */ public function getColumns($table) { + [$schema, $table] = $this->parseSchemaAndTable($table); + $table = $this->connection->getTablePrefix().$table; return $this->connection->getPostProcessor()->processColumns( - $this->connection->selectFromWriteConnection($this->grammar->compileColumns($table)), - $this->connection->scalar($this->grammar->compileSqlCreateStatement($table)) + $this->connection->selectFromWriteConnection($this->grammar->compileColumns($schema, $table)), + $this->connection->scalar($this->grammar->compileSqlCreateStatement($schema, $table)) ); } @@ -101,7 +124,9 @@ public function dropAllTables() $this->connection->select($this->grammar->compileEnableWriteableSchema()); - $this->connection->select($this->grammar->compileDropAllTables()); + foreach ($this->getCurrentSchemaListing() as $schema) { + $this->connection->select($this->grammar->compileDropAllTables($schema)); + } $this->connection->select($this->grammar->compileDisableWriteableSchema()); @@ -117,7 +142,9 @@ public function dropAllViews() { $this->connection->select($this->grammar->compileEnableWriteableSchema()); - $this->connection->select($this->grammar->compileDropAllViews()); + foreach ($this->getCurrentSchemaListing() as $schema) { + $this->connection->select($this->grammar->compileDropAllViews($schema)); + } $this->connection->select($this->grammar->compileDisableWriteableSchema()); @@ -172,4 +199,14 @@ public function refreshDatabaseFile() { file_put_contents($this->connection->getDatabaseName(), ''); } + + /** + * Get the names of current schemas for the connection. + * + * @return string[]|null + */ + public function getCurrentSchemaListing() + { + return ['main']; + } } diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index 9b59ccc0ebd3..1cbc5afa7692 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -2,7 +2,7 @@ namespace Illuminate\Database\Schema; -use InvalidArgumentException; +use Illuminate\Support\Arr; class SqlServerBuilder extends Builder { @@ -32,46 +32,6 @@ public function dropDatabaseIfExists($name) ); } - /** - * Determine if the given table exists. - * - * @param string $table - * @return bool - */ - public function hasTable($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - return (bool) $this->connection->scalar( - $this->grammar->compileTableExists($schema, $table) - ); - } - - /** - * Determine if the given view exists. - * - * @param string $view - * @return bool - */ - public function hasView($view) - { - [$schema, $view] = $this->parseSchemaAndTable($view); - - $schema ??= $this->getDefaultSchema(); - $view = $this->connection->getTablePrefix().$view; - - foreach ($this->getViews() as $value) { - if (strtolower($view) === strtolower($value['name']) - && strtolower($schema) === strtolower($value['schema'])) { - return true; - } - } - - return false; - } - /** * Drop all tables from the database. * @@ -95,84 +55,12 @@ public function dropAllViews() } /** - * Get the columns for a given table. + * Get the default schema name for the connection. * - * @param string $table - * @return array + * @return string|null */ - public function getColumns($table) + public function getCurrentSchemaName() { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - $results = $this->connection->selectFromWriteConnection( - $this->grammar->compileColumns($schema, $table) - ); - - return $this->connection->getPostProcessor()->processColumns($results); - } - - /** - * Get the indexes for a given table. - * - * @param string $table - * @return array - */ - public function getIndexes($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - return $this->connection->getPostProcessor()->processIndexes( - $this->connection->selectFromWriteConnection($this->grammar->compileIndexes($schema, $table)) - ); - } - - /** - * Get the foreign keys for a given table. - * - * @param string $table - * @return array - */ - public function getForeignKeys($table) - { - [$schema, $table] = $this->parseSchemaAndTable($table); - - $table = $this->connection->getTablePrefix().$table; - - return $this->connection->getPostProcessor()->processForeignKeys( - $this->connection->selectFromWriteConnection($this->grammar->compileForeignKeys($schema, $table)) - ); - } - - /** - * Get the default schema for the connection. - * - * @return string - */ - protected function getDefaultSchema() - { - return $this->connection->scalar($this->grammar->compileDefaultSchema()); - } - - /** - * Parse the database object reference and extract the schema and table. - * - * @param string $reference - * @return array - */ - protected function parseSchemaAndTable($reference) - { - $parts = array_pad(explode('.', $reference, 2), -2, null); - - if (str_contains($parts[1], '.')) { - $database = $parts[0]; - - throw new InvalidArgumentException("Using three-part reference is not supported, you may use `Schema::connection('$database')` instead."); - } - - return $parts; + return Arr::first($this->getSchemas(), fn ($schema) => $schema['default'])['name']; } } diff --git a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php index 0b7f96abdd21..b72c3150c762 100644 --- a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php +++ b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php @@ -4,7 +4,6 @@ use Illuminate\Contracts\Console\Kernel; use Illuminate\Database\ConnectionInterface; -use Illuminate\Database\Schema\PostgresBuilder; use Illuminate\Foundation\Testing\Traits\CanConfigureMigrationCommands; use Illuminate\Support\Collection; @@ -99,9 +98,7 @@ function (Collection $tables) use ($connection, $name) { ) ->each(function (array $table) use ($connection) { $connection->withoutTablePrefix(function ($connection) use ($table) { - $table = $connection->table( - $table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name'] - ); + $table = $connection->table($table['schema_qualified_name']); if ($table->exists()) { $table->truncate(); @@ -123,12 +120,7 @@ protected function getAllTablesForConnection(ConnectionInterface $connection, ?s $schema = $connection->getSchemaBuilder(); - return static::$allTables[$name] = (new Collection($schema->getTables()))->when( - $schema instanceof PostgresBuilder ? $schema->getSchemas() : null, - fn (Collection $tables, array $schemas) => $tables->filter( - fn (array $table) => in_array($table['schema'], $schemas) - ) - )->all(); + return static::$allTables[$name] = (new Collection($schema->getTables($schema->getCurrentSchemaListing())))->all(); } /** @@ -137,7 +129,7 @@ protected function getAllTablesForConnection(ConnectionInterface $connection, ?s protected function tableExistsIn(array $table, array $tables): bool { return $table['schema'] - ? ! empty(array_intersect([$table['name'], $table['schema'].'.'.$table['name']], $tables)) + ? ! empty(array_intersect([$table['name'], $table['schema_qualified_name']], $tables)) : in_array($table['name'], $tables); } diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index c2d4249727d2..3e645ac530f5 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -105,7 +105,7 @@ * @method static string getTablePrefix() * @method static \Illuminate\Database\Connection setTablePrefix(string $prefix) * @method static \Illuminate\Database\Grammar withTablePrefix(\Illuminate\Database\Grammar $grammar) - * @method static void withoutTablePrefix(\Closure $callback) + * @method static mixed withoutTablePrefix(\Closure $callback) * @method static string getServerVersion() * @method static void resolverFor(string $driver, \Closure $callback) * @method static \Closure|null getResolver(string $driver) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index fccccaa2fbd1..a388c6b415dc 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -10,12 +10,13 @@ * @method static void morphUsingUlids() * @method static bool createDatabase(string $name) * @method static bool dropDatabaseIfExists(string $name) + * @method static array getSchemas() * @method static bool hasTable(string $table) * @method static bool hasView(string $view) - * @method static array getTables() - * @method static array getTableListing() - * @method static array getViews() - * @method static array getTypes() + * @method static array getTables(string|string[]|null $schema = null) + * @method static array getTableListing(string|string[]|null $schema = null, bool $schemaQualified = true) + * @method static array getViews(string|string[]|null $schema = null) + * @method static array getTypes(string|string[]|null $schema = null) * @method static bool hasColumn(string $table, string $column) * @method static bool hasColumns(string $table, array $columns) * @method static void whenTableHasColumn(string $table, string $column, \Closure $callback) @@ -42,6 +43,9 @@ * @method static \Illuminate\Database\Connection getConnection() * @method static \Illuminate\Database\Schema\Builder setConnection(\Illuminate\Database\Connection $connection) * @method static void blueprintResolver(\Closure $resolver) + * @method static string[]|null getCurrentSchemaListing() + * @method static string|null getCurrentSchemaName() + * @method static array parseSchemaAndTable(string $reference, string|bool|null $withDefaultSchema = null) * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) * @method static bool hasMacro(string $name) diff --git a/tests/Database/DatabaseMariaDbSchemaBuilderTest.php b/tests/Database/DatabaseMariaDbSchemaBuilderTest.php index d8d7a64c17cc..eed08f0d5d48 100755 --- a/tests/Database/DatabaseMariaDbSchemaBuilderTest.php +++ b/tests/Database/DatabaseMariaDbSchemaBuilderTest.php @@ -38,7 +38,7 @@ public function testGetColumnListing() $connection->shouldReceive('getDatabaseName')->andReturn('db'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileColumns')->with('db', 'prefix_table')->once()->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->with(null, 'prefix_table')->once()->andReturn('sql'); $processor->shouldReceive('processColumns')->once()->andReturn([['name' => 'column']]); $builder = new MariaDbBuilder($connection); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); diff --git a/tests/Database/DatabaseMySQLSchemaBuilderTest.php b/tests/Database/DatabaseMySQLSchemaBuilderTest.php index c5fa3ea273f2..78f3900317a2 100755 --- a/tests/Database/DatabaseMySQLSchemaBuilderTest.php +++ b/tests/Database/DatabaseMySQLSchemaBuilderTest.php @@ -38,7 +38,7 @@ public function testGetColumnListing() $connection->shouldReceive('getDatabaseName')->andReturn('db'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileColumns')->with('db', 'prefix_table')->once()->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->with(null, 'prefix_table')->once()->andReturn('sql'); $processor->shouldReceive('processColumns')->once()->andReturn([['name' => 'column']]); $builder = new MySqlBuilder($connection); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index c6f79c130704..ea6f77da62e3 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -142,7 +142,7 @@ public function testGetColumnListingWhenSchemaUnqualifiedAndSearchPathMissing() $connection->shouldReceive('getConfig')->with('schema')->andReturn(null); $grammar = m::mock(PostgresGrammar::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $grammar->shouldReceive('compileColumns')->with('public', 'foo')->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->with(null, 'foo')->andReturn('sql'); $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'some_column']]); $connection->shouldReceive('getTablePrefix'); $processor = m::mock(PostgresProcessor::class); @@ -159,7 +159,7 @@ public function testGetColumnListingWhenSchemaUnqualifiedAndSearchPathFilled() $connection->shouldReceive('getConfig')->with('search_path')->andReturn('myapp,public'); $grammar = m::mock(PostgresGrammar::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $grammar->shouldReceive('compileColumns')->with('myapp', 'foo')->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->with(null, 'foo')->andReturn('sql'); $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'some_column']]); $connection->shouldReceive('getTablePrefix'); $processor = m::mock(PostgresProcessor::class); @@ -177,7 +177,7 @@ public function testGetColumnListingWhenSchemaUnqualifiedAndSearchPathIsUserVari $connection->shouldReceive('getConfig')->with('search_path')->andReturn('$user'); $grammar = m::mock(PostgresGrammar::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $grammar->shouldReceive('compileColumns')->with('foouser', 'foo')->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->with(null, 'foo')->andReturn('sql'); $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'some_column']]); $connection->shouldReceive('getTablePrefix'); $processor = m::mock(PostgresProcessor::class); @@ -228,8 +228,8 @@ public function testDropAllTablesWhenSearchPathIsString() $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); $grammar->shouldReceive('compileTables')->andReturn('sql'); - $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'public']]); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'public']]); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'public', 'schema_qualified_name' => 'public.users']]); + $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'public', 'schema_qualified_name' => 'public.users']]); $grammar->shouldReceive('compileDropAllTables')->with(['public.users'])->andReturn('drop table "public"."users" cascade'); $connection->shouldReceive('statement')->with('drop table "public"."users" cascade'); $builder = $this->getBuilder($connection); @@ -247,9 +247,9 @@ public function testDropAllTablesWhenSearchPathIsStringOfMany() $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'foouser', 'schema_qualified_name' => 'foouser.users']]); $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'foouser', 'schema_qualified_name' => 'foouser.users']]); $grammar->shouldReceive('compileDropAllTables')->with(['foouser.users'])->andReturn('drop table "foouser"."users" cascade'); $connection->shouldReceive('statement')->with('drop table "foouser"."users" cascade'); $builder = $this->getBuilder($connection); @@ -272,9 +272,9 @@ public function testDropAllTablesWhenSearchPathIsArrayOfMany() $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'foouser', 'schema_qualified_name' => 'foouser.users']]); $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'foouser', 'schema_qualified_name' => 'foouser.users']]); $grammar->shouldReceive('compileDropAllTables')->with(['foouser.users'])->andReturn('drop table "foouser"."users" cascade'); $connection->shouldReceive('statement')->with('drop table "foouser"."users" cascade'); $builder = $this->getBuilder($connection); diff --git a/tests/Database/DatabasePostgresSchemaBuilderTest.php b/tests/Database/DatabasePostgresSchemaBuilderTest.php index c38c7d183614..0b1124463981 100755 --- a/tests/Database/DatabasePostgresSchemaBuilderTest.php +++ b/tests/Database/DatabasePostgresSchemaBuilderTest.php @@ -21,8 +21,6 @@ public function testHasTable() $connection = m::mock(Connection::class); $grammar = m::mock(PostgresGrammar::class); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getConfig')->with('schema')->andReturn('schema'); - $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); $builder = new PostgresBuilder($connection); $grammar->shouldReceive('compileTableExists')->twice()->andReturn('sql'); $connection->shouldReceive('getTablePrefix')->twice()->andReturn('prefix_'); @@ -39,10 +37,7 @@ public function testGetColumnListing() $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $connection->shouldReceive('getConfig')->with('database')->andReturn('db'); - $connection->shouldReceive('getConfig')->with('schema')->andReturn('schema'); - $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); - $grammar->shouldReceive('compileColumns')->with('public', 'prefix_table')->once()->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->with(null, 'prefix_table')->once()->andReturn('sql'); $processor->shouldReceive('processColumns')->once()->andReturn([['name' => 'column']]); $builder = new PostgresBuilder($connection); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 27ac6b24f795..0a3764d4837b 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -4255,10 +4255,12 @@ public function testDeleteWithJoinMethod() public function testTruncateMethod() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('statement')->once()->with('truncate table "users"', []); + $connection = $builder->getConnection(); + $connection->shouldReceive('statement')->once()->with('truncate table "users"', []); + $connection->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn([null, 'users']); $builder->from('users')->truncate(); - $sqlite = new SQLiteGrammar; + $sqlite = (new SQLiteGrammar)->setConnection($connection); $builder = $this->getBuilder(); $builder->from('users'); $this->assertEquals([ @@ -4271,10 +4273,12 @@ public function testTruncateMethodWithPrefix() { $builder = $this->getBuilder(); $builder->getGrammar()->setTablePrefix('prefix_'); - $builder->getConnection()->shouldReceive('statement')->once()->with('truncate table "prefix_users"', []); + $connection = $builder->getConnection(); + $connection->shouldReceive('statement')->once()->with('truncate table "prefix_users"', []); + $connection->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn([null, 'users']); $builder->from('users')->truncate(); - $sqlite = new SQLiteGrammar; + $sqlite = (new SQLiteGrammar)->setConnection($connection); $sqlite->setTablePrefix('prefix_'); $builder = $this->getBuilder(); $builder->from('users'); @@ -4284,6 +4288,25 @@ public function testTruncateMethodWithPrefix() ], $sqlite->compileTruncate($builder)); } + public function testTruncateMethodWithPrefixAndSchema() + { + $builder = $this->getBuilder(); + $builder->getGrammar()->setTablePrefix('prefix_'); + $connection = $builder->getConnection(); + $connection->shouldReceive('statement')->once()->with('truncate table "my_schema"."prefix_users"', []); + $connection->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn(['my_schema', 'users']); + $builder->from('my_schema.users')->truncate(); + + $sqlite = (new SQLiteGrammar)->setConnection($connection); + $sqlite->setTablePrefix('prefix_'); + $builder = $this->getBuilder(); + $builder->from('my_schema.users'); + $this->assertEquals([ + 'delete from "my_schema".sqlite_sequence where name = ?' => ['prefix_users'], + 'delete from "my_schema"."prefix_users"' => [], + ], $sqlite->compileTruncate($builder)); + } + public function testPreserveAddsClosureToArray() { $builder = $this->getBuilder(); diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index 245fd70467ef..0b9c5dbbc348 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -98,6 +98,16 @@ public function testDropIndex() $this->assertSame('drop index "foo"', $statements[0]); } + public function testDropIndexWithSchema() + { + $blueprint = new Blueprint($this->getConnection(), 'my_schema.users'); + $blueprint->dropIndex('foo'); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('drop index "my_schema"."foo"', $statements[0]); + } + public function testDropColumn() { $db = new Manager; @@ -225,6 +235,22 @@ public function testAddingIndex() $this->assertSame('create index "baz" on "users" ("foo", "bar")', $statements[0]); } + public function testAddingUniqueKeyWithSchema() + { + $blueprint = new Blueprint($this->getConnection(), 'foo.users'); + $blueprint->unique('foo', 'bar'); + + $this->assertSame(['create unique index "foo"."bar" on "users" ("foo")'], $blueprint->toSql()); + } + + public function testAddingIndexWithSchema() + { + $blueprint = new Blueprint($this->getConnection(), 'foo.users'); + $blueprint->index(['foo', 'bar'], 'baz'); + + $this->assertSame(['create index "foo"."baz" on "users" ("foo", "bar")'], $blueprint->toSql()); + } + public function testAddingSpatialIndex() { $this->expectException(RuntimeException::class); @@ -992,28 +1018,89 @@ public function testDroppingColumnsWorks() $this->assertEquals(['alter table "users" drop column "name"'], $blueprint->toSql()); } + public function testRenamingAndChangingColumnsWork() + { + $builder = mock(SQLiteBuilder::class) + ->makePartial() + ->shouldReceive('getColumns')->andReturn([ + ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar', 'collation' => null, 'nullable' => false, 'default' => null, 'auto_increment' => false, 'comment' => null, 'generation' => null], + ['name' => 'age', 'type_name' => 'varchar', 'type' => 'varchar', 'collation' => null, 'nullable' => false, 'default' => null, 'auto_increment' => false, 'comment' => null, 'generation' => null], + ]) + ->shouldReceive('getIndexes')->andReturn([]) + ->shouldReceive('getForeignKeys')->andReturn([]) + ->getMock(); + + $connection = $this->getConnection(builder: $builder); + $connection->shouldReceive('scalar')->with('pragma foreign_keys')->andReturn(false); + + $blueprint = new Blueprint($connection, 'users'); + $blueprint->renameColumn('name', 'first_name'); + $blueprint->integer('age')->change(); + + $this->assertEquals([ + 'alter table "users" rename column "name" to "first_name"', + 'create table "__temp__users" ("first_name" varchar not null, "age" integer not null)', + 'insert into "__temp__users" ("first_name", "age") select "first_name", "age" from "users"', + 'drop table "users"', + 'alter table "__temp__users" rename to "users"', + ], $blueprint->toSql()); + } + + public function testRenamingAndChangingColumnsWorkWithSchema() + { + $builder = mock(SQLiteBuilder::class) + ->makePartial() + ->shouldReceive('getColumns')->andReturn([ + ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar', 'collation' => null, 'nullable' => false, 'default' => null, 'auto_increment' => false, 'comment' => null, 'generation' => null], + ['name' => 'age', 'type_name' => 'varchar', 'type' => 'varchar', 'collation' => null, 'nullable' => false, 'default' => null, 'auto_increment' => false, 'comment' => null, 'generation' => null], + ]) + ->shouldReceive('getIndexes')->andReturn([]) + ->shouldReceive('getForeignKeys')->andReturn([]) + ->getMock(); + + $connection = $this->getConnection(builder: $builder); + $connection->shouldReceive('scalar')->with('pragma foreign_keys')->andReturn(false); + + $blueprint = new Blueprint($connection, 'my_schema.users'); + $blueprint->renameColumn('name', 'first_name'); + $blueprint->integer('age')->change(); + + $this->assertEquals([ + 'alter table "my_schema"."users" rename column "name" to "first_name"', + 'create table "my_schema"."__temp__users" ("first_name" varchar not null, "age" integer not null)', + 'insert into "my_schema"."__temp__users" ("first_name", "age") select "first_name", "age" from "my_schema"."users"', + 'drop table "my_schema"."users"', + 'alter table "my_schema"."__temp__users" rename to "users"', + ], $blueprint->toSql()); + } + protected function getConnection( ?SQLiteGrammar $grammar = null, ?SQLiteBuilder $builder = null, + $prefix = '' ) { - $grammar ??= $this->getGrammar(); + $connection = m::mock(Connection::class); + $grammar ??= $this->getGrammar($connection); $builder ??= $this->getBuilder(); - return m::mock(Connection::class) + return $connection + ->shouldReceive('getTablePrefix')->andReturn($prefix) + ->shouldReceive('getConfig')->andReturn(null) ->shouldReceive('getSchemaGrammar')->andReturn($grammar) ->shouldReceive('getSchemaBuilder')->andReturn($builder) ->shouldReceive('getServerVersion')->andReturn('3.35') ->getMock(); } - public function getGrammar() + public function getGrammar(?Connection $connection = null) { - return new SQLiteGrammar(); + return (new SQLiteGrammar())->setConnection($connection ?? $this->getConnection()); } public function getBuilder() { return mock(SQLiteBuilder::class) + ->makePartial() ->shouldReceive('getColumns')->andReturn([]) ->shouldReceive('getIndexes')->andReturn([]) ->shouldReceive('getForeignKeys')->andReturn([]) diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index 55e64b7d77a6..d069d530dbce 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -236,6 +236,28 @@ public function testDropColumn() $this->assertStringContainsString('alter table "users" drop column "foo"', $getSql(new SqlServerGrammar)[0]); } + public function testNativeColumnModifyingOnMySql() + { + $blueprint = $this->getBlueprint(new MySqlGrammar, 'users', function ($table) { + $table->double('amount')->nullable()->invisible()->after('name')->change(); + $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->useCurrentOnUpdate()->change(); + $table->enum('difficulty', ['easy', 'hard'])->default('easy')->charset('utf8mb4')->collation('unicode')->change(); + $table->geometry('positions', 'multipolygon', 1234)->storedAs('expression')->change(); + $table->string('old_name', 50)->renameTo('new_name')->change(); + $table->bigIncrements('id')->first()->from(10)->comment('my comment')->change(); + }); + + $this->assertEquals([ + 'alter table `users` modify `amount` double null invisible after `name`', + 'alter table `users` modify `added_at` timestamp(4) not null default CURRENT_TIMESTAMP(4) on update CURRENT_TIMESTAMP(4)', + "alter table `users` modify `difficulty` enum('easy', 'hard') character set utf8mb4 collate 'unicode' not null default 'easy'", + 'alter table `users` modify `positions` multipolygon srid 1234 as (expression) stored', + 'alter table `users` change `old_name` `new_name` varchar(50) not null', + "alter table `users` modify `id` bigint unsigned not null auto_increment comment 'my comment' first", + 'alter table `users` auto_increment = 10', + ], $blueprint->toSql()); + } + public function testMacroable() { Blueprint::macro('foo', function () { diff --git a/tests/Database/DatabaseSchemaBuilderTest.php b/tests/Database/DatabaseSchemaBuilderTest.php index e5ffd52d3d4e..e2f03e36dcc2 100644 --- a/tests/Database/DatabaseSchemaBuilderTest.php +++ b/tests/Database/DatabaseSchemaBuilderTest.php @@ -47,11 +47,12 @@ public function testDropDatabaseIfExists() public function testHasTableCorrectlyCallsGrammar() { $connection = m::mock(Connection::class); - $grammar = m::mock(stdClass::class); + $grammar = m::mock(Grammar::class); $processor = m::mock(Processor::class); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); $connection->shouldReceive('getPostProcessor')->andReturn($processor); $builder = new Builder($connection); + $grammar->shouldReceive('compileTableExists'); $grammar->shouldReceive('compileTables')->once()->andReturn('sql'); $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'prefix_table']]); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); @@ -82,7 +83,7 @@ public function testGetColumnTypeAddsPrefix() $processor->shouldReceive('processColumns')->once()->andReturn([['name' => 'id', 'type_name' => 'integer']]); $builder = new Builder($connection); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); - $grammar->shouldReceive('compileColumns')->once()->with('prefix_users')->andReturn('sql'); + $grammar->shouldReceive('compileColumns')->once()->with(null, 'prefix_users')->andReturn('sql'); $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql')->andReturn([['name' => 'id', 'type_name' => 'integer']]); $this->assertSame('integer', $builder->getColumnType('users', 'id')); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index a22bf69c095f..8877e450770a 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -53,7 +53,9 @@ public function testBasicCreateTable() public function testCreateTemporaryTable() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $connection = $this->getConnection(); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $blueprint = new Blueprint($connection, 'users'); $blueprint->create(); $blueprint->temporary(); $blueprint->increments('id'); @@ -64,6 +66,21 @@ public function testCreateTemporaryTable() $this->assertSame('create table "#users" ("id" int not null identity primary key, "email" nvarchar(255) not null)', $statements[0]); } + public function testCreateTemporaryTableWithPrefix() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getTablePrefix')->andReturn('prefix_'); + $blueprint = new Blueprint($connection, 'users'); + $blueprint->create(); + $blueprint->temporary(); + $blueprint->increments('id'); + $blueprint->string('email'); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('create table "#prefix_users" ("id" int not null identity primary key, "email" nvarchar(255) not null)', $statements[0]); + } + public function testDropTable() { $blueprint = new Blueprint($this->getConnection(), 'users'); @@ -953,18 +970,20 @@ protected function getConnection( ?SqlServerGrammar $grammar = null, ?SqlServerBuilder $builder = null ) { - $grammar ??= $this->getGrammar(); + $connection = m::mock(Connection::class); + $grammar ??= $this->getGrammar($connection); $builder ??= $this->getBuilder(); - return m::mock(Connection::class) + return $connection ->shouldReceive('getSchemaGrammar')->andReturn($grammar) ->shouldReceive('getSchemaBuilder')->andReturn($builder) ->getMock(); } - public function getGrammar() + public function getGrammar(?Connection $connection = null) { - return new SqlServerGrammar; + return ($grammar = new SqlServerGrammar) + ->setConnection($connection ?? $this->getConnection(grammar: $grammar)); } public function getBuilder() diff --git a/tests/Foundation/Testing/DatabaseTruncationTest.php b/tests/Foundation/Testing/DatabaseTruncationTest.php index 8b28d69cab76..1f972145cdbd 100644 --- a/tests/Foundation/Testing/DatabaseTruncationTest.php +++ b/tests/Foundation/Testing/DatabaseTruncationTest.php @@ -47,8 +47,8 @@ protected function tearDown(): void public function testTruncateTables() { $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => null, 'name' => 'foo'], - ['schema' => null, 'name' => 'bar'], + ['schema' => null, 'name' => 'foo', 'schema_qualified_name' => 'foo'], + ['schema' => null, 'name' => 'bar', 'schema_qualified_name' => 'bar'], ]); $this->truncateTablesForConnection($connection, 'test'); @@ -61,10 +61,10 @@ public function testTruncateTablesWithTablesToTruncateProperty() $this->tablesToTruncate = ['foo', 'bar', 'qux']; $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => null, 'name' => 'migrations'], - ['schema' => null, 'name' => 'foo'], - ['schema' => null, 'name' => 'bar'], - ['schema' => null, 'name' => 'baz'], + ['schema' => null, 'name' => 'migrations', 'schema_qualified_name' => 'migrations'], + ['schema' => null, 'name' => 'foo', 'schema_qualified_name' => 'foo'], + ['schema' => null, 'name' => 'bar', 'schema_qualified_name' => 'bar'], + ['schema' => null, 'name' => 'baz', 'schema_qualified_name' => 'baz'], ]); $this->truncateTablesForConnection($connection, 'test'); @@ -77,10 +77,10 @@ public function testTruncateTablesWithExceptTablesProperty() $this->exceptTables = ['baz', 'qux']; $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => null, 'name' => 'migrations'], - ['schema' => null, 'name' => 'foo'], - ['schema' => null, 'name' => 'bar'], - ['schema' => null, 'name' => 'baz'], + ['schema' => null, 'name' => 'migrations', 'schema_qualified_name' => 'migrations'], + ['schema' => null, 'name' => 'foo', 'schema_qualified_name' => 'foo'], + ['schema' => null, 'name' => 'bar', 'schema_qualified_name' => 'bar'], + ['schema' => null, 'name' => 'baz', 'schema_qualified_name' => 'baz'], ]); $this->truncateTablesForConnection($connection, 'test'); @@ -91,12 +91,12 @@ public function testTruncateTablesWithExceptTablesProperty() public function testTruncateTablesWithSchema() { $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => 'public', 'name' => 'migrations'], - ['schema' => 'public', 'name' => 'foo'], - ['schema' => 'public', 'name' => 'bar'], - ['schema' => 'private', 'name' => 'migrations'], - ['schema' => 'private', 'name' => 'foo'], - ['schema' => 'private', 'name' => 'baz'], + ['schema' => 'public', 'name' => 'migrations', 'schema_qualified_name' => 'public.migrations'], + ['schema' => 'public', 'name' => 'foo', 'schema_qualified_name' => 'public.foo'], + ['schema' => 'public', 'name' => 'bar', 'schema_qualified_name' => 'public.bar'], + ['schema' => 'private', 'name' => 'migrations', 'schema_qualified_name' => 'private.migrations'], + ['schema' => 'private', 'name' => 'foo', 'schema_qualified_name' => 'private.foo'], + ['schema' => 'private', 'name' => 'baz', 'schema_qualified_name' => 'private.baz'], ]); $this->truncateTablesForConnection($connection, 'test'); @@ -109,13 +109,13 @@ public function testTruncateTablesWithSchemaTablesToTruncateProperty() $this->tablesToTruncate = ['foo', 'public.bar']; $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => 'public', 'name' => 'migrations'], - ['schema' => 'public', 'name' => 'foo'], - ['schema' => 'public', 'name' => 'bar'], - ['schema' => 'public', 'name' => 'baz'], - ['schema' => 'private', 'name' => 'migrations'], - ['schema' => 'private', 'name' => 'foo'], - ['schema' => 'private', 'name' => 'bar'], + ['schema' => 'public', 'name' => 'migrations', 'schema_qualified_name' => 'public.migrations'], + ['schema' => 'public', 'name' => 'foo', 'schema_qualified_name' => 'public.foo'], + ['schema' => 'public', 'name' => 'bar', 'schema_qualified_name' => 'public.bar'], + ['schema' => 'public', 'name' => 'baz', 'schema_qualified_name' => 'public.baz'], + ['schema' => 'private', 'name' => 'migrations', 'schema_qualified_name' => 'private.migrations'], + ['schema' => 'private', 'name' => 'foo', 'schema_qualified_name' => 'private.foo'], + ['schema' => 'private', 'name' => 'bar', 'schema_qualified_name' => 'private.bar'], ]); $this->truncateTablesForConnection($connection, 'test'); @@ -128,13 +128,13 @@ public function testTruncateTablesWithSchemaAndExceptTablesProperty() $this->exceptTables = ['foo', 'public.bar']; $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => 'public', 'name' => 'migrations'], - ['schema' => 'public', 'name' => 'foo'], - ['schema' => 'public', 'name' => 'bar'], - ['schema' => 'public', 'name' => 'baz'], - ['schema' => 'private', 'name' => 'migrations'], - ['schema' => 'private', 'name' => 'foo'], - ['schema' => 'private', 'name' => 'bar'], + ['schema' => 'public', 'name' => 'migrations', 'schema_qualified_name' => 'public.migrations'], + ['schema' => 'public', 'name' => 'foo', 'schema_qualified_name' => 'public.foo'], + ['schema' => 'public', 'name' => 'bar', 'schema_qualified_name' => 'public.bar'], + ['schema' => 'public', 'name' => 'baz', 'schema_qualified_name' => 'public.baz'], + ['schema' => 'private', 'name' => 'migrations', 'schema_qualified_name' => 'private.migrations'], + ['schema' => 'private', 'name' => 'foo', 'schema_qualified_name' => 'private.foo'], + ['schema' => 'private', 'name' => 'bar', 'schema_qualified_name' => 'private.bar'], ]); $this->truncateTablesForConnection($connection, 'test'); @@ -145,11 +145,11 @@ public function testTruncateTablesWithSchemaAndExceptTablesProperty() public function testTruncateTablesWithConnectionPrefix() { $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => 'public', 'name' => 'my_migrations'], - ['schema' => 'public', 'name' => 'my_foo'], - ['schema' => 'public', 'name' => 'my_baz'], - ['schema' => 'private', 'name' => 'my_migrations'], - ['schema' => 'private', 'name' => 'my_foo'], + ['schema' => 'public', 'name' => 'my_migrations', 'schema_qualified_name' => 'public.my_migrations'], + ['schema' => 'public', 'name' => 'my_foo', 'schema_qualified_name' => 'public.my_foo'], + ['schema' => 'public', 'name' => 'my_baz', 'schema_qualified_name' => 'public.my_baz'], + ['schema' => 'private', 'name' => 'my_migrations', 'schema_qualified_name' => 'private.my_migrations'], + ['schema' => 'private', 'name' => 'my_foo', 'schema_qualified_name' => 'private.my_foo'], ], 'my_'); $this->truncateTablesForConnection($connection, 'test'); @@ -160,14 +160,14 @@ public function testTruncateTablesWithConnectionPrefix() public function testTruncateTablesOnPgsqlWithSearchPath() { $connection = $this->arrangeConnection($truncatedTables, [ - ['schema' => 'public', 'name' => 'migrations'], - ['schema' => 'public', 'name' => 'foo'], - ['schema' => 'public', 'name' => 'bar'], - ['schema' => 'my_schema', 'name' => 'foo'], - ['schema' => 'my_schema', 'name' => 'baz'], - ['schema' => 'private', 'name' => 'migrations'], - ['schema' => 'private', 'name' => 'foo'], - ['schema' => 'private', 'name' => 'baz'], + ['schema' => 'public', 'name' => 'migrations', 'schema_qualified_name' => 'public.migrations'], + ['schema' => 'public', 'name' => 'foo', 'schema_qualified_name' => 'public.foo'], + ['schema' => 'public', 'name' => 'bar', 'schema_qualified_name' => 'public.bar'], + ['schema' => 'my_schema', 'name' => 'foo', 'schema_qualified_name' => 'my_schema.foo'], + ['schema' => 'my_schema', 'name' => 'baz', 'schema_qualified_name' => 'my_schema.baz'], + ['schema' => 'private', 'name' => 'migrations', 'schema_qualified_name' => 'private.migrations'], + ['schema' => 'private', 'name' => 'foo', 'schema_qualified_name' => 'private.foo'], + ['schema' => 'private', 'name' => 'baz', 'schema_qualified_name' => 'private.baz'], ], '', PostgresBuilder::class, ['my_schema', 'public']); $this->truncateTablesForConnection($connection, 'test'); @@ -181,11 +181,12 @@ private function arrangeConnection( $actual = []; $schema = m::mock($builder ?? Builder::class); - $schema->shouldReceive('getTables')->once()->andReturn($allTables); - - if ($builder === PostgresBuilder::class && $schemas) { - $schema->shouldReceive('getSchemas')->once()->andReturn($schemas); - } + $schema->shouldReceive('getTables')->with($schemas)->once()->andReturn( + empty($schemas) + ? $allTables + : array_filter($allTables, fn ($table) => in_array($table['schema'], $schemas)) + ); + $schema->shouldReceive('getCurrentSchemaListing')->once()->andReturn($schemas); $connection = m::mock(Connection::class); $connection->shouldReceive('getTablePrefix')->andReturn($prefix); diff --git a/tests/Integration/Database/SchemaBuilderSchemaNameTest.php b/tests/Integration/Database/SchemaBuilderSchemaNameTest.php index b88b1964aadd..93bd151f4b1b 100644 --- a/tests/Integration/Database/SchemaBuilderSchemaNameTest.php +++ b/tests/Integration/Database/SchemaBuilderSchemaNameTest.php @@ -8,17 +8,42 @@ use Orchestra\Testbench\Attributes\RequiresDatabase; use PHPUnit\Framework\Attributes\DataProvider; -#[RequiresDatabase(['pgsql', 'sqlsrv'])] class SchemaBuilderSchemaNameTest extends DatabaseTestCase { + protected function setUp(): void + { + parent::setUp(); + + if ($this->usesSqliteInMemoryDatabaseConnection()) { + $this->markTestSkipped('Test cannot be run using :memory: database connection, SQLite test file is here: \Illuminate\Tests\Integration\Database\Sqlite\SchemaBuilderSchemaNameTest'); + } + } + protected function defineDatabaseMigrations() { - if ($this->driver === 'pgsql') { - DB::connection('without-prefix')->statement('create schema if not exists my_schema'); - DB::connection('with-prefix')->statement('create schema if not exists my_schema'); + if (in_array($this->driver, ['mariadb', 'mysql'])) { + Schema::createDatabase('my_schema'); + } elseif ($this->driver === 'sqlite') { + DB::connection('without-prefix')->statement("attach database ':memory:' as my_schema"); + DB::connection('with-prefix')->statement("attach database ':memory:' as my_schema"); + } elseif ($this->driver === 'pgsql') { + DB::statement('create schema if not exists my_schema'); } elseif ($this->driver === 'sqlsrv') { - DB::connection('without-prefix')->statement("if schema_id('my_schema') is null begin exec('create schema my_schema') end"); - DB::connection('with-prefix')->statement("if schema_id('my_schema') is null begin exec('create schema my_schema') end"); + DB::statement("if schema_id('my_schema') is null begin exec('create schema my_schema') end"); + } + } + + protected function destroyDatabaseMigrations() + { + if (in_array($this->driver, ['mariadb', 'mysql'])) { + Schema::dropDatabaseIfExists('my_schema'); + } elseif ($this->driver === 'sqlite') { + DB::connection('without-prefix')->statement('detach database my_schema'); + DB::connection('with-prefix')->statement('detach database my_schema'); + } elseif ($this->driver === 'pgsql') { + DB::statement('drop schema if exists my_schema cascade'); + } elseif ($this->driver === 'sqlsrv') { + // DB::statement("if schema_id('my_schema') is not null begin exec('drop schema my_schema') end"); } } @@ -26,12 +51,34 @@ protected function defineEnvironment($app) { parent::defineEnvironment($app); + $connection = $app['config']->get('database.default'); + + $app['config']->set("database.connections.$connection.prefix_indexes", true); $app['config']->set('database.connections.pgsql.search_path', 'public,my_schema'); - $app['config']->set('database.connections.without-prefix', $app['config']->get('database.connections.'.$this->driver)); + $app['config']->set('database.connections.without-prefix', $app['config']->get('database.connections.'.$connection)); $app['config']->set('database.connections.with-prefix', $app['config']->get('database.connections.without-prefix')); $app['config']->set('database.connections.with-prefix.prefix', 'example_'); } + #[DataProvider('connectionProvider')] + public function testSchemas($connection) + { + $schema = Schema::connection($connection); + + $schemas = $schema->getSchemas(); + + $this->assertSame($schema->getCurrentSchemaName(), collect($schemas)->firstWhere('default')['name']); + $this->assertEqualsCanonicalizing( + match ($this->driver) { + 'mysql', 'mariadb' => ['laravel', 'my_schema'], + 'pgsql' => ['public', 'my_schema'], + 'sqlite' => ['main', 'my_schema'], + 'sqlsrv' => ['dbo', 'guest', 'my_schema'], + }, + array_column($schemas, 'name'), + ); + } + #[DataProvider('connectionProvider')] public function testCreate($connection) { @@ -43,6 +90,14 @@ public function testCreate($connection) $this->assertTrue($schema->hasTable('my_schema.table')); $this->assertFalse($schema->hasTable('table')); + + $currentSchema = $schema->getCurrentSchemaName(); + $tableName = $connection === 'with-prefix' ? 'example_table' : 'table'; + + $this->assertEqualsCanonicalizing( + [$currentSchema.'.migrations', 'my_schema.'.$tableName], + $schema->getTableListing([$currentSchema, 'my_schema']) + ); } #[DataProvider('connectionProvider')] @@ -62,7 +117,11 @@ public function testRename($connection) $this->assertTrue($schema->hasTable('table')); $this->assertFalse($schema->hasTable('my_table')); - $schema->rename('my_schema.table', 'new_table'); + if (in_array($this->driver, ['mariadb', 'mysql'])) { + $schema->rename('my_schema.table', 'my_schema.new_table'); + } else { + $schema->rename('my_schema.table', 'new_table'); + } $schema->rename('table', 'my_table'); $this->assertTrue($schema->hasTable('my_schema.new_table')); @@ -86,10 +145,23 @@ public function testDrop($connection) $this->assertTrue($schema->hasTable('my_schema.table')); $this->assertTrue($schema->hasTable('table')); + $currentSchema = $schema->getCurrentSchemaName(); + $tableName = $connection === 'with-prefix' ? 'example_table' : 'table'; + + $this->assertEqualsCanonicalizing( + [$currentSchema.'.migrations', $currentSchema.'.'.$tableName, 'my_schema.'.$tableName], + $schema->getTableListing([$currentSchema, 'my_schema']) + ); + $schema->drop('my_schema.table'); $this->assertFalse($schema->hasTable('my_schema.table')); $this->assertTrue($schema->hasTable('table')); + + $this->assertEqualsCanonicalizing( + [$currentSchema.'.migrations', $currentSchema.'.'.$tableName], + $schema->getTableListing([$currentSchema, 'my_schema']) + ); } #[DataProvider('connectionProvider')] @@ -210,8 +282,16 @@ public function testModifyColumns($connection) $this->assertStringContainsString('default title', collect($schema->getColumns('my_table'))->firstWhere('name', 'title')['default']); $this->assertEquals($this->driver === 'sqlsrv' ? 'nvarchar' : 'varchar', $schema->getColumnType('my_schema.table', 'name')); $this->assertEquals($this->driver === 'sqlsrv' ? 'nvarchar' : 'varchar', $schema->getColumnType('my_table', 'title')); - $this->assertEquals($this->driver === 'pgsql' ? 'int8' : 'bigint', $schema->getColumnType('my_schema.table', 'count')); - $this->assertEquals($this->driver === 'pgsql' ? 'int8' : 'bigint', $schema->getColumnType('my_table', 'count')); + $this->assertEquals(match ($this->driver) { + 'pgsql' => 'int8', + 'sqlite' => 'integer', + default => 'bigint', + }, $schema->getColumnType('my_schema.table', 'count')); + $this->assertEquals(match ($this->driver) { + 'pgsql' => 'int8', + 'sqlite' => 'integer', + default => 'bigint', + }, $schema->getColumnType('my_table', 'count')); } #[DataProvider('connectionProvider')] @@ -306,6 +386,7 @@ public function testIndexes($connection) } #[DataProvider('connectionProvider')] + #[RequiresDatabase(['mariadb', 'mysql', 'pgsql', 'sqlsrv'])] public function testForeignKeys($connection) { $schema = Schema::connection($connection); @@ -315,7 +396,8 @@ public function testForeignKeys($connection) }); $schema->create('my_schema.table', function (Blueprint $table) { $table->id(); - $table->foreignId('my_table_id')->constrained(); + $table->foreignId('my_table_id') + ->constrained(table: in_array($this->driver, ['mariadb', 'mysql']) ? 'laravel.my_tables' : null); }); $schema->create('table', function (Blueprint $table) { $table->unsignedBigInteger('table_id'); @@ -324,10 +406,15 @@ public function testForeignKeys($connection) $schemaTableName = $connection === 'with-prefix' ? 'example_table' : 'table'; $tableName = $connection === 'with-prefix' ? 'example_my_tables' : 'my_tables'; + $defaultSchemaName = match ($this->driver) { + 'pgsql' => 'public', + 'sqlsrv' => 'dbo', + default => 'laravel', + }; $this->assertTrue(collect($schema->getForeignKeys('my_schema.table'))->contains( fn ($foreign) => $foreign['columns'] === ['my_table_id'] - && $foreign['foreign_table'] === $tableName && in_array($foreign['foreign_schema'], ['public', 'dbo']) + && $foreign['foreign_table'] === $tableName && $foreign['foreign_schema'] === $defaultSchemaName && $foreign['foreign_columns'] === ['id'] )); @@ -348,29 +435,80 @@ public function testForeignKeys($connection) $this->assertEmpty($schema->getForeignKeys('table')); } + #[DataProvider('connectionProvider')] + #[RequiresDatabase('sqlite')] + public function testForeignKeysOnSameSchema($connection) + { + $schema = Schema::connection($connection); + + $schema->create('my_schema.my_tables', function (Blueprint $table) { + $table->id(); + }); + $schema->create('my_schema.table', function (Blueprint $table) { + $table->id(); + $table->foreignId('my_table_id')->constrained(); + }); + $schema->create('my_schema.second_table', function (Blueprint $table) { + $table->unsignedBigInteger('table_id'); + $table->foreign('table_id')->references('id')->on('table'); + }); + + $myTableName = $connection === 'with-prefix' ? 'example_my_tables' : 'my_tables'; + $tableName = $connection === 'with-prefix' ? 'example_table' : 'table'; + + $this->assertTrue(collect($schema->getForeignKeys('my_schema.table'))->contains( + fn ($foreign) => $foreign['columns'] === ['my_table_id'] + && $foreign['foreign_table'] === $myTableName && $foreign['foreign_schema'] === 'my_schema' + && $foreign['foreign_columns'] === ['id'] + )); + + $this->assertTrue(collect($schema->getForeignKeys('my_schema.second_table'))->contains( + fn ($foreign) => $foreign['columns'] === ['table_id'] + && $foreign['foreign_table'] === $tableName && $foreign['foreign_schema'] === 'my_schema' + && $foreign['foreign_columns'] === ['id'] + )); + + $schema->table('my_schema.table', function (Blueprint $table) { + $table->dropForeign(['my_table_id']); + }); + + $this->assertEmpty($schema->getForeignKeys('my_schema.table')); + } + #[DataProvider('connectionProvider')] public function testHasView($connection) { - $connection = DB::connection($connection); - $schema = $connection->getSchemaBuilder(); + $db = DB::connection($connection); + $schema = $db->getSchemaBuilder(); - $connection->statement('create view '.$connection->getSchemaGrammar()->wrapTable('my_schema.view').' (name) as select 1'); - $connection->statement('create view '.$connection->getSchemaGrammar()->wrapTable('my_view').' (name) as select 1'); + $db->statement('create view '.$db->getSchemaGrammar()->wrapTable('my_schema.view').' (name) as select 1'); + $db->statement('create view '.$db->getSchemaGrammar()->wrapTable('my_view').' (name) as select 1'); $this->assertTrue($schema->hasView('my_schema.view')); $this->assertTrue($schema->hasView('my_view')); $this->assertTrue($schema->hasColumn('my_schema.view', 'name')); $this->assertTrue($schema->hasColumn('my_view', 'name')); - $connection->statement('drop view '.$connection->getSchemaGrammar()->wrapTable('my_schema.view')); - $connection->statement('drop view '.$connection->getSchemaGrammar()->wrapTable('my_view')); + $currentSchema = $schema->getCurrentSchemaName(); + $viewName = $connection === 'with-prefix' ? 'example_view' : 'view'; + $myViewName = $connection === 'with-prefix' ? 'example_my_view' : 'my_view'; + + $this->assertEqualsCanonicalizing( + [$currentSchema.'.'.$myViewName, 'my_schema.'.$viewName], + array_column($schema->getViews([$currentSchema, 'my_schema']), 'schema_qualified_name') + ); + + $db->statement('drop view '.$db->getSchemaGrammar()->wrapTable('my_schema.view')); + $db->statement('drop view '.$db->getSchemaGrammar()->wrapTable('my_view')); $this->assertFalse($schema->hasView('my_schema.view')); $this->assertFalse($schema->hasView('my_view')); + + $this->assertEmpty($schema->getViews([$currentSchema, 'my_schema'])); } #[DataProvider('connectionProvider')] - #[RequiresDatabase('pgsql')] + #[RequiresDatabase(['mariadb', 'mysql', 'pgsql'])] public function testComment($connection) { $schema = Schema::connection($connection); @@ -386,12 +524,13 @@ public function testComment($connection) $tables = collect($schema->getTables()); $tableName = $connection === 'with-prefix' ? 'example_table' : 'table'; + $defaultSchema = $this->driver === 'pgsql' ? 'public' : 'laravel'; $this->assertEquals('comment on schema table', $tables->first(fn ($table) => $table['name'] === $tableName && $table['schema'] === 'my_schema')['comment'] ); $this->assertEquals('comment on table', - $tables->first(fn ($table) => $table['name'] === $tableName && $table['schema'] === 'public')['comment'] + $tables->first(fn ($table) => $table['name'] === $tableName && $table['schema'] === $defaultSchema)['comment'] ); $this->assertEquals('comment on schema column', collect($schema->getColumns('my_schema.table'))->firstWhere('name', 'name')['comment'] @@ -402,7 +541,7 @@ public function testComment($connection) } #[DataProvider('connectionProvider')] - #[RequiresDatabase('pgsql')] + #[RequiresDatabase(['mariadb', 'mysql', 'pgsql'])] public function testAutoIncrementStartingValue($connection) { $this->expectNotToPerformAssertions(); @@ -440,7 +579,7 @@ public function testHasTable($connection) 'database.connections.'.$connection.'.password' => 'Passw0rd', ]); - $this->assertEquals('my_schema', $db->scalar('select schema_name()')); + $this->assertEquals('my_schema', $schema->getCurrentSchemaName()); $schema->create('table', function (Blueprint $table) { $table->id(); diff --git a/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php b/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php index b8aaf1a0f818..2db84efd5aa7 100644 --- a/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php +++ b/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php @@ -74,28 +74,6 @@ public function testRenamingColumnsWorks() $this->assertTrue($schema->hasColumns('test', ['bar', 'qux'])); } - public function testNativeColumnModifyingOnMySql() - { - $blueprint = $this->getBlueprint(new MySqlGrammar, 'users', function ($table) { - $table->double('amount')->nullable()->invisible()->after('name')->change(); - $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->useCurrentOnUpdate()->change(); - $table->enum('difficulty', ['easy', 'hard'])->default('easy')->charset('utf8mb4')->collation('unicode')->change(); - $table->geometry('positions', 'multipolygon', 1234)->storedAs('expression')->change(); - $table->string('old_name', 50)->renameTo('new_name')->change(); - $table->bigIncrements('id')->first()->from(10)->comment('my comment')->change(); - }); - - $this->assertEquals([ - 'alter table `users` modify `amount` double null invisible after `name`', - 'alter table `users` modify `added_at` timestamp(4) not null default CURRENT_TIMESTAMP(4) on update CURRENT_TIMESTAMP(4)', - "alter table `users` modify `difficulty` enum('easy', 'hard') character set utf8mb4 collate 'unicode' not null default 'easy'", - 'alter table `users` modify `positions` multipolygon srid 1234 as (expression) stored', - 'alter table `users` change `old_name` `new_name` varchar(50) not null', - "alter table `users` modify `id` bigint unsigned not null auto_increment comment 'my comment' first", - 'alter table `users` auto_increment = 10', - ], $blueprint->toSql()); - } - public function testNativeColumnModifyingOnPostgreSql() { $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { @@ -542,6 +520,7 @@ protected function getBlueprint( Closure $callback, ): Blueprint { $connection = DB::connection()->setSchemaGrammar($grammar); + $grammar->setConnection($connection); return new Blueprint($connection, $table, $callback); } diff --git a/tests/Integration/Database/Sqlite/SchemaBuilderSchemaNameTest.php b/tests/Integration/Database/Sqlite/SchemaBuilderSchemaNameTest.php new file mode 100644 index 000000000000..03f52e9e875b --- /dev/null +++ b/tests/Integration/Database/Sqlite/SchemaBuilderSchemaNameTest.php @@ -0,0 +1,11 @@ +mustRun(); + remote('migrate:install'); } protected function tearDown(): void From 67ff0cde163bc41b8d3de2209e3a504448e8c18e Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 22 Jan 2025 23:07:30 +0000 Subject: [PATCH 063/455] Update facade docblocks --- src/Illuminate/Support/Facades/Schema.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index a388c6b415dc..6204dde9f100 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -40,12 +40,12 @@ * @method static bool enableForeignKeyConstraints() * @method static bool disableForeignKeyConstraints() * @method static mixed withoutForeignKeyConstraints(\Closure $callback) - * @method static \Illuminate\Database\Connection getConnection() - * @method static \Illuminate\Database\Schema\Builder setConnection(\Illuminate\Database\Connection $connection) - * @method static void blueprintResolver(\Closure $resolver) * @method static string[]|null getCurrentSchemaListing() * @method static string|null getCurrentSchemaName() * @method static array parseSchemaAndTable(string $reference, string|bool|null $withDefaultSchema = null) + * @method static \Illuminate\Database\Connection getConnection() + * @method static \Illuminate\Database\Schema\Builder setConnection(\Illuminate\Database\Connection $connection) + * @method static void blueprintResolver(\Closure $resolver) * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) * @method static bool hasMacro(string $name) From e7cb34ef759008d430c9647de8c6ab587191a670 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Thu, 23 Jan 2025 22:05:21 +0800 Subject: [PATCH 064/455] [12.x] Fix Session's `getCookieExpirationDate` incompatibility with Carbon 3 (#54313) Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Session/Middleware/StartSession.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 287341598113..859d4604ea43 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -266,7 +266,7 @@ protected function getCookieExpirationDate() $config = $this->manager->getSessionConfig(); return $config['expire_on_close'] ? 0 : Date::instance( - Carbon::now()->addMinutes($config['lifetime']) + Carbon::now()->addMinutes((int) $config['lifetime']) ); } From 8b24a11e68d55c4623d4f3bfe0acdc5bb7591ad3 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Thu, 23 Jan 2025 22:21:24 +0800 Subject: [PATCH 065/455] [12.x] Update minimum PHPUnit versions (#54323) * [12.x] Update minimum PHPUnit versions This is inline with the minimum supported version defined in `nunomaduro/collision` Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- .github/workflows/tests.yml | 4 ++-- composer.json | 4 ++-- src/Illuminate/Testing/composer.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 33f7860f4cd6..8d3c3894cff6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,7 +40,7 @@ jobs: fail-fast: true matrix: php: [8.2, 8.3, 8.4] - phpunit: ['11.3.6'] + phpunit: ['11.5.3'] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - PHPUnit ${{ matrix.phpunit }} - ${{ matrix.stability }} @@ -103,7 +103,7 @@ jobs: fail-fast: true matrix: php: [8.2, 8.3, 8.4] - phpunit: ['11.3.6'] + phpunit: ['11.5.3'] stability: [prefer-lowest, prefer-stable] exclude: - php: 8.4 diff --git a/composer.json b/composer.json index b2d3ea23a945..7172a1401c59 100644 --- a/composer.json +++ b/composer.json @@ -115,7 +115,7 @@ "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^1.11.5", - "phpunit/phpunit": "^11.3.6", + "phpunit/phpunit": "^11.5.3", "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", "symfony/cache": "^7.2.0", @@ -188,7 +188,7 @@ "mockery/mockery": "Required to use mocking (^1.6).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", - "phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0).", + "phpunit/phpunit": "Required to use assertions and run tests (^11.5.3).", "predis/predis": "Required to use the predis connector (^2.3).", "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 (^6.0|^7.0).", diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index 29254b53a515..8196d3449e46 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -37,7 +37,7 @@ "illuminate/database": "Required to assert databases (^12.0).", "illuminate/http": "Required to assert responses (^12.0).", "mockery/mockery": "Required to use mocking (^1.6).", - "phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0)." + "phpunit/phpunit": "Required to use assertions and run tests (^11.5.3)." }, "config": { "sort-packages": true From 3502c22341edddee9d733709c2f9a21f3ff2aef1 Mon Sep 17 00:00:00 2001 From: Sander Muller Date: Fri, 24 Jan 2025 18:25:33 +0100 Subject: [PATCH 066/455] [12.x] Prevent XSS vulnerabilities by excluding SVGs by default in image validation (#54331) * Prevent XSS through SVG image validation * Apply by default in validateImage * formatting --------- Co-authored-by: Taylor Otwell --- .../Concerns/ValidatesAttributes.php | 11 ++++-- src/Illuminate/Validation/Rule.php | 5 +-- src/Illuminate/Validation/Rules/File.php | 5 +-- src/Illuminate/Validation/Rules/ImageFile.php | 10 ++++-- tests/Validation/ValidationFileRuleTest.php | 34 +++++++++++++++++++ tests/Validation/ValidationValidatorTest.php | 6 ++++ 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index cdbe90f3bdb0..469150bad19f 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1387,11 +1387,18 @@ public function validateHexColor($attribute, $value) * * @param string $attribute * @param mixed $value + * @param array $parameters * @return bool */ - public function validateImage($attribute, $value) + public function validateImage($attribute, $value, $parameters = []) { - return $this->validateMimes($attribute, $value, ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp']); + $mimes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; + + if (is_array($parameters) && in_array('allow_svg', $parameters)) { + $mimes[] = 'svg'; + } + + return $this->validateMimes($attribute, $value, $mimes); } /** diff --git a/src/Illuminate/Validation/Rule.php b/src/Illuminate/Validation/Rule.php index b94f40ca3372..c997e83a433a 100644 --- a/src/Illuminate/Validation/Rule.php +++ b/src/Illuminate/Validation/Rule.php @@ -204,11 +204,12 @@ public static function file() /** * Get an image file rule builder instance. * + * @param bool $allowSvg * @return \Illuminate\Validation\Rules\ImageFile */ - public static function imageFile() + public static function imageFile($allowSvg = false) { - return new ImageFile; + return new ImageFile($allowSvg); } /** diff --git a/src/Illuminate/Validation/Rules/File.php b/src/Illuminate/Validation/Rules/File.php index 4c3449be08da..0aa0d71ce35f 100644 --- a/src/Illuminate/Validation/Rules/File.php +++ b/src/Illuminate/Validation/Rules/File.php @@ -118,11 +118,12 @@ public static function default() /** * Limit the uploaded file to only image types. * + * @param bool $allowSvg * @return ImageFile */ - public static function image() + public static function image($allowSvg = false) { - return new ImageFile(); + return new ImageFile($allowSvg); } /** diff --git a/src/Illuminate/Validation/Rules/ImageFile.php b/src/Illuminate/Validation/Rules/ImageFile.php index 2cee97e5bc00..4142a63382c0 100644 --- a/src/Illuminate/Validation/Rules/ImageFile.php +++ b/src/Illuminate/Validation/Rules/ImageFile.php @@ -7,17 +7,23 @@ class ImageFile extends File /** * Create a new image file rule instance. * + * @param bool $allowSvg * @return void */ - public function __construct() + public function __construct($allowSvg = false) { - $this->rules('image'); + if ($allowSvg) { + $this->rules('image:allow_svg'); + } else { + $this->rules('image'); + } } /** * The dimension constraints for the uploaded file. * * @param \Illuminate\Validation\Rules\Dimensions $dimensions + * @return $this */ public function dimensions($dimensions) { diff --git a/tests/Validation/ValidationFileRuleTest.php b/tests/Validation/ValidationFileRuleTest.php index 1705a3ef198b..c70783da69bd 100644 --- a/tests/Validation/ValidationFileRuleTest.php +++ b/tests/Validation/ValidationFileRuleTest.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Facade; use Illuminate\Translation\ArrayLoader; use Illuminate\Translation\Translator; +use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\File; use Illuminate\Validation\ValidationServiceProvider; use Illuminate\Validation\Validator; @@ -194,6 +195,39 @@ public function testImage() ); } + public function testImageFailsOnSvgByDefault() + { + $maliciousSvgFileWithXSS = UploadedFile::fake()->createWithContent( + name: 'foo.svg', + content: <<<'XML' + + XSS Logo + + + XML + ); + + $this->fails( + File::image(), + $maliciousSvgFileWithXSS, + ['validation.image'] + ); + $this->fails( + Rule::imageFile(), + $maliciousSvgFileWithXSS, + ['validation.image'] + ); + + $this->passes( + File::image(allowSvg: true), + $maliciousSvgFileWithXSS + ); + $this->passes( + Rule::imageFile(allowSvg: true), + $maliciousSvgFileWithXSS + ); + } + public function testSize() { $this->fails( diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 6603471e6095..ae5e71ab8778 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -4891,6 +4891,12 @@ public function testValidateImage() $file6->expects($this->any())->method('guessExtension')->willReturn('svg'); $file6->expects($this->any())->method('getClientOriginalExtension')->willReturn('svg'); $v = new Validator($trans, ['x' => $file6], ['x' => 'image']); + $this->assertFalse($v->passes()); + + $file6 = $this->getMockBuilder(UploadedFile::class)->onlyMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); + $file6->expects($this->any())->method('guessExtension')->willReturn('svg'); + $file6->expects($this->any())->method('getClientOriginalExtension')->willReturn('svg'); + $v = new Validator($trans, ['x' => $file6], ['x' => 'image:allow_svg']); $this->assertTrue($v->passes()); $file7 = $this->getMockBuilder(UploadedFile::class)->onlyMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); From 1903c93bb3052bcb6e7619dd3662302ae30cc421 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 27 Jan 2025 03:31:42 +0800 Subject: [PATCH 067/455] Convert interfaces (introduced in after 11.0.0) from docblock to method (#54348) For backward compatibility, we typically add new method to Interface using docblock on minor/patch releases. This should be a good time to declare them as actual method. Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Contracts/Routing/UrlGenerator.php | 14 +++++++++++--- .../Queue/Failed/FailedJobProviderInterface.php | 11 ++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Contracts/Routing/UrlGenerator.php b/src/Illuminate/Contracts/Routing/UrlGenerator.php index 0e542c9b43d8..ed159066c9d1 100644 --- a/src/Illuminate/Contracts/Routing/UrlGenerator.php +++ b/src/Illuminate/Contracts/Routing/UrlGenerator.php @@ -2,9 +2,6 @@ namespace Illuminate\Contracts\Routing; -/** - * @method string query(string $path, array $query = [], mixed $extra = [], bool|null $secure = null) - */ interface UrlGenerator { /** @@ -86,6 +83,17 @@ public function signedRoute($name, $parameters = [], $expiration = null, $absolu */ public function temporarySignedRoute($name, $expiration, $parameters = [], $absolute = true); + /** + * Generate an absolute URL with the given query parameters. + * + * @param string $path + * @param array $query + * @param mixed $extra + * @param bool|null $secure + * @return string + */ + public function query($path, $query = [], $extra = [], $secure = null); + /** * Get the URL to a controller action. * diff --git a/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php b/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php index bb52d1749ada..b7ce69fca8b4 100644 --- a/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php +++ b/src/Illuminate/Queue/Failed/FailedJobProviderInterface.php @@ -2,9 +2,6 @@ namespace Illuminate\Queue\Failed; -/** - * @method array ids(string $queue = null) - */ interface FailedJobProviderInterface { /** @@ -18,6 +15,14 @@ interface FailedJobProviderInterface */ public function log($connection, $queue, $payload, $exception); + /** + * Get the IDs of all of the failed jobs. + * + * @param string|null $queue + * @return array + */ + public function ids($queue = null); + /** * Get a list of all of the failed jobs. * From 140d2cffc587df33e0775ddb6f2660b75756f3bd Mon Sep 17 00:00:00 2001 From: Julius Kiekbusch Date: Tue, 28 Jan 2025 21:54:28 +0100 Subject: [PATCH 068/455] [12.x] Validate paths for UTF-8 characters (#54370) * Add validate utf-8 path middleware * styleci formatting * styleci formatting * Rename Middleware * formatting --------- Co-authored-by: Taylor Otwell --- .../Foundation/Configuration/Middleware.php | 1 + .../Http/Exceptions/MalformedUrlException.php | 18 +++++++ .../Http/Middleware/ValidatePathEncoding.php | 28 ++++++++++ .../Middleware/ValidatePathEncodingTest.php | 53 +++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 src/Illuminate/Http/Exceptions/MalformedUrlException.php create mode 100644 src/Illuminate/Http/Middleware/ValidatePathEncoding.php create mode 100644 tests/Foundation/Http/Middleware/ValidatePathEncodingTest.php diff --git a/src/Illuminate/Foundation/Configuration/Middleware.php b/src/Illuminate/Foundation/Configuration/Middleware.php index f6bc12eb2e9e..20b50499aedf 100644 --- a/src/Illuminate/Foundation/Configuration/Middleware.php +++ b/src/Illuminate/Foundation/Configuration/Middleware.php @@ -451,6 +451,7 @@ public function appendToPriorityList($after, $append) public function getGlobalMiddleware() { $middleware = $this->global ?: array_values(array_filter([ + \Illuminate\Http\Middleware\ValidatePathEncoding::class, \Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class, $this->trustHosts ? \Illuminate\Http\Middleware\TrustHosts::class : null, \Illuminate\Http\Middleware\TrustProxies::class, diff --git a/src/Illuminate/Http/Exceptions/MalformedUrlException.php b/src/Illuminate/Http/Exceptions/MalformedUrlException.php new file mode 100644 index 000000000000..c5aa86d418be --- /dev/null +++ b/src/Illuminate/Http/Exceptions/MalformedUrlException.php @@ -0,0 +1,18 @@ +path()); + + if (! mb_check_encoding($decodedPath, 'UTF-8')) { + throw new MalformedUrlException; + } + + return $next($request); + } +} diff --git a/tests/Foundation/Http/Middleware/ValidatePathEncodingTest.php b/tests/Foundation/Http/Middleware/ValidatePathEncodingTest.php new file mode 100644 index 000000000000..67a0b4ea22b7 --- /dev/null +++ b/tests/Foundation/Http/Middleware/ValidatePathEncodingTest.php @@ -0,0 +1,53 @@ +server->set('REQUEST_METHOD', 'GET'); + $symfonyRequest->server->set('REQUEST_URI', $path); + $request = Request::createFromBase($symfonyRequest); + + $response = $middleware->handle($request, fn () => new Response('OK')); + + $this->assertSame(200, $response->status()); + $this->assertSame('OK', $response->content()); + } + + #[TestWith(['%C0'])] + #[TestWith(['%c0'])] + public function testInvalidPathsAreFailing(string $path): void + { + $middleware = new ValidatePathEncoding; + $symfonyRequest = new SymfonyRequest; + $symfonyRequest->server->set('REQUEST_METHOD', 'GET'); + $symfonyRequest->server->set('REQUEST_URI', $path); + $request = Request::createFromBase($symfonyRequest); + + try { + $middleware->handle($request, fn () => new Response('OK')); + + $this->fail('MalformedUrlExceptions should have been thrown.'); + } catch(MalformedUrlException $e) { + $this->assertSame(400, $e->getStatusCode()); + $this->assertSame('Malformed URL.', $e->getMessage()); + } + } +} From 345e7555098f0d3a0f1508f49f16985ac46decce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=2E=20Nagy=20Gerg=C5=91?= Date: Thu, 30 Jan 2025 19:24:38 +0100 Subject: [PATCH 069/455] [12.x] Fix aggregate alias when using expression (#54418) --- .../Eloquent/Concerns/QueriesRelationships.php | 6 +++++- tests/Database/DatabaseEloquentBuilderTest.php | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index e064689a8f54..bbd1ccca4f42 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -775,7 +775,11 @@ public function withAggregate($relations, $column, $function = null) // the query builder. Then, we will return the builder instance back to the developer // for further constraint chaining that needs to take place on the query as needed. $alias ??= Str::snake( - preg_replace('/[^[:alnum:][:space:]_]/u', '', "$name $function {$this->getQuery()->getGrammar()->getValue($column)}") + preg_replace( + '/[^[:alnum:][:space:]_]/u', + '', + sprintf('%s %s %s', $name, $function, strtolower($this->getQuery()->getGrammar()->getValue($column))) + ) ); if ($function === 'exists') { diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 912c2e2dd207..e7e65fac8204 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -1441,6 +1441,18 @@ public function testWithCountMultipleAndPartialRename() $this->assertSame('select "eloquent_builder_test_model_parent_stubs".*, (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id") as "foo_bar", (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id") as "foo_count" from "eloquent_builder_test_model_parent_stubs"', $builder->toSql()); } + public function testWithAggregateAlias() + { + $model = new EloquentBuilderTestModelParentStub; + + $builder = $model->withAggregate('foo', new Expression('TIMESTAMPDIFF(SECOND, `created_at`, `updated_at`)'), 'sum'); + + $this->assertSame( + 'select "eloquent_builder_test_model_parent_stubs".*, (select sum(TIMESTAMPDIFF(SECOND, `created_at`, `updated_at`)) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id") as "foo_sum_timestampdiffsecond_created_at_updated_at" from "eloquent_builder_test_model_parent_stubs"', + $builder->toSql() + ); + } + public function testWithAggregateAndSelfRelationConstrain() { EloquentBuilderTestStub::resolveRelationUsing('children', function ($model) { From 9243eac9be32b3e3d5a78ba9dc8a0d34c709ae97 Mon Sep 17 00:00:00 2001 From: Kristijan <470003+eldair@users.noreply.github.com> Date: Fri, 31 Jan 2025 09:14:10 +0100 Subject: [PATCH 070/455] Update Session.php (#54421) Added flash method to Session interface --- src/Illuminate/Contracts/Session/Session.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Illuminate/Contracts/Session/Session.php b/src/Illuminate/Contracts/Session/Session.php index 1bf025a096c8..4fea003cf8a9 100644 --- a/src/Illuminate/Contracts/Session/Session.php +++ b/src/Illuminate/Contracts/Session/Session.php @@ -98,6 +98,15 @@ public function pull($key, $default = null); */ public function put($key, $value = null); + /** + * Flash a key / value pair to the session. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function flash(string $key, $value = true); + /** * Get the CSRF token value. * From afac7829dece216064c35e045e85f293f4d036ea Mon Sep 17 00:00:00 2001 From: Kim Youngwoo <40349371+dvlpr91@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:21:08 +0900 Subject: [PATCH 071/455] Adding the withQueryString method to the paginator interface (#54462) - According to the documentation, `paginate` has a `withQueryString` method. - See, https://laravel.com/docs/pagination#appending-query-string-values - Not only `cursorPaginate`, but also `paginate` and `simplePaginate` should implement `withQueryString` and work with it. ref: https://github.com/laravel/framework/pull/54460 --- src/Illuminate/Contracts/Pagination/Paginator.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Illuminate/Contracts/Pagination/Paginator.php b/src/Illuminate/Contracts/Pagination/Paginator.php index c59f58b7138e..e7769d4ef21f 100644 --- a/src/Illuminate/Contracts/Pagination/Paginator.php +++ b/src/Illuminate/Contracts/Pagination/Paginator.php @@ -34,6 +34,13 @@ public function appends($key, $value = null); */ public function fragment($fragment = null); + /** + * Add all current query string values to the paginator. + * + * @return $this + */ + public function withQueryString(); + /** * The URL for the next page, or null. * From d112023898198bd72e514d953db1b2e3802d59a6 Mon Sep 17 00:00:00 2001 From: Mathias Grimm Date: Wed, 5 Feb 2025 08:20:50 -0300 Subject: [PATCH 072/455] [12.x] feat: --memory=0 should mean skip memory exceeded verification (Breaking Change) (#54393) * [12.x] feat: MemoryExceeded 0 should mean infinite memory * [12.x] feat: MemoryExceeded 0 should mean infinite memory * [12.x] feat: MemoryExceeded 0 should mean infinite memory --- src/Illuminate/Queue/Worker.php | 2 +- tests/Queue/QueueWorkerTest.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 49ad0aa3bce6..c4ffb227a591 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -748,7 +748,7 @@ protected function supportsAsyncSignals() */ public function memoryExceeded($memoryLimit) { - return (memory_get_usage(true) / 1024 / 1024) >= $memoryLimit; + return $memoryLimit > 0 && (memory_get_usage(true) / 1024 / 1024) >= $memoryLimit; } /** diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index 33aa4c8dc785..6c511807a50c 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -100,6 +100,24 @@ public function testWorkerStopsWhenMemoryExceeded() $this->events->shouldHaveReceived('dispatch')->with(m::type(JobProcessed::class))->once(); } + public function testWorkerMemoryExceededWhenMemoryIsZero() + { + $worker = new Worker(...$this->workerDependencies()); + $this->assertFalse($worker->memoryExceeded(0)); + } + + public function testWorkerMemoryExceededWhenMemoryGreaterThanZero() + { + $worker = new Worker(...$this->workerDependencies()); + $this->assertTrue($worker->memoryExceeded(1)); + } + + public function testWorkerMemoryExceededWhenMemoryIsNegative() + { + $worker = new Worker(...$this->workerDependencies()); + $this->assertFalse($worker->memoryExceeded(-1)); + } + public function testJobCanBeFiredBasedOnPriority() { $worker = $this->getWorker('default', [ From 54f5cdecde0719e2a28447a7dc578ae0298294f6 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Thu, 6 Feb 2025 16:25:19 -0500 Subject: [PATCH 073/455] Auto-discover nested policies following conventional, parallel hierarchy (#54493) * Remove redundant check * Support parallel conventional hierachies * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Auth/Access/Gate.php | 3 +++ .../Fixtures/Models/Nested/SubTestUser.php | 27 +++++++++++++++++++ .../Fixtures/Models/Nested/TopTestUser.php | 27 +++++++++++++++++++ .../Policies/Nested/SubTestUserPolicy.php | 8 ++++++ .../Policies/Nested/TopTestUserPolicy.php | 8 ++++++ .../Auth/GatePolicyResolutionTest.php | 15 +++++++++++ 6 files changed, 88 insertions(+) create mode 100644 tests/Integration/Auth/Fixtures/Models/Nested/SubTestUser.php create mode 100644 tests/Integration/Auth/Fixtures/Models/Nested/TopTestUser.php create mode 100644 tests/Integration/Auth/Fixtures/Models/Policies/Nested/SubTestUserPolicy.php create mode 100644 tests/Integration/Auth/Fixtures/Policies/Nested/TopTestUserPolicy.php diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 162f95f6e128..a4b7f89784f4 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -703,6 +703,9 @@ protected function guessPolicyName($class) $classDirname = implode('\\', array_slice($classDirnameSegments, 0, $index)); return $classDirname.'\\Policies\\'.class_basename($class).'Policy'; + })->when(str_contains($classDirname, '\\Models\\'), function ($collection) use ($class, $classDirname) { + return $collection->concat([str_replace('\\Models\\', '\\Policies\\', $classDirname).'\\'.class_basename($class).'Policy']) + ->concat([str_replace('\\Models\\', '\\Models\\Policies\\', $classDirname).'\\'.class_basename($class).'Policy']); })->reverse()->values()->first(function ($class) { return class_exists($class); }) ?: [$classDirname.'\\Policies\\'.class_basename($class).'Policy']); diff --git a/tests/Integration/Auth/Fixtures/Models/Nested/SubTestUser.php b/tests/Integration/Auth/Fixtures/Models/Nested/SubTestUser.php new file mode 100644 index 000000000000..8a02e5bbdee3 --- /dev/null +++ b/tests/Integration/Auth/Fixtures/Models/Nested/SubTestUser.php @@ -0,0 +1,27 @@ +assertInstanceOf( + TopTestUserPolicy::class, + Gate::getPolicyFor(Fixtures\Models\Nested\TopTestUser::class) + ); + + $this->assertInstanceOf( + SubTestUserPolicy::class, + Gate::getPolicyFor(Fixtures\Models\Nested\SubTestUser::class) + ); + } + public function testPolicyCanBeGuessedUsingCallback() { Gate::guessPolicyNamesUsing(function () { From d078dc7cdd19f75ed1bff4bf2a08b5eb567a75d3 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 7 Feb 2025 05:46:01 +0800 Subject: [PATCH 074/455] [12.x] Reintroduce PHPUnit 10.5 supports (#54490) * [12.x] Reintroduce PHPUnit 10.5 supports This minimize the requirements to match with PHPUnit 11 requirements for Laravel packages while still maintaining support for older PHPUnit versions used in Laravel 10 and below. This would be inline with Laravel Framework 12 being just a maintenance upgrade. Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- 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 a27e84bea4fd..3b171a3e7aba 100644 --- a/composer.json +++ b/composer.json @@ -115,7 +115,7 @@ "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^1.11.5", - "phpunit/phpunit": "^11.5.3", + "phpunit/phpunit": "^10.5.35|^11.5.3", "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", "symfony/cache": "^7.2.0", @@ -188,7 +188,7 @@ "mockery/mockery": "Required to use mocking (^1.6).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", - "phpunit/phpunit": "Required to use assertions and run tests (^11.5.3).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3).", "predis/predis": "Required to use the predis connector (^2.3).", "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 (^6.0|^7.0).", diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index 8196d3449e46..16e4e1c59cd7 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -37,7 +37,7 @@ "illuminate/database": "Required to assert databases (^12.0).", "illuminate/http": "Required to assert responses (^12.0).", "mockery/mockery": "Required to use mocking (^1.6).", - "phpunit/phpunit": "Required to use assertions and run tests (^11.5.3)." + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3)." }, "config": { "sort-packages": true From 748b738138492dbd7306c93e8d78cb6494b04c66 Mon Sep 17 00:00:00 2001 From: Alan Cole Date: Fri, 7 Feb 2025 15:07:18 +0000 Subject: [PATCH 075/455] Allow limiting the bcrypt length when hashing --- config/hashing.php | 1 + src/Illuminate/Hashing/BcryptHasher.php | 19 +++++++++++++++++++ .../Hashing/BcryptValueTooLongException.php | 13 +++++++++++++ tests/Hashing/HasherTest.php | 8 ++++++++ 4 files changed, 41 insertions(+) create mode 100644 src/Illuminate/Hashing/BcryptValueTooLongException.php diff --git a/config/hashing.php b/config/hashing.php index 9eb408e09eea..48408568809b 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -31,6 +31,7 @@ 'bcrypt' => [ 'rounds' => env('BCRYPT_ROUNDS', 12), 'verify' => env('HASH_VERIFY', true), + 'limit_length' => env('BCRYPT_LIMIT_LENGTH', true), ], /* diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index 237d588f7a29..f447e00150e4 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -8,6 +8,13 @@ class BcryptHasher extends AbstractHasher implements HasherContract { + /** + * The maximum byte length of the value to hash. + * + * @var int + */ + const MAX_BYTE_LENGTH = 72; + /** * The default cost factor. * @@ -22,6 +29,13 @@ class BcryptHasher extends AbstractHasher implements HasherContract */ protected $verifyAlgorithm = false; + /** + * Impose bcrypt byte limit. + * + * @var bool + */ + protected $limitLength = false; + /** * Create a new hasher instance. * @@ -32,6 +46,7 @@ public function __construct(array $options = []) { $this->rounds = $options['rounds'] ?? $this->rounds; $this->verifyAlgorithm = $options['verify'] ?? $this->verifyAlgorithm; + $this->limitLength = $options['limit_length'] ?? $this->limitLength; } /** @@ -46,6 +61,10 @@ public function __construct(array $options = []) public function make(#[\SensitiveParameter] $value, array $options = []) { try { + if ($this->limitLength && strlen($value) > self::MAX_BYTE_LENGTH) { + throw new BcryptValueTooLongException; + } + $hash = password_hash($value, PASSWORD_BCRYPT, [ 'cost' => $this->cost($options), ]); diff --git a/src/Illuminate/Hashing/BcryptValueTooLongException.php b/src/Illuminate/Hashing/BcryptValueTooLongException.php new file mode 100644 index 000000000000..af086b200a4a --- /dev/null +++ b/src/Illuminate/Hashing/BcryptValueTooLongException.php @@ -0,0 +1,13 @@ +assertTrue($this->hashManager->isHashed($value)); } + public function testBcryptValueTooLong() + { + $this->expectException(BcryptValueTooLongException::class); + $hasher = new BcryptHasher(['limit_length' => true]); + $hasher->make(str_repeat('a', 73)); + } + public function testBasicArgon2iHashing() { $hasher = new ArgonHasher; From 6f03e9eda953584776dd7e31ae7ba98fff1c60ea Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 10 Feb 2025 05:47:39 -0600 Subject: [PATCH 076/455] formatting --- config/hashing.php | 2 +- src/Illuminate/Hashing/BcryptHasher.php | 20 +++++++------------ .../Hashing/BcryptValueTooLongException.php | 13 ------------ tests/Hashing/HasherTest.php | 4 ++-- 4 files changed, 10 insertions(+), 29 deletions(-) delete mode 100644 src/Illuminate/Hashing/BcryptValueTooLongException.php diff --git a/config/hashing.php b/config/hashing.php index 48408568809b..fff1c0058817 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -31,7 +31,7 @@ 'bcrypt' => [ 'rounds' => env('BCRYPT_ROUNDS', 12), 'verify' => env('HASH_VERIFY', true), - 'limit_length' => env('BCRYPT_LIMIT_LENGTH', true), + 'limit' => env('BCRYPT_LIMIT', 72), ], /* diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index f447e00150e4..18df9c221a38 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -4,17 +4,11 @@ use Error; use Illuminate\Contracts\Hashing\Hasher as HasherContract; +use InvalidArgumentException; use RuntimeException; class BcryptHasher extends AbstractHasher implements HasherContract { - /** - * The maximum byte length of the value to hash. - * - * @var int - */ - const MAX_BYTE_LENGTH = 72; - /** * The default cost factor. * @@ -30,11 +24,11 @@ class BcryptHasher extends AbstractHasher implements HasherContract protected $verifyAlgorithm = false; /** - * Impose bcrypt byte limit. + * The maximum allowed length of strings that can be hashed. * - * @var bool + * @var int|null */ - protected $limitLength = false; + protected $limit; /** * Create a new hasher instance. @@ -46,7 +40,7 @@ public function __construct(array $options = []) { $this->rounds = $options['rounds'] ?? $this->rounds; $this->verifyAlgorithm = $options['verify'] ?? $this->verifyAlgorithm; - $this->limitLength = $options['limit_length'] ?? $this->limitLength; + $this->limit = $options['limit'] ?? $this->limit; } /** @@ -61,8 +55,8 @@ public function __construct(array $options = []) public function make(#[\SensitiveParameter] $value, array $options = []) { try { - if ($this->limitLength && strlen($value) > self::MAX_BYTE_LENGTH) { - throw new BcryptValueTooLongException; + if ($this->limit && strlen($value) > $this->limit) { + throw new InvalidArgumentException('Value is too long to hash. Value must be less than '.$this->limit.' bytes.'); } $hash = password_hash($value, PASSWORD_BCRYPT, [ diff --git a/src/Illuminate/Hashing/BcryptValueTooLongException.php b/src/Illuminate/Hashing/BcryptValueTooLongException.php deleted file mode 100644 index af086b200a4a..000000000000 --- a/src/Illuminate/Hashing/BcryptValueTooLongException.php +++ /dev/null @@ -1,13 +0,0 @@ -expectException(BcryptValueTooLongException::class); - $hasher = new BcryptHasher(['limit_length' => true]); + $this->expectException(\InvalidArgumentException::class); + $hasher = new BcryptHasher(['limit' => 72]); $hasher->make(str_repeat('a', 73)); } From 1816d7bb391855ab2a784c7597f7a6dff60c21ad Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 10 Feb 2025 11:48:14 +0000 Subject: [PATCH 077/455] Apply fixes from StyleCI --- tests/Hashing/HasherTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Hashing/HasherTest.php b/tests/Hashing/HasherTest.php index 400ec8bd15e1..2547a9fea588 100755 --- a/tests/Hashing/HasherTest.php +++ b/tests/Hashing/HasherTest.php @@ -7,7 +7,6 @@ use Illuminate\Hashing\Argon2IdHasher; use Illuminate\Hashing\ArgonHasher; use Illuminate\Hashing\BcryptHasher; -use Illuminate\Hashing\BcryptValueTooLongException; use Illuminate\Hashing\HashManager; use PHPUnit\Framework\Attributes\Depends; use PHPUnit\Framework\TestCase; From b6406fc7ccc0ab4cb0be764ae766c5d4e9a4d1b8 Mon Sep 17 00:00:00 2001 From: crynobone <172966+crynobone@users.noreply.github.com> Date: Wed, 12 Feb 2025 02:38:31 +0000 Subject: [PATCH 078/455] Update facade docblocks --- src/Illuminate/Support/Facades/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index 5a0e6044fdf1..fbf1035e54e6 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -112,7 +112,7 @@ * @method static void scoped(string $abstract, \Closure|string|null $concrete = null) * @method static void scopedIf(string $abstract, \Closure|string|null $concrete = null) * @method static void extend(string $abstract, \Closure $closure) - * @method static void instance(string $abstract, void $instance) + * @method static mixed instance(string $abstract, mixed $instance) * @method static void tag(array|string $abstracts, array|mixed $tags) * @method static iterable tagged(string $tag) * @method static void alias(string $abstract, string $alias) From 96e75027b249e3ff85201d20ab61ff103e6e5c62 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 12 Feb 2025 10:43:41 +0800 Subject: [PATCH 079/455] chore: Update `queues.yml` Signed-off-by: Mior Muhammad Zaki --- .github/workflows/queues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/queues.yml b/.github/workflows/queues.yml index fe72df206be7..2302892a3d38 100644 --- a/.github/workflows/queues.yml +++ b/.github/workflows/queues.yml @@ -150,7 +150,7 @@ jobs: coverage: none - name: Set Framework version - run: composer config version "11.x-dev" + run: composer config version "12.x-dev" - name: Install dependencies uses: nick-fields/retry@v3 From a4864ff916a3daa1d5baa7fdabc3ec127b541822 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 12 Feb 2025 10:03:04 -0600 Subject: [PATCH 080/455] default limit to null --- config/hashing.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/hashing.php b/config/hashing.php index fff1c0058817..356ec108dbe4 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -31,7 +31,7 @@ 'bcrypt' => [ 'rounds' => env('BCRYPT_ROUNDS', 12), 'verify' => env('HASH_VERIFY', true), - 'limit' => env('BCRYPT_LIMIT', 72), + 'limit' => env('BCRYPT_LIMIT', null), ], /* From c78fa3d0684206f721b9a3b76e8c596aa8a08cd0 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 12 Feb 2025 20:00:57 +0330 Subject: [PATCH 081/455] [12.x] Fix accessing `Connection` property in `Grammar` classes (#54487) * fix connection references * formatting * formatting * formatting --- config/database.php | 1 + src/Illuminate/Database/Connection.php | 21 +-- src/Illuminate/Database/Grammar.php | 48 +++--- src/Illuminate/Database/MariaDbConnection.php | 8 +- src/Illuminate/Database/MySqlConnection.php | 8 +- .../Database/PostgresConnection.php | 8 +- .../Database/Query/Grammars/SQLiteGrammar.php | 4 +- src/Illuminate/Database/SQLiteConnection.php | 8 +- src/Illuminate/Database/Schema/Blueprint.php | 32 ++-- .../Database/Schema/BlueprintState.php | 12 +- src/Illuminate/Database/Schema/Builder.php | 31 +--- .../Database/Schema/Grammars/Grammar.php | 29 ++-- .../Schema/Grammars/MariaDbGrammar.php | 10 +- .../Database/Schema/Grammars/MySqlGrammar.php | 87 ++++------ .../Schema/Grammars/PostgresGrammar.php | 45 ++---- .../Schema/Grammars/SQLiteGrammar.php | 34 ++-- .../Schema/Grammars/SqlServerGrammar.php | 38 +---- .../Database/Schema/MySqlBuilder.php | 26 --- .../Database/Schema/PostgresBuilder.php | 26 --- .../Database/Schema/SQLiteBuilder.php | 4 +- .../Database/Schema/SqlServerBuilder.php | 26 --- .../Database/SqlServerConnection.php | 8 +- src/Illuminate/Support/Facades/DB.php | 1 - .../DatabaseAbstractSchemaGrammarTest.php | 17 +- ...EloquentBelongsToManyCreateOrFirstTest.php | 8 +- ...tabaseEloquentBuilderCreateOrFirstTest.php | 8 +- .../Database/DatabaseEloquentBuilderTest.php | 40 +++-- ...tabaseEloquentHasManyCreateOrFirstTest.php | 8 +- ...loquentHasManyThroughCreateOrFirstTest.php | 8 +- tests/Database/DatabaseMariaDbBuilderTest.php | 10 +- .../DatabaseMariaDbQueryGrammarTest.php | 3 +- .../DatabaseMariaDbSchemaGrammarTest.php | 28 ++-- tests/Database/DatabaseMySqlBuilderTest.php | 8 +- .../DatabaseMySqlQueryGrammarTest.php | 3 +- .../DatabaseMySqlSchemaGrammarTest.php | 24 +-- .../Database/DatabasePostgresBuilderTest.php | 8 +- .../DatabasePostgresQueryGrammarTest.php | 11 +- .../DatabasePostgresSchemaGrammarTest.php | 37 +++-- tests/Database/DatabaseQueryBuilderTest.php | 151 +++++++++--------- tests/Database/DatabaseQueryGrammarTest.php | 5 +- .../DatabaseSQLiteQueryGrammarTest.php | 3 +- .../DatabaseSQLiteSchemaGrammarTest.php | 2 +- .../Database/DatabaseSchemaBlueprintTest.php | 151 ++++++++---------- tests/Database/DatabaseSchemaBuilderTest.php | 15 +- .../DatabaseSqlServerQueryGrammarTest.php | 3 +- .../DatabaseSqlServerSchemaGrammarTest.php | 27 ++-- tests/Database/SqlServerBuilderTest.php | 8 +- .../Sqlite/DatabaseSchemaBlueprintTest.php | 75 +++++---- .../Concerns/InteractsWithDatabaseTest.php | 21 ++- 49 files changed, 479 insertions(+), 718 deletions(-) diff --git a/config/database.php b/config/database.php index 125949ed5a15..1b1ce4d99003 100644 --- a/config/database.php +++ b/config/database.php @@ -36,6 +36,7 @@ 'url' => env('DB_URL'), 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', + 'prefix_indexes' => null, 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 'busy_timeout' => null, 'journal_mode' => null, diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 8dd7213117c4..69780f78a2b4 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -248,9 +248,7 @@ public function useDefaultQueryGrammar() */ protected function getDefaultQueryGrammar() { - ($grammar = new QueryGrammar)->setConnection($this); - - return $grammar; + return new QueryGrammar($this); } /** @@ -1626,26 +1624,9 @@ public function setTablePrefix($prefix) { $this->tablePrefix = $prefix; - $this->getQueryGrammar()->setTablePrefix($prefix); - return $this; } - /** - * Set the table prefix and return the grammar. - * - * @template TGrammar of \Illuminate\Database\Grammar - * - * @param TGrammar $grammar - * @return TGrammar - */ - public function withTablePrefix(Grammar $grammar) - { - $grammar->setTablePrefix($this->tablePrefix); - - return $grammar; - } - /** * Execute the given callback without table prefix. * diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 187d1348ad30..4ff5ddc34a17 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -19,11 +19,15 @@ abstract class Grammar protected $connection; /** - * The grammar table prefix. + * Create a new grammar instance. * - * @var string + * @param \Illuminate\Database\Connection $connection + * @return void */ - protected $tablePrefix = ''; + public function __construct(Connection $connection) + { + $this->connection = $connection; + } /** * Wrap an array of values. @@ -49,15 +53,15 @@ public function wrapTable($table, $prefix = null) return $this->getValue($table); } + $prefix ??= $this->connection->getTablePrefix(); + // If the table being wrapped has an alias we'll need to separate the pieces // so we can prefix the table and then wrap each of the segments on their // own and then join these both back together using the "as" connector. if (stripos($table, ' as ') !== false) { - return $this->wrapAliasedTable($table); + return $this->wrapAliasedTable($table, $prefix); } - $prefix ??= $this->tablePrefix; - // If the table being wrapped has a custom schema name specified, we need to // prefix the last segment as the table name then wrap each segment alone // and eventually join them both back together using the dot connector. @@ -118,13 +122,16 @@ protected function wrapAliasedValue($value) * Wrap a table that has an alias. * * @param string $value + * @param string|null $prefix * @return string */ - protected function wrapAliasedTable($value) + protected function wrapAliasedTable($value, $prefix = null) { $segments = preg_split('/\s+as\s+/i', $value); - return $this->wrapTable($segments[0]).' as '.$this->wrapValue($this->tablePrefix.$segments[1]); + $prefix ??= $this->connection->getTablePrefix(); + + return $this->wrapTable($segments[0], $prefix).' as '.$this->wrapValue($prefix.$segments[1]); } /** @@ -238,10 +245,6 @@ public function quoteString($value) */ public function escape($value, $binary = false) { - if (is_null($this->connection)) { - throw new RuntimeException("The database driver's grammar implementation does not support escaping values."); - } - return $this->connection->escape($value, $binary); } @@ -284,35 +287,26 @@ public function getDateFormat() /** * Get the grammar's table prefix. * + * @deprecated Use DB::getTablePrefix() + * * @return string */ public function getTablePrefix() { - return $this->tablePrefix; + return $this->connection->getTablePrefix(); } /** * Set the grammar's table prefix. * + * @deprecated Use DB::setTablePrefix() + * * @param string $prefix * @return $this */ public function setTablePrefix($prefix) { - $this->tablePrefix = $prefix; - - return $this; - } - - /** - * Set the grammar's database connection. - * - * @param \Illuminate\Database\Connection $connection - * @return $this - */ - public function setConnection($connection) - { - $this->connection = $connection; + $this->connection->setTablePrefix($prefix); return $this; } diff --git a/src/Illuminate/Database/MariaDbConnection.php b/src/Illuminate/Database/MariaDbConnection.php index ebd33a15b9b5..c4040b6c34ad 100755 --- a/src/Illuminate/Database/MariaDbConnection.php +++ b/src/Illuminate/Database/MariaDbConnection.php @@ -47,9 +47,7 @@ public function getServerVersion(): string */ protected function getDefaultQueryGrammar() { - ($grammar = new QueryGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new QueryGrammar($this); } /** @@ -73,9 +71,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - ($grammar = new SchemaGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new SchemaGrammar($this); } /** diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index abc1edb4f831..54c1aff0b7e9 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -121,9 +121,7 @@ public function getServerVersion(): string */ protected function getDefaultQueryGrammar() { - ($grammar = new QueryGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new QueryGrammar($this); } /** @@ -147,9 +145,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - ($grammar = new SchemaGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new SchemaGrammar($this); } /** diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index 06fa2e1d8e48..f80b5dce5df1 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -62,9 +62,7 @@ protected function isUniqueConstraintError(Exception $exception) */ protected function getDefaultQueryGrammar() { - ($grammar = new QueryGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new QueryGrammar($this); } /** @@ -88,9 +86,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - ($grammar = new SchemaGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new SchemaGrammar($this); } /** diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index 6dc65a07c034..e3983855e6b5 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -439,12 +439,12 @@ protected function compileDeleteWithJoinsOrLimit(Builder $query) */ public function compileTruncate(Builder $query) { - [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($query->from); + [$schema, $table] = $query->getConnection()->getSchemaBuilder()->parseSchemaAndTable($query->from); $schema = $schema ? $this->wrapValue($schema).'.' : ''; return [ - 'delete from '.$schema.'sqlite_sequence where name = ?' => [$this->getTablePrefix().$table], + 'delete from '.$schema.'sqlite_sequence where name = ?' => [$query->getConnection()->getTablePrefix().$table], 'delete from '.$this->wrapTable($query->from) => [], ]; } diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index bccd33118118..997afb3934e6 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -162,9 +162,7 @@ protected function isUniqueConstraintError(Exception $exception) */ protected function getDefaultQueryGrammar() { - ($grammar = new QueryGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new QueryGrammar($this); } /** @@ -188,9 +186,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - ($grammar = new SchemaGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new SchemaGrammar($this); } /** diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 729a7dce67ef..f21962dd9528 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -34,13 +34,6 @@ class Blueprint */ protected $table; - /** - * The prefix of the table. - * - * @var string - */ - protected $prefix; - /** * The columns that should be added to the table. * @@ -103,15 +96,13 @@ class Blueprint * @param \Illuminate\Database\Connection $connection * @param string $table * @param \Closure|null $callback - * @param string $prefix * @return void */ - public function __construct(Connection $connection, $table, ?Closure $callback = null, $prefix = '') + public function __construct(Connection $connection, $table, ?Closure $callback = null) { $this->connection = $connection; $this->grammar = $connection->getSchemaGrammar(); $this->table = $table; - $this->prefix = $prefix; if (! is_null($callback)) { $callback($this); @@ -158,7 +149,7 @@ public function toSql() $this->state->update($command); } - if (! is_null($sql = $this->grammar->$method($this, $command, $this->connection))) { + if (! is_null($sql = $this->grammar->$method($this, $command))) { $statements = array_merge($statements, (array) $sql); } } @@ -290,7 +281,7 @@ public function addAlterCommands() return; } - $alterCommands = $this->grammar->getAlterCommands($this->connection); + $alterCommands = $this->grammar->getAlterCommands(); [$commands, $lastCommandWasAlter, $hasAlterCommand] = [ [], false, false, @@ -313,7 +304,7 @@ public function addAlterCommands() } if ($hasAlterCommand) { - $this->state = new BlueprintState($this, $this->connection, $this->grammar); + $this->state = new BlueprintState($this, $this->connection); } $this->commands = $commands; @@ -1703,9 +1694,13 @@ protected function dropIndexCommand($command, $type, $index) */ protected function createIndexName($type, array $columns) { - $table = str_contains($this->table, '.') - ? substr_replace($this->table, '.'.$this->prefix, strrpos($this->table, '.'), 1) - : $this->prefix.$this->table; + $table = $this->table; + + if ($this->connection->getConfig('prefix_indexes')) { + $table = str_contains($this->table, '.') + ? substr_replace($this->table, '.'.$this->connection->getTablePrefix(), strrpos($this->table, '.'), 1) + : $this->connection->getTablePrefix().$this->table; + } $index = strtolower($table.'_'.implode('_', $columns).'_'.$type); @@ -1824,11 +1819,13 @@ public function getTable() /** * Get the table prefix. * + * @deprecated Use DB::getTablePrefix() + * * @return string */ public function getPrefix() { - return $this->prefix; + return $this->connection->getTablePrefix(); } /** @@ -1854,7 +1851,6 @@ public function getCommands() /** * Determine if the blueprint has state. * - * @param mixed $name * @return bool */ private function hasState(): bool diff --git a/src/Illuminate/Database/Schema/BlueprintState.php b/src/Illuminate/Database/Schema/BlueprintState.php index 4a2ea127a97a..c804e778fd81 100644 --- a/src/Illuminate/Database/Schema/BlueprintState.php +++ b/src/Illuminate/Database/Schema/BlueprintState.php @@ -4,7 +4,6 @@ use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; -use Illuminate\Database\Schema\Grammars\Grammar; use Illuminate\Support\Collection; use Illuminate\Support\Fluent; use Illuminate\Support\Str; @@ -25,13 +24,6 @@ class BlueprintState */ protected $connection; - /** - * The grammar instance. - * - * @var \Illuminate\Database\Schema\Grammars\Grammar - */ - protected $grammar; - /** * The columns. * @@ -65,14 +57,12 @@ class BlueprintState * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Database\Connection $connection - * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar * @return void */ - public function __construct(Blueprint $blueprint, Connection $connection, Grammar $grammar) + public function __construct(Blueprint $blueprint, Connection $connection) { $this->blueprint = $blueprint; $this->connection = $connection; - $this->grammar = $grammar; $schema = $connection->getSchemaBuilder(); $table = $blueprint->getTable(); diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index a42f9f28802b..5f1fa7afc69a 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -126,12 +126,12 @@ public static function morphUsingUlids() * * @param string $name * @return bool - * - * @throws \LogicException */ public function createDatabase($name) { - throw new LogicException('This database driver does not support creating databases.'); + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name) + ); } /** @@ -139,12 +139,12 @@ public function createDatabase($name) * * @param string $name * @return bool - * - * @throws \LogicException */ public function dropDatabaseIfExists($name) { - throw new LogicException('This database driver does not support dropping databases.'); + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); } /** @@ -630,13 +630,11 @@ protected function createBlueprint($table, ?Closure $callback = null) { $connection = $this->connection; - $prefix = $connection->getConfig('prefix_indexes') ? $connection->getConfig('prefix') : ''; - if (isset($this->resolver)) { - return call_user_func($this->resolver, $connection, $table, $callback, $prefix); + return call_user_func($this->resolver, $connection, $table, $callback); } - return Container::getInstance()->make(Blueprint::class, compact('connection', 'table', 'callback', 'prefix')); + return Container::getInstance()->make(Blueprint::class, compact('connection', 'table', 'callback')); } /** @@ -698,19 +696,6 @@ public function getConnection() return $this->connection; } - /** - * Set the database connection instance. - * - * @param \Illuminate\Database\Connection $connection - * @return $this - */ - public function setConnection(Connection $connection) - { - $this->connection = $connection; - - return $this; - } - /** * Set the Schema Blueprint resolver callback. * diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index fd78be04e96c..92ccf334ad86 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -5,11 +5,9 @@ use BackedEnum; use Illuminate\Contracts\Database\Query\Expression; use Illuminate\Database\Concerns\CompilesJsonPaths; -use Illuminate\Database\Connection; use Illuminate\Database\Grammar as BaseGrammar; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; -use LogicException; use RuntimeException; abstract class Grammar extends BaseGrammar @@ -41,27 +39,26 @@ abstract class Grammar extends BaseGrammar * Compile a create database command. * * @param string $name - * @param \Illuminate\Database\Connection $connection - * @return void - * - * @throws \LogicException + * @return string */ - public function compileCreateDatabase($name, $connection) + public function compileCreateDatabase($name) { - throw new LogicException('This database driver does not support creating databases.'); + return sprintf('create database %s', + $this->wrapValue($name), + ); } /** * Compile a drop database if exists command. * * @param string $name - * @return void - * - * @throws \LogicException + * @return string */ public function compileDropDatabaseIfExists($name) { - throw new LogicException('This database driver does not support dropping databases.'); + return sprintf('drop database if exists %s', + $this->wrapValue($name) + ); } /** @@ -172,10 +169,9 @@ public function compileForeignKeys($schema, $table) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string */ - public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { return sprintf('alter table %s rename column %s to %s', $this->wrapTable($blueprint), @@ -189,14 +185,13 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string * * @throws \RuntimeException */ - public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileChange(Blueprint $blueprint, Fluent $command) { - throw new LogicException('This database driver does not support modifying columns.'); + throw new RuntimeException('This database driver does not support modifying columns.'); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php index 2996406a27fb..5bf769843e68 100755 --- a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php @@ -2,7 +2,6 @@ namespace Illuminate\Database\Schema\Grammars; -use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; @@ -13,16 +12,15 @@ class MariaDbGrammar extends MySqlGrammar * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string */ - public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { - if (version_compare($connection->getServerVersion(), '10.5.2', '<')) { - return $this->compileLegacyRenameColumn($blueprint, $command, $connection); + if (version_compare($this->connection->getServerVersion(), '10.5.2', '<')) { + return $this->compileLegacyRenameColumn($blueprint, $command); } - return parent::compileRenameColumn($blueprint, $command, $connection); + return parent::compileRenameColumn($blueprint, $command); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 5012fa4d48d3..938a18856e32 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -2,7 +2,6 @@ namespace Illuminate\Database\Schema\Grammars; -use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\ColumnDefinition; @@ -40,41 +39,21 @@ class MySqlGrammar extends Grammar * Compile a create database command. * * @param string $name - * @param \Illuminate\Database\Connection $connection * @return string */ - public function compileCreateDatabase($name, $connection) + public function compileCreateDatabase($name) { - $charset = $connection->getConfig('charset'); - $collation = $connection->getConfig('collation'); + $sql = parent::compileCreateDatabase($name); - if (! $charset || ! $collation) { - return sprintf( - 'create database %s', - $this->wrapValue($name), - ); + if ($charset = $this->connection->getConfig('charset')) { + $sql .= sprintf(' default character set %s', $this->wrapValue($charset)); } - return sprintf( - 'create database %s default character set %s default collate %s', - $this->wrapValue($name), - $this->wrapValue($charset), - $this->wrapValue($collation), - ); - } + if ($collation = $this->connection->getConfig('collation')) { + $sql .= sprintf(' default collate %s', $this->wrapValue($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) - ); + return $sql; } /** @@ -225,26 +204,25 @@ public function compileForeignKeys($schema, $table) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return string */ - public function compileCreate(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileCreate(Blueprint $blueprint, Fluent $command) { $sql = $this->compileCreateTable( - $blueprint, $command, $connection + $blueprint, $command ); // Once we have the primary SQL, we can add the encoding option to the SQL for // the table. Then, we can check if a storage engine has been supplied for // the table. If so, we will add the engine declaration to the SQL query. $sql = $this->compileCreateEncoding( - $sql, $connection, $blueprint + $sql, $blueprint ); // Finally, we will append the engine configuration onto this SQL statement as // the final thing we do before returning this finished SQL. Once this gets // added the query will be ready to execute against the real connections. - return $this->compileCreateEngine($sql, $connection, $blueprint); + return $this->compileCreateEngine($sql, $blueprint); } /** @@ -252,10 +230,9 @@ public function compileCreate(Blueprint $blueprint, Fluent $command, Connection * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return string */ - protected function compileCreateTable($blueprint, $command, $connection) + protected function compileCreateTable($blueprint, $command) { $tableStructure = $this->getColumns($blueprint); @@ -280,18 +257,17 @@ protected function compileCreateTable($blueprint, $command, $connection) * Append the character set specifications to a command. * * @param string $sql - * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return string */ - protected function compileCreateEncoding($sql, Connection $connection, Blueprint $blueprint) + protected function compileCreateEncoding($sql, Blueprint $blueprint) { // First we will set the character set if one has been set on either the create // blueprint itself or on the root configuration for the connection that the // table is being created on. We will add these to the create table query. if (isset($blueprint->charset)) { $sql .= ' default character set '.$blueprint->charset; - } elseif (! is_null($charset = $connection->getConfig('charset'))) { + } elseif (! is_null($charset = $this->connection->getConfig('charset'))) { $sql .= ' default character set '.$charset; } @@ -300,7 +276,7 @@ protected function compileCreateEncoding($sql, Connection $connection, Blueprint // connection that the query is targeting. We'll add it to this SQL query. if (isset($blueprint->collation)) { $sql .= " collate '{$blueprint->collation}'"; - } elseif (! is_null($collation = $connection->getConfig('collation'))) { + } elseif (! is_null($collation = $this->connection->getConfig('collation'))) { $sql .= " collate '{$collation}'"; } @@ -311,15 +287,14 @@ protected function compileCreateEncoding($sql, Connection $connection, Blueprint * Append the engine specifications to a command. * * @param string $sql - * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return string */ - protected function compileCreateEngine($sql, Connection $connection, Blueprint $blueprint) + protected function compileCreateEngine($sql, Blueprint $blueprint) { if (isset($blueprint->engine)) { return $sql.' engine = '.$blueprint->engine; - } elseif (! is_null($engine = $connection->getConfig('engine'))) { + } elseif (! is_null($engine = $this->connection->getConfig('engine'))) { return $sql.' engine = '.$engine; } @@ -361,19 +336,19 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string */ - public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { - $version = $connection->getServerVersion(); + $isMaria = $this->connection->isMaria(); + $version = $this->connection->getServerVersion(); - if (($connection->isMaria() && version_compare($version, '10.5.2', '<')) || - (! $connection->isMaria() && version_compare($version, '8.0.3', '<'))) { - return $this->compileLegacyRenameColumn($blueprint, $command, $connection); + if (($isMaria && version_compare($version, '10.5.2', '<')) || + (! $isMaria && version_compare($version, '8.0.3', '<'))) { + return $this->compileLegacyRenameColumn($blueprint, $command); } - return parent::compileRenameColumn($blueprint, $command, $connection); + return parent::compileRenameColumn($blueprint, $command); } /** @@ -381,12 +356,11 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return string */ - protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $command) { - $column = (new Collection($connection->getSchemaBuilder()->getColumns($blueprint->getTable()))) + $column = (new Collection($this->connection->getSchemaBuilder()->getColumns($blueprint->getTable()))) ->firstWhere('name', $command->from); $modifiers = $this->addModifiers($column['type'], $blueprint, new ColumnDefinition([ @@ -425,12 +399,9 @@ protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $comma * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string - * - * @throws \RuntimeException */ - public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileChange(Blueprint $blueprint, Fluent $command) { $column = $command->column; @@ -1117,7 +1088,7 @@ protected function typeGeometry(Fluent $column) return sprintf('%s%s', $subtype ?? 'geometry', match (true) { - $column->srid && $this->connection?->isMaria() => ' ref_system_id='.$column->srid, + $column->srid && $this->connection->isMaria() => ' ref_system_id='.$column->srid, (bool) $column->srid => ' srid '.$column->srid, default => '', } diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 8a2ccb2cff1a..21a5863f305e 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -2,7 +2,6 @@ namespace Illuminate\Database\Schema\Grammars; -use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Collection; @@ -43,30 +42,17 @@ class PostgresGrammar extends Grammar * Compile a create database command. * * @param string $name - * @param \Illuminate\Database\Connection $connection * @return string */ - public function compileCreateDatabase($name, $connection) + public function compileCreateDatabase($name) { - return sprintf( - 'create database %s encoding %s', - $this->wrapValue($name), - $this->wrapValue($connection->getConfig('charset')), - ); - } + $sql = parent::compileCreateDatabase($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) - ); + if ($charset = $this->connection->getConfig('charset')) { + $sql .= sprintf(' encoding %s', $this->wrapValue($charset)); + } + + return $sql; } /** @@ -175,7 +161,7 @@ public function compileColumns($schema, $table) .'(select tc.collcollate from pg_catalog.pg_collation tc where tc.oid = a.attcollation) as collation, ' .'not a.attnotnull as nullable, ' .'(select pg_get_expr(adbin, adrelid) from pg_attrdef where c.oid = pg_attrdef.adrelid and pg_attrdef.adnum = a.attnum) as default, ' - .(version_compare($this->connection?->getServerVersion(), '12.0', '<') ? "'' as generated, " : 'a.attgenerated as generated, ') + .(version_compare($this->connection->getServerVersion(), '12.0', '<') ? "'' as generated, " : 'a.attgenerated as generated, ') .'col_description(c.oid, a.attnum) as comment ' .'from pg_attribute a, pg_class c, pg_type t, pg_namespace n ' .'where c.relname = %s and n.nspname = %s and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid and n.oid = c.relnamespace ' @@ -283,9 +269,11 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent { if ($command->column->autoIncrement && $value = $command->column->get('startingValue', $command->column->get('from'))) { - $table = last(explode('.', $blueprint->getTable())); + [$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); + + $table = ($schema ? $schema.'.' : '').$this->connection->getTablePrefix().$table; - return 'alter sequence '.$blueprint->getPrefix().$table.'_'.$command->column->name.'_seq restart with '.$value; + return 'alter sequence '.$table.'_'.$command->column->name.'_seq restart with '.$value; } } @@ -294,12 +282,9 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string - * - * @throws \RuntimeException */ - public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileChange(Blueprint $blueprint, Fluent $command) { $column = $command->column; @@ -537,8 +522,8 @@ public function compileDropColumn(Blueprint $blueprint, Fluent $command) */ public function compileDropPrimary(Blueprint $blueprint, Fluent $command) { - $table = last(explode('.', $blueprint->getTable())); - $index = $this->wrap("{$blueprint->getPrefix()}{$table}_pkey"); + [, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); + $index = $this->wrap("{$this->connection->getTablePrefix()}{$table}_pkey"); return 'alter table '.$this->wrapTable($blueprint)." drop constraint {$index}"; } diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index dc37b26d5730..6f4b7c49217f 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -2,7 +2,6 @@ namespace Illuminate\Database\Schema\Grammars; -use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\IndexDefinition; @@ -30,14 +29,13 @@ class SQLiteGrammar extends Grammar /** * Get the commands to be compiled on the alter command. * - * @param \Illuminate\Database\Connection $connection * @return array */ - public function getAlterCommands(Connection $connection) + public function getAlterCommands() { $alterCommands = ['change', 'primary', 'dropPrimary', 'foreign', 'dropForeign']; - if (version_compare($connection->getServerVersion(), '3.35', '<')) { + if (version_compare($this->connection->getServerVersion(), '3.35', '<')) { $alterCommands[] = 'dropColumn'; } @@ -123,7 +121,7 @@ public function compileTables($schema, $withSize = false) /** * Compile the query for legacy versions of SQLite to determine the tables. * - * @param string|string[]|null $schema + * @param string $schema * @param bool $withSize * @return string */ @@ -321,12 +319,9 @@ public function compileAdd(Blueprint $blueprint, Fluent $command) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string - * - * @throws \RuntimeException */ - public function compileAlter(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileAlter(Blueprint $blueprint, Fluent $command) { $columnNames = []; $autoIncrementColumn = null; @@ -354,12 +349,12 @@ public function compileAlter(Blueprint $blueprint, Fluent $command, Connection $ ->map(fn ($index) => $this->{'compile'.ucfirst($index->name)}($blueprint, $index)) ->all(); - [, $tableName] = $connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); - $tempTable = $this->wrapTable($blueprint, '__temp__'.$connection->getTablePrefix()); + [, $tableName] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($blueprint->getTable()); + $tempTable = $this->wrapTable($blueprint, '__temp__'.$this->connection->getTablePrefix()); $table = $this->wrapTable($blueprint); $columnNames = implode(', ', $columnNames); - $foreignKeyConstraintsEnabled = $connection->scalar('pragma foreign_keys'); + $foreignKeyConstraintsEnabled = $this->connection->scalar('pragma foreign_keys'); return array_filter(array_merge([ $foreignKeyConstraintsEnabled ? $this->compileDisableForeignKeyConstraints() : null, @@ -380,12 +375,9 @@ public function compileAlter(Blueprint $blueprint, Fluent $command, Connection $ * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string - * - * @throws \RuntimeException */ - public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileChange(Blueprint $blueprint, Fluent $command) { // Handled on table alteration... } @@ -531,12 +523,11 @@ public function compileRebuild() * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|null */ - public function compileDropColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileDropColumn(Blueprint $blueprint, Fluent $command) { - if (version_compare($connection->getServerVersion(), '3.35', '<')) { + if (version_compare($this->connection->getServerVersion(), '3.35', '<')) { // Handled on table alteration... return null; @@ -639,14 +630,13 @@ public function compileRename(Blueprint $blueprint, Fluent $command) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array * * @throws \RuntimeException */ - public function compileRenameIndex(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileRenameIndex(Blueprint $blueprint, Fluent $command) { - $indexes = $connection->getSchemaBuilder()->getIndexes($blueprint->getTable()); + $indexes = $this->connection->getSchemaBuilder()->getIndexes($blueprint->getTable()); $index = Arr::first($indexes, fn ($index) => $index['name'] === $command->from); diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 6333b23e6118..b387b3a4d42d 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -2,7 +2,6 @@ namespace Illuminate\Database\Schema\Grammars; -use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; @@ -37,35 +36,6 @@ class SqlServerGrammar extends Grammar */ protected $fluentCommands = ['Default']; - /** - * 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 the schemas. * @@ -261,10 +231,9 @@ public function compileAdd(Blueprint $blueprint, Fluent $command) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string */ - public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { return sprintf("sp_rename %s, %s, N'COLUMN'", $this->quoteString($this->wrapTable($blueprint).'.'.$this->wrap($command->from)), @@ -277,12 +246,9 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @param \Illuminate\Database\Connection $connection * @return array|string - * - * @throws \RuntimeException */ - public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) + public function compileChange(Blueprint $blueprint, Fluent $command) { return [ $this->compileDropDefaultConstraint($blueprint, $command), diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index b55f324b69e1..6676411225ea 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -4,32 +4,6 @@ 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) - ); - } - /** * Drop all tables from the database. * diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index f8b88d5b003a..66f311742708 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -8,32 +8,6 @@ class PostgresBuilder extends Builder { use ParsesSearchPath; - /** - * 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/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index af49bae8126e..6e818c37db9c 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -27,9 +27,7 @@ public function createDatabase($name) */ public function dropDatabaseIfExists($name) { - return File::exists($name) - ? File::delete($name) - : true; + return ! File::exists($name) || File::delete($name); } /** diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index 1cbc5afa7692..9161bc61af7c 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -6,32 +6,6 @@ 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/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index 19f7bb8afbf3..1e6fe52bfe16 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -93,9 +93,7 @@ protected function isUniqueConstraintError(Exception $exception) */ protected function getDefaultQueryGrammar() { - ($grammar = new QueryGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new QueryGrammar($this); } /** @@ -119,9 +117,7 @@ public function getSchemaBuilder() */ protected function getDefaultSchemaGrammar() { - ($grammar = new SchemaGrammar)->setConnection($this); - - return $this->withTablePrefix($grammar); + return new SchemaGrammar($this); } /** diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 3e645ac530f5..3ddeae76298a 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -104,7 +104,6 @@ * @method static \Illuminate\Database\Connection setReadWriteType(string|null $readWriteType) * @method static string getTablePrefix() * @method static \Illuminate\Database\Connection setTablePrefix(string $prefix) - * @method static \Illuminate\Database\Grammar withTablePrefix(\Illuminate\Database\Grammar $grammar) * @method static mixed withoutTablePrefix(\Closure $callback) * @method static string getServerVersion() * @method static void resolverFor(string $driver, \Closure $callback) diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php index 04e23eb264be..3eeee6beb228 100755 --- a/tests/Database/DatabaseAbstractSchemaGrammarTest.php +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -4,7 +4,6 @@ use Illuminate\Database\Connection; use Illuminate\Database\Schema\Grammars\Grammar; -use LogicException; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -17,21 +16,17 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new class extends Grammar {}; + $connection = m::mock(Connection::class); + $grammar = new class($connection) extends Grammar {}; - $this->expectException(LogicException::class); - $this->expectExceptionMessage('This database driver does not support creating databases.'); - - $grammar->compileCreateDatabase('foo', m::mock(Connection::class)); + $this->assertSame('create database "foo"', $grammar->compileCreateDatabase('foo')); } public function testDropDatabaseIfExists() { - $grammar = new class extends Grammar {}; - - $this->expectException(LogicException::class); - $this->expectExceptionMessage('This database driver does not support dropping databases.'); + $connection = m::mock(Connection::class); + $grammar = new class($connection) extends Grammar {}; - $grammar->compileDropDatabaseIfExists('foo'); + $this->assertSame('drop database if exists "foo"', $grammar->compileDropDatabaseIfExists('foo')); } } diff --git a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php index 3ea77e45aedc..8fb7dab36607 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php @@ -5,7 +5,7 @@ namespace Illuminate\Tests\Database; use Exception; -use Illuminate\Database\ConnectionInterface; +use Illuminate\Database\Connection; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; @@ -450,9 +450,11 @@ protected function mockConnectionForModels(array $models, string $database, arra { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; $processorClass = 'Illuminate\Database\Query\Processors\\'.$database.'Processor'; - $grammar = new $grammarClass; $processor = new $processorClass; - $connection = Mockery::mock(ConnectionInterface::class, ['getQueryGrammar' => $grammar, 'getPostProcessor' => $processor]); + $connection = Mockery::mock(Connection::class, ['getPostProcessor' => $processor]); + $grammar = new $grammarClass($connection); + $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); $connection->shouldReceive('query')->andReturnUsing(function () use ($connection, $grammar, $processor) { return new BaseBuilder($connection, $grammar, $processor); }); diff --git a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php index b629194b6ea6..63cffe311f53 100755 --- a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php @@ -3,7 +3,7 @@ namespace Illuminate\Tests\Database; use Exception; -use Illuminate\Database\ConnectionInterface; +use Illuminate\Database\Connection; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Query\Builder; @@ -473,9 +473,11 @@ protected function mockConnectionForModel(Model $model, string $database, array { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; $processorClass = 'Illuminate\Database\Query\Processors\\'.$database.'Processor'; - $grammar = new $grammarClass; $processor = new $processorClass; - $connection = Mockery::mock(ConnectionInterface::class, ['getQueryGrammar' => $grammar, 'getPostProcessor' => $processor]); + $connection = Mockery::mock(Connection::class, ['getPostProcessor' => $processor]); + $grammar = new $grammarClass($connection); + $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); $connection->shouldReceive('query')->andReturnUsing(function () use ($connection, $grammar, $processor) { return new Builder($connection, $grammar, $processor); }); diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 33e576c45bb6..29a9cb9ff346 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -4,6 +4,7 @@ use BadMethodCallException; use Closure; +use Illuminate\Database\Connection; use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Eloquent\Builder; @@ -1000,11 +1001,6 @@ public function testQueryPassThru() $builder->getQuery()->shouldReceive('raw')->once()->with('bar')->andReturn('foo'); $this->assertSame('foo', $builder->raw('bar')); - - $builder = $this->getBuilder(); - $grammar = new Grammar; - $builder->getQuery()->shouldReceive('getGrammar')->once()->andReturn($grammar); - $this->assertSame($grammar, $builder->getGrammar()); } public function testQueryScopes() @@ -2323,7 +2319,9 @@ public function testUpdate() { Carbon::setTestNow($now = '2017-10-10 10:10:10'); - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $model = new EloquentBuilderTestStub; $this->mockConnectionForModel($model, ''); @@ -2337,7 +2335,9 @@ public function testUpdate() public function testUpdateWithTimestampValue() { - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $model = new EloquentBuilderTestStub; $this->mockConnectionForModel($model, ''); @@ -2351,7 +2351,9 @@ public function testUpdateWithTimestampValue() public function testUpdateWithQualifiedTimestampValue() { - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $model = new EloquentBuilderTestStub; $this->mockConnectionForModel($model, ''); @@ -2365,7 +2367,9 @@ public function testUpdateWithQualifiedTimestampValue() public function testUpdateWithoutTimestamp() { - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $model = new EloquentBuilderTestStubWithoutTimestamp; $this->mockConnectionForModel($model, ''); @@ -2381,7 +2385,9 @@ public function testUpdateWithAlias() { Carbon::setTestNow($now = '2017-10-10 10:10:10'); - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $model = new EloquentBuilderTestStub; $this->mockConnectionForModel($model, ''); @@ -2397,7 +2403,9 @@ public function testUpdateWithAliasWithQualifiedTimestampValue() { Carbon::setTestNow($now = '2017-10-10 10:10:10'); - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $model = new EloquentBuilderTestStub; $this->mockConnectionForModel($model, ''); @@ -2501,7 +2509,9 @@ public function testWithCastsMethod() public function testClone() { - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = new Builder($query); $builder->select('*')->from('users'); $clone = $builder->clone()->where('email', 'foo'); @@ -2594,9 +2604,11 @@ protected function mockConnectionForModel($model, $database) { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; $processorClass = 'Illuminate\Database\Query\Processors\\'.$database.'Processor'; - $grammar = new $grammarClass; $processor = new $processorClass; - $connection = m::mock(ConnectionInterface::class, ['getQueryGrammar' => $grammar, 'getPostProcessor' => $processor]); + $connection = m::mock(Connection::class, ['getPostProcessor' => $processor]); + $grammar = new $grammarClass($connection); + $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); $connection->shouldReceive('query')->andReturnUsing(function () use ($connection, $grammar, $processor) { return new BaseBuilder($connection, $grammar, $processor); }); diff --git a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php index 09faed3f2654..5a3b9e5c1c06 100755 --- a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php @@ -3,7 +3,7 @@ namespace Illuminate\Tests\Database; use Exception; -use Illuminate\Database\ConnectionInterface; +use Illuminate\Database\Connection; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -320,9 +320,11 @@ protected function mockConnectionForModel(Model $model, string $database, array { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; $processorClass = 'Illuminate\Database\Query\Processors\\'.$database.'Processor'; - $grammar = new $grammarClass; $processor = new $processorClass; - $connection = Mockery::mock(ConnectionInterface::class, ['getQueryGrammar' => $grammar, 'getPostProcessor' => $processor]); + $connection = Mockery::mock(Connection::class, ['getPostProcessor' => $processor]); + $grammar = new $grammarClass($connection); + $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); $connection->shouldReceive('query')->andReturnUsing(function () use ($connection, $grammar, $processor) { return new Builder($connection, $grammar, $processor); }); diff --git a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php index 1b364e57b9f7..b499100ef406 100644 --- a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php @@ -5,7 +5,7 @@ namespace Illuminate\Tests\Database; use Exception; -use Illuminate\Database\ConnectionInterface; +use Illuminate\Database\Connection; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasManyThrough; @@ -372,9 +372,11 @@ protected function mockConnectionForModel(Model $model, string $database, array { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; $processorClass = 'Illuminate\Database\Query\Processors\\'.$database.'Processor'; - $grammar = new $grammarClass; $processor = new $processorClass; - $connection = Mockery::mock(ConnectionInterface::class, ['getQueryGrammar' => $grammar, 'getPostProcessor' => $processor]); + $connection = Mockery::mock(Connection::class, ['getPostProcessor' => $processor]); + $grammar = new $grammarClass($connection); + $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); $connection->shouldReceive('query')->andReturnUsing(function () use ($connection, $grammar, $processor) { return new Builder($connection, $grammar, $processor); }); diff --git a/tests/Database/DatabaseMariaDbBuilderTest.php b/tests/Database/DatabaseMariaDbBuilderTest.php index 9f26f35ed6a3..35d260407861 100644 --- a/tests/Database/DatabaseMariaDbBuilderTest.php +++ b/tests/Database/DatabaseMariaDbBuilderTest.php @@ -1,6 +1,6 @@ shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); $connection->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8mb4_unicode_ci'); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); @@ -33,9 +33,9 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new MariaDbGrammar; - $connection = m::mock(Connection::class); + $grammar = new MariaDbGrammar($connection); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('statement')->once()->with( 'drop database if exists `my_database_a`' diff --git a/tests/Database/DatabaseMariaDbQueryGrammarTest.php b/tests/Database/DatabaseMariaDbQueryGrammarTest.php index f5a5a4dc8975..e86e5fd9193e 100755 --- a/tests/Database/DatabaseMariaDbQueryGrammarTest.php +++ b/tests/Database/DatabaseMariaDbQueryGrammarTest.php @@ -18,8 +18,7 @@ public function testToRawSql() { $connection = m::mock(Connection::class); $connection->shouldReceive('escape')->with('foo', false)->andReturn("'foo'"); - $grammar = new MariaDbGrammar; - $grammar->setConnection($connection); + $grammar = new MariaDbGrammar($connection); $query = $grammar->substituteBindingsIntoRawSql( 'select * from "users" where \'Hello\\\'World?\' IS NOT NULL AND "email" = ?', diff --git a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php index 53a573e33b8d..e30063710c9e 100755 --- a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php +++ b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php @@ -1,6 +1,6 @@ getGrammar(); - $grammar->setTablePrefix('prefix_'); - - $conn = $this->getConnection($grammar); + $conn = $this->getConnection(prefix: 'prefix_'); $conn->shouldReceive('getConfig')->andReturn(null); $blueprint = new Blueprint($conn, 'users'); @@ -1330,7 +1327,7 @@ public function testCreateDatabase() $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); + $statement = $this->getGrammar($connection)->compileCreateDatabase('my_database_a'); $this->assertSame( 'create database `my_database_a` default character set `utf8mb4_foo` default collate `utf8mb4_unicode_ci_foo`', @@ -1341,7 +1338,7 @@ public function testCreateDatabase() $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); + $statement = $this->getGrammar($connection)->compileCreateDatabase('my_database_b'); $this->assertSame( 'create database `my_database_b` default character set `utf8mb4_bar` default collate `utf8mb4_unicode_ci_bar`', @@ -1471,7 +1468,8 @@ public function testDropDatabaseIfExists() public function testDropAllTables() { - $statement = $this->getGrammar()->compileDropAllTables(['alpha', 'beta', 'gamma']); + $connection = $this->getConnection(); + $statement = $this->getGrammar($connection)->compileDropAllTables(['alpha', 'beta', 'gamma']); $this->assertSame('drop table `alpha`,`beta`,`gamma`', $statement); } @@ -1498,19 +1496,25 @@ public function testGrammarsAreMacroable() protected function getConnection( ?MariaDbGrammar $grammar = null, ?MariaDbBuilder $builder = null, + string $prefix = '' ) { - $grammar ??= $this->getGrammar(); + $connection = m::mock(Connection::class) + ->shouldReceive('getTablePrefix')->andReturn($prefix) + ->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(null) + ->getMock(); + + $grammar ??= $this->getGrammar($connection); $builder ??= $this->getBuilder(); - return m::mock(Connection::class) + return $connection ->shouldReceive('getSchemaGrammar')->andReturn($grammar) ->shouldReceive('getSchemaBuilder')->andReturn($builder) ->getMock(); } - public function getGrammar() + public function getGrammar(?Connection $connection = null) { - return new MariaDbGrammar; + return new MariaDbGrammar($connection ?? $this->getConnection()); } public function getBuilder() diff --git a/tests/Database/DatabaseMySqlBuilderTest.php b/tests/Database/DatabaseMySqlBuilderTest.php index 464ce75c741f..3317af8f2b7c 100644 --- a/tests/Database/DatabaseMySqlBuilderTest.php +++ b/tests/Database/DatabaseMySqlBuilderTest.php @@ -17,9 +17,9 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new MySqlGrammar; - $connection = m::mock(Connection::class); + $grammar = new MySqlGrammar($connection); + $connection->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); $connection->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8mb4_unicode_ci'); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); @@ -33,9 +33,9 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new MySqlGrammar; - $connection = m::mock(Connection::class); + $grammar = new MySqlGrammar($connection); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('statement')->once()->with( 'drop database if exists `my_database_a`' diff --git a/tests/Database/DatabaseMySqlQueryGrammarTest.php b/tests/Database/DatabaseMySqlQueryGrammarTest.php index 2bb285415f78..04f5c1222e96 100755 --- a/tests/Database/DatabaseMySqlQueryGrammarTest.php +++ b/tests/Database/DatabaseMySqlQueryGrammarTest.php @@ -18,8 +18,7 @@ public function testToRawSql() { $connection = m::mock(Connection::class); $connection->shouldReceive('escape')->with('foo', false)->andReturn("'foo'"); - $grammar = new MySqlGrammar; - $grammar->setConnection($connection); + $grammar = new MySqlGrammar($connection); $query = $grammar->substituteBindingsIntoRawSql( 'select * from "users" where \'Hello\\\'World?\' IS NOT NULL AND "email" = ?', diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 4615e419e205..64002304ba10 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -165,10 +165,7 @@ public function testCharsetCollationCreateTable() public function testBasicCreateTableWithPrefix() { - $grammar = $this->getGrammar(); - $grammar->setTablePrefix('prefix_'); - - $conn = $this->getConnection($grammar); + $conn = $this->getConnection(prefix: 'prefix_'); $conn->shouldReceive('getConfig')->andReturn(null); $blueprint = new Blueprint($conn, 'users'); @@ -1340,7 +1337,7 @@ public function testCreateDatabase() $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); + $statement = $this->getGrammar($connection)->compileCreateDatabase('my_database_a'); $this->assertSame( 'create database `my_database_a` default character set `utf8mb4_foo` default collate `utf8mb4_unicode_ci_foo`', @@ -1351,7 +1348,7 @@ public function testCreateDatabase() $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); + $statement = $this->getGrammar($connection)->compileCreateDatabase('my_database_b'); $this->assertSame( 'create database `my_database_b` default character set `utf8mb4_bar` default collate `utf8mb4_unicode_ci_bar`', @@ -1508,19 +1505,26 @@ public function testGrammarsAreMacroable() protected function getConnection( ?MySqlGrammar $grammar = null, ?MySqlBuilder $builder = null, + string $prefix = '' ) { - $grammar ??= $this->getGrammar(); + $connection = m::mock(Connection::class) + ->shouldReceive('getTablePrefix')->andReturn($prefix) + ->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(null) + ->shouldReceive('isMaria')->andReturn(false) + ->getMock(); + + $grammar ??= $this->getGrammar($connection); $builder ??= $this->getBuilder(); - return m::mock(Connection::class) + return $connection ->shouldReceive('getSchemaGrammar')->andReturn($grammar) ->shouldReceive('getSchemaBuilder')->andReturn($builder) ->getMock(); } - public function getGrammar() + public function getGrammar(?Connection $connection = null) { - return new MySqlGrammar; + return new MySqlGrammar($connection ?? $this->getConnection()); } public function getBuilder() diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index ea6f77da62e3..466817e48c5e 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -18,9 +18,9 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new PostgresGrammar; - $connection = m::mock(Connection::class); + $grammar = new PostgresGrammar($connection); + $connection->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('statement')->once()->with( @@ -33,9 +33,9 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new PostgresGrammar; - $connection = m::mock(Connection::class); + $grammar = new PostgresGrammar($connection); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('statement')->once()->with( 'drop database if exists "my_database_a"' diff --git a/tests/Database/DatabasePostgresQueryGrammarTest.php b/tests/Database/DatabasePostgresQueryGrammarTest.php index 2fc526946ef5..718ee9d9cd12 100755 --- a/tests/Database/DatabasePostgresQueryGrammarTest.php +++ b/tests/Database/DatabasePostgresQueryGrammarTest.php @@ -19,8 +19,7 @@ public function testToRawSql() { $connection = m::mock(Connection::class); $connection->shouldReceive('escape')->with('foo', false)->andReturn("'foo'"); - $grammar = new PostgresGrammar; - $grammar->setConnection($connection); + $grammar = new PostgresGrammar($connection); $query = $grammar->substituteBindingsIntoRawSql( 'select * from "users" where \'{}\' ?? \'Hello\\\'\\\'World?\' AND "email" = ?', @@ -36,8 +35,7 @@ public function testCustomOperators() PostgresGrammar::customOperators(['@@>', 1]); $connection = m::mock(Connection::class); - $grammar = new PostgresGrammar; - $grammar->setConnection($connection); + $grammar = new PostgresGrammar($connection); $operators = $grammar->getOperators(); @@ -51,7 +49,10 @@ public function testCustomOperators() public function testCompileTruncate() { - $postgres = new PostgresGrammar; + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + + $postgres = new PostgresGrammar($connection); $builder = m::mock(Builder::class); $builder->from = 'users'; diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 041df2b2f042..3b7b0cb4e9c7 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -57,7 +57,10 @@ public function testAddingVector() public function testCreateTableWithAutoIncrementStartingValue() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $connection = $this->getConnection(); + $connection->getSchemaBuilder()->shouldReceive('parseSchemaAndTable')->andReturn([null, 'users']); + + $blueprint = new Blueprint($connection, 'users'); $blueprint->create(); $blueprint->increments('id')->startingValue(1000); $blueprint->string('email'); @@ -71,7 +74,10 @@ public function testCreateTableWithAutoIncrementStartingValue() public function testAddColumnsWithMultipleAutoIncrementStartingValue() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $builder = $this->getBuilder(); + $builder->shouldReceive('parseSchemaAndTable')->andReturn([null, 'users']); + + $blueprint = new Blueprint($this->getConnection(builder: $builder), 'users'); $blueprint->id()->from(100); $blueprint->increments('code')->from(200); $blueprint->string('name')->from(300); @@ -158,7 +164,10 @@ public function testDropColumn() public function testDropPrimary() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $connection = $this->getConnection(); + $connection->getSchemaBuilder()->shouldReceive('parseSchemaAndTable')->andReturn([null, 'users']); + + $blueprint = new Blueprint($connection, 'users'); $blueprint->dropPrimary(); $statements = $blueprint->toSql(); @@ -1046,7 +1055,7 @@ public function testCreateDatabase() { $connection = $this->getConnection(); $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8_foo'); - $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + $statement = $this->getGrammar($connection)->compileCreateDatabase('my_database_a'); $this->assertSame( 'create database "my_database_a" encoding "utf8_foo"', @@ -1055,7 +1064,7 @@ public function testCreateDatabase() $connection = $this->getConnection(); $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8_bar'); - $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + $statement = $this->getGrammar($connection)->compileCreateDatabase('my_database_b'); $this->assertSame( 'create database "my_database_b" encoding "utf8_bar"', @@ -1104,12 +1113,9 @@ public function testDropAllTypesEscapesTableNames() public function testCompileColumns() { $connection = $this->getConnection(); - $grammar = $this->getGrammar(); - $connection->shouldReceive('getServerVersion')->once()->andReturn('12.0.0'); - $grammar->setConnection($connection); - $statement = $grammar->compileColumns('public', 'table'); + $statement = $connection->getSchemaGrammar()->compileColumns('public', 'table'); $this->assertStringContainsString("where c.relname = 'table' and n.nspname = 'public'", $statement); } @@ -1118,18 +1124,23 @@ protected function getConnection( ?PostgresGrammar $grammar = null, ?PostgresBuilder $builder = null ) { - $grammar ??= $this->getGrammar(); + $connection = m::mock(Connection::class) + ->shouldReceive('getTablePrefix')->andReturn('') + ->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(null) + ->getMock(); + + $grammar ??= $this->getGrammar($connection); $builder ??= $this->getBuilder(); - return m::mock(Connection::class) + return $connection ->shouldReceive('getSchemaGrammar')->andReturn($grammar) ->shouldReceive('getSchemaBuilder')->andReturn($builder) ->getMock(); } - public function getGrammar() + public function getGrammar(?Connection $connection = null) { - return new PostgresGrammar; + return new PostgresGrammar($connection ?? $this->getConnection()); } public function getBuilder() diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 447925df2f12..1773aff32783 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -7,7 +7,7 @@ use Closure; use DateTime; use Illuminate\Contracts\Database\Query\ConditionExpression; -use Illuminate\Database\ConnectionInterface; +use Illuminate\Database\Connection; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Expression as Raw; @@ -121,8 +121,7 @@ public function testAddingSelects() public function testBasicSelectWithPrefix() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $builder->select('*')->from('users'); $this->assertSame('select * from "prefix_users"', $builder->toSql()); } @@ -154,16 +153,14 @@ public function testBasicAlias() public function testAliasWithPrefix() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $builder->select('*')->from('users as people'); $this->assertSame('select * from "prefix_users" as "prefix_people"', $builder->toSql()); } public function testJoinAliasesWithPrefix() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $builder->select('*')->from('services')->join('translations AS t', 't.item_id', '=', 'services.id'); $this->assertSame('select * from "prefix_services" inner join "prefix_translations" as "prefix_t" on "prefix_t"."item_id" = "prefix_services"."id"', $builder->toSql()); } @@ -3259,8 +3256,7 @@ public function testJoinSub() public function testJoinSubWithPrefix() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $builder->from('users')->joinSub('select * from "contacts"', 'sub', 'users.id', '=', 'sub.id'); $this->assertSame('select * from "prefix_users" inner join (select * from "contacts") as "prefix_sub" on "prefix_users"."id" = "prefix_sub"."id"', $builder->toSql()); } @@ -3375,9 +3371,7 @@ public function testJoinLateralSqlServer() public function testJoinLateralWithPrefix() { - $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('getDatabaseName'); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getMySqlBuilder(prefix: 'prefix_'); $builder->from('users')->joinLateral('select * from `contacts` where `contracts`.`user_id` = `users`.`id`', 'sub'); $this->assertSame('select * from `prefix_users` inner join lateral (select * from `contacts` where `contracts`.`user_id` = `users`.`id`) as `prefix_sub` on true', $builder->toSql()); } @@ -4241,8 +4235,8 @@ public function testUpdateMethodWorksWithQueryAsValue() public function testUpdateOrInsertMethod() { $builder = m::mock(Builder::class.'[where,exists,insert]', [ - m::mock(ConnectionInterface::class), - new Grammar, + $connection = m::mock(Connection::class), + new Grammar($connection), m::mock(Processor::class), ]); @@ -4253,8 +4247,8 @@ public function testUpdateOrInsertMethod() $this->assertTrue($builder->updateOrInsert(['email' => 'foo'], ['name' => 'bar'])); $builder = m::mock(Builder::class.'[where,exists,update]', [ - m::mock(ConnectionInterface::class), - new Grammar, + $connection = m::mock(Connection::class), + new Grammar($connection), m::mock(Processor::class), ]); @@ -4269,8 +4263,8 @@ public function testUpdateOrInsertMethod() public function testUpdateOrInsertMethodWorksWithEmptyUpdateValues() { $builder = m::spy(Builder::class.'[where,exists,update]', [ - m::mock(ConnectionInterface::class), - new Grammar, + $connection = m::mock(Connection::class), + new Grammar($connection), m::mock(Processor::class), ]); @@ -4397,54 +4391,47 @@ public function testTruncateMethod() $builder = $this->getBuilder(); $connection = $builder->getConnection(); $connection->shouldReceive('statement')->once()->with('truncate table "users"', []); - $connection->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn([null, 'users']); $builder->from('users')->truncate(); - $sqlite = (new SQLiteGrammar)->setConnection($connection); - $builder = $this->getBuilder(); + $builder = $this->getSQLiteBuilder(); + $builder->getConnection()->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn([null, 'users']); $builder->from('users'); $this->assertEquals([ 'delete from sqlite_sequence where name = ?' => ['users'], 'delete from "users"' => [], - ], $sqlite->compileTruncate($builder)); + ], $builder->getGrammar()->compileTruncate($builder)); } public function testTruncateMethodWithPrefix() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $connection = $builder->getConnection(); $connection->shouldReceive('statement')->once()->with('truncate table "prefix_users"', []); - $connection->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn([null, 'users']); $builder->from('users')->truncate(); - $sqlite = (new SQLiteGrammar)->setConnection($connection); - $sqlite->setTablePrefix('prefix_'); - $builder = $this->getBuilder(); + $builder = $this->getSQLiteBuilder(prefix: 'prefix_'); + $builder->getConnection()->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn([null, 'users']); $builder->from('users'); $this->assertEquals([ 'delete from sqlite_sequence where name = ?' => ['prefix_users'], 'delete from "prefix_users"' => [], - ], $sqlite->compileTruncate($builder)); + ], $builder->getGrammar()->compileTruncate($builder)); } public function testTruncateMethodWithPrefixAndSchema() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $connection = $builder->getConnection(); $connection->shouldReceive('statement')->once()->with('truncate table "my_schema"."prefix_users"', []); - $connection->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn(['my_schema', 'users']); $builder->from('my_schema.users')->truncate(); - $sqlite = (new SQLiteGrammar)->setConnection($connection); - $sqlite->setTablePrefix('prefix_'); - $builder = $this->getBuilder(); + $builder = $this->getSQLiteBuilder(prefix: 'prefix_'); + $builder->getConnection()->shouldReceive('getSchemaBuilder->parseSchemaAndTable')->andReturn(['my_schema', 'users']); $builder->from('my_schema.users'); $this->assertEquals([ 'delete from "my_schema".sqlite_sequence where name = ?' => ['prefix_users'], 'delete from "my_schema"."prefix_users"' => [], - ], $sqlite->compileTruncate($builder)); + ], $builder->getGrammar()->compileTruncate($builder)); } public function testPreserveAddsClosureToArray() @@ -4585,10 +4572,10 @@ public function testMySqlWrapping() public function testMySqlUpdateWrappingJson() { - $grammar = new MySqlGrammar; + $connection = $this->createMock(Connection::class); + $grammar = new MySqlGrammar($connection); $processor = m::mock(Processor::class); - $connection = $this->createMock(ConnectionInterface::class); $connection->expects($this->once()) ->method('update') ->with( @@ -4603,10 +4590,10 @@ public function testMySqlUpdateWrappingJson() public function testMySqlUpdateWrappingNestedJson() { - $grammar = new MySqlGrammar; + $connection = $this->createMock(Connection::class); + $grammar = new MySqlGrammar($connection); $processor = m::mock(Processor::class); - $connection = $this->createMock(ConnectionInterface::class); $connection->expects($this->once()) ->method('update') ->with( @@ -4621,10 +4608,10 @@ public function testMySqlUpdateWrappingNestedJson() public function testMySqlUpdateWrappingJsonArray() { - $grammar = new MySqlGrammar; + $connection = $this->createMock(Connection::class); + $grammar = new MySqlGrammar($connection); $processor = m::mock(Processor::class); - $connection = $this->createMock(ConnectionInterface::class); $connection->expects($this->once()) ->method('update') ->with( @@ -4648,10 +4635,10 @@ public function testMySqlUpdateWrappingJsonArray() public function testMySqlUpdateWrappingJsonPathArrayIndex() { - $grammar = new MySqlGrammar; + $connection = $this->createMock(Connection::class); + $grammar = new MySqlGrammar($connection); $processor = m::mock(Processor::class); - $connection = $this->createMock(ConnectionInterface::class); $connection->expects($this->once()) ->method('update') ->with( @@ -4671,10 +4658,10 @@ public function testMySqlUpdateWrappingJsonPathArrayIndex() public function testMySqlUpdateWithJsonPreparesBindingsCorrectly() { - $grammar = new MySqlGrammar; + $connection = $this->getConnection(); + $grammar = new MySqlGrammar($connection); $processor = m::mock(Processor::class); - $connection = m::mock(ConnectionInterface::class); $connection->shouldReceive('update') ->once() ->with( @@ -6826,8 +6813,7 @@ public function testFromSub() public function testFromSubWithPrefix() { - $builder = $this->getBuilder(); - $builder->getGrammar()->setTablePrefix('prefix_'); + $builder = $this->getBuilder(prefix: 'prefix_'); $builder->fromSub(function ($query) { $query->select(new Raw('max(last_seen_at) as last_seen_at'))->from('user_sessions')->where('foo', '=', '1'); }, 'sessions')->where('bar', '<', '10'); @@ -6984,11 +6970,11 @@ public function testCloneWithoutBindings() public function testToRawSql() { - $connection = m::mock(ConnectionInterface::class); + $connection = $this->getConnection(); $connection->shouldReceive('prepareBindings') ->with(['foo']) ->andReturn(['foo']); - $grammar = m::mock(Grammar::class)->makePartial(); + $grammar = m::mock(Grammar::class, [$connection])->makePartial(); $grammar->shouldReceive('substituteBindingsIntoRawSql') ->with('select * from "users" where "email" = ?', ['foo']) ->andReturn('select * from "users" where "email" = \'foo\''); @@ -6998,76 +6984,85 @@ public function testToRawSql() $this->assertSame('select * from "users" where "email" = \'foo\'', $builder->toRawSql()); } - protected function getConnection() + protected function getConnection(string $prefix = '') { - $connection = m::mock(ConnectionInterface::class); + $connection = m::mock(Connection::class); $connection->shouldReceive('getDatabaseName')->andReturn('database'); + $connection->shouldReceive('getTablePrefix')->andReturn($prefix); return $connection; } - protected function getBuilder() + protected function getBuilder(string $prefix = '') { - $grammar = new Grammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new Grammar($connection); $processor = m::mock(Processor::class); - return new Builder($this->getConnection(), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getPostgresBuilder() + protected function getPostgresBuilder(string $prefix = '') { - $grammar = new PostgresGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new PostgresGrammar($connection); $processor = m::mock(Processor::class); - return new Builder($this->getConnection(), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getMySqlBuilder() + protected function getMySqlBuilder(string $prefix = '') { - $grammar = new MySqlGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new MySqlGrammar($connection); $processor = m::mock(Processor::class); - return new Builder(m::mock(ConnectionInterface::class), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getMariaDbBuilder() + protected function getMariaDbBuilder(string $prefix = '') { - $grammar = new MariaDbGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new MariaDbGrammar($connection); $processor = m::mock(Processor::class); - return new Builder(m::mock(ConnectionInterface::class), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getSQLiteBuilder() + protected function getSQLiteBuilder(string $prefix = '') { - $grammar = new SQLiteGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new SQLiteGrammar($connection); $processor = m::mock(Processor::class); - return new Builder(m::mock(ConnectionInterface::class), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getSqlServerBuilder() + protected function getSqlServerBuilder(string $prefix = '') { - $grammar = new SqlServerGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new SqlServerGrammar($connection); $processor = m::mock(Processor::class); - return new Builder($this->getConnection(), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getMySqlBuilderWithProcessor() + protected function getMySqlBuilderWithProcessor(string $prefix = '') { - $grammar = new MySqlGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new MySqlGrammar($connection); $processor = new MySqlProcessor; - return new Builder(m::mock(ConnectionInterface::class), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } - protected function getPostgresBuilderWithProcessor() + protected function getPostgresBuilderWithProcessor(string $prefix = '') { - $grammar = new PostgresGrammar; + $connection = $this->getConnection(prefix: $prefix); + $grammar = new PostgresGrammar($connection); $processor = new PostgresProcessor; - return new Builder(m::mock(ConnectionInterface::class), $grammar, $processor); + return new Builder($connection, $grammar, $processor); } /** @@ -7076,8 +7071,8 @@ protected function getPostgresBuilderWithProcessor() protected function getMockQueryBuilder() { return m::mock(Builder::class, [ - m::mock(ConnectionInterface::class), - new Grammar, + $connection = $this->getConnection(), + new Grammar($connection), m::mock(Processor::class), ])->makePartial(); } diff --git a/tests/Database/DatabaseQueryGrammarTest.php b/tests/Database/DatabaseQueryGrammarTest.php index aee7f822caba..ced4930d3f98 100644 --- a/tests/Database/DatabaseQueryGrammarTest.php +++ b/tests/Database/DatabaseQueryGrammarTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Database; +use Illuminate\Database\Connection; use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Expression; use Illuminate\Database\Query\Grammars\Grammar; @@ -19,7 +20,7 @@ protected function tearDown(): void public function testWhereRawReturnsStringWhenExpressionPassed() { $builder = m::mock(Builder::class); - $grammar = new Grammar; + $grammar = new Grammar(m::mock(Connection::class)); $reflection = new ReflectionClass($grammar); $method = $reflection->getMethod('whereRaw'); $expressionArray = ['sql' => new Expression('select * from "users"')]; @@ -32,7 +33,7 @@ public function testWhereRawReturnsStringWhenExpressionPassed() public function testWhereRawReturnsStringWhenStringPassed() { $builder = m::mock(Builder::class); - $grammar = new Grammar; + $grammar = new Grammar(m::mock(Connection::class)); $reflection = new ReflectionClass($grammar); $method = $reflection->getMethod('whereRaw'); $stringArray = ['sql' => 'select * from "users"']; diff --git a/tests/Database/DatabaseSQLiteQueryGrammarTest.php b/tests/Database/DatabaseSQLiteQueryGrammarTest.php index 1cc5d77ed442..c94377352571 100755 --- a/tests/Database/DatabaseSQLiteQueryGrammarTest.php +++ b/tests/Database/DatabaseSQLiteQueryGrammarTest.php @@ -18,8 +18,7 @@ public function testToRawSql() { $connection = m::mock(Connection::class); $connection->shouldReceive('escape')->with('foo', false)->andReturn("'foo'"); - $grammar = new SQLiteGrammar; - $grammar->setConnection($connection); + $grammar = new SQLiteGrammar($connection); $query = $grammar->substituteBindingsIntoRawSql( 'select * from "users" where \'Hello\'\'World?\' IS NOT NULL AND "email" = ?', diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index 0b9c5dbbc348..f061c2a067a8 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -1094,7 +1094,7 @@ protected function getConnection( public function getGrammar(?Connection $connection = null) { - return (new SQLiteGrammar())->setConnection($connection ?? $this->getConnection()); + return new SQLiteGrammar($connection ?? $this->getConnection()); } public function getBuilder() diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index d069d530dbce..e8546270597b 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -6,17 +6,7 @@ use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Builder; -use Illuminate\Database\Schema\Grammars\Grammar; -use Illuminate\Database\Schema\Grammars\MariaDbGrammar; use Illuminate\Database\Schema\Grammars\MySqlGrammar; -use Illuminate\Database\Schema\Grammars\PostgresGrammar; -use Illuminate\Database\Schema\Grammars\SQLiteGrammar; -use Illuminate\Database\Schema\Grammars\SqlServerGrammar; -use Illuminate\Database\Schema\MariaDbBuilder; -use Illuminate\Database\Schema\MySqlBuilder; -use Illuminate\Database\Schema\PostgresBuilder; -use Illuminate\Database\Schema\SQLiteBuilder; -use Illuminate\Database\Schema\SqlServerBuilder; use Illuminate\Tests\Database\Fixtures\Models\User; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -120,10 +110,10 @@ public function testDefaultCurrentDateTime() })->toSql(); }; - $this->assertEquals(['alter table `users` add `created` datetime not null default CURRENT_TIMESTAMP'], $getSql(new MySqlGrammar)); - $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $getSql(new PostgresGrammar)); - $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SQLiteGrammar)); - $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SqlServerGrammar)); + $this->assertEquals(['alter table `users` add `created` datetime not null default CURRENT_TIMESTAMP'], $getSql('MySql')); + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $getSql('Postgres')); + $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $getSql('SQLite')); + $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $getSql('SqlServer')); } public function testDefaultCurrentTimestamp() @@ -134,10 +124,10 @@ public function testDefaultCurrentTimestamp() })->toSql(); }; - $this->assertEquals(['alter table `users` add `created` timestamp not null default CURRENT_TIMESTAMP'], $getSql(new MySqlGrammar)); - $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $getSql(new PostgresGrammar)); - $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SQLiteGrammar)); - $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $getSql(new SqlServerGrammar)); + $this->assertEquals(['alter table `users` add `created` timestamp not null default CURRENT_TIMESTAMP'], $getSql('MySql')); + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $getSql('Postgres')); + $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $getSql('SQLite')); + $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $getSql('SqlServer')); } public function testRemoveColumn() @@ -150,7 +140,7 @@ public function testRemoveColumn() })->toSql(); }; - $this->assertEquals(['alter table `users` add `foo` varchar(255) not null'], $getSql(new MySqlGrammar)); + $this->assertEquals(['alter table `users` add `foo` varchar(255) not null'], $getSql('MySql')); } public function testRenameColumn() @@ -165,15 +155,15 @@ public function testRenameColumn() }))->toSql(); }; - $this->assertEquals(['alter table `users` rename column `foo` to `bar`'], $getSql(new MySqlGrammar)); - $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $getSql(new PostgresGrammar)); - $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $getSql(new SQLiteGrammar)); - $this->assertEquals(['sp_rename N\'"users"."foo"\', "bar", N\'COLUMN\''], $getSql(new SqlServerGrammar)); + $this->assertEquals(['alter table `users` rename column `foo` to `bar`'], $getSql('MySql')); + $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $getSql('Postgres')); + $this->assertEquals(['alter table "users" rename column "foo" to "bar"'], $getSql('SQLite')); + $this->assertEquals(['sp_rename N\'"users"."foo"\', "bar", N\'COLUMN\''], $getSql('SqlServer')); } public function testNativeRenameColumnOnMysql57() { - $connection = $this->getConnection(new MySqlGrammar); + $connection = $this->getConnection('MySql'); $connection->shouldReceive('isMaria')->andReturn(false); $connection->shouldReceive('getServerVersion')->andReturn('5.7'); $connection->getSchemaBuilder()->shouldReceive('getColumns')->andReturn([ @@ -197,7 +187,7 @@ public function testNativeRenameColumnOnMysql57() public function testNativeRenameColumnOnLegacyMariaDB() { - $connection = $this->getConnection(new MariaDbGrammar); + $connection = $this->getConnection('MariaDb'); $connection->shouldReceive('isMaria')->andReturn(true); $connection->shouldReceive('getServerVersion')->andReturn('10.1.35'); $connection->getSchemaBuilder()->shouldReceive('getColumns')->andReturn([ @@ -230,15 +220,15 @@ public function testDropColumn() })->toSql(); }; - $this->assertEquals(['alter table `users` drop `foo`'], $getSql(new MySqlGrammar)); - $this->assertEquals(['alter table "users" drop column "foo"'], $getSql(new PostgresGrammar)); - $this->assertEquals(['alter table "users" drop column "foo"'], $getSql(new SQLiteGrammar)); - $this->assertStringContainsString('alter table "users" drop column "foo"', $getSql(new SqlServerGrammar)[0]); + $this->assertEquals(['alter table `users` drop `foo`'], $getSql('MySql')); + $this->assertEquals(['alter table "users" drop column "foo"'], $getSql('Postgres')); + $this->assertEquals(['alter table "users" drop column "foo"'], $getSql('SQLite')); + $this->assertStringContainsString('alter table "users" drop column "foo"', $getSql('SqlServer')[0]); } public function testNativeColumnModifyingOnMySql() { - $blueprint = $this->getBlueprint(new MySqlGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('MySql', 'users', function ($table) { $table->double('amount')->nullable()->invisible()->after('name')->change(); $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->useCurrentOnUpdate()->change(); $table->enum('difficulty', ['easy', 'hard'])->default('easy')->charset('utf8mb4')->collation('unicode')->change(); @@ -268,7 +258,7 @@ public function testMacroable() return 'bar'; }); - $blueprint = $this->getBlueprint(new MySqlGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('MySql', 'users', function ($table) { $table->foo(); }); @@ -287,7 +277,7 @@ public function testDefaultUsingIdMorph() 'alter table `comments` add `commentable_type` varchar(255) not null', 'alter table `comments` add `commentable_id` bigint unsigned not null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDefaultUsingNullableIdMorph() @@ -302,7 +292,7 @@ public function testDefaultUsingNullableIdMorph() 'alter table `comments` add `commentable_type` varchar(255) null', 'alter table `comments` add `commentable_id` bigint unsigned null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDefaultUsingUuidMorph() @@ -319,7 +309,7 @@ public function testDefaultUsingUuidMorph() 'alter table `comments` add `commentable_type` varchar(255) not null', 'alter table `comments` add `commentable_id` char(36) not null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDefaultUsingNullableUuidMorph() @@ -336,7 +326,7 @@ public function testDefaultUsingNullableUuidMorph() 'alter table `comments` add `commentable_type` varchar(255) null', 'alter table `comments` add `commentable_id` char(36) null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDefaultUsingUlidMorph() @@ -353,7 +343,7 @@ public function testDefaultUsingUlidMorph() 'alter table `comments` add `commentable_type` varchar(255) not null', 'alter table `comments` add `commentable_id` char(26) not null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDefaultUsingNullableUlidMorph() @@ -370,7 +360,7 @@ public function testDefaultUsingNullableUlidMorph() 'alter table `comments` add `commentable_type` varchar(255) null', 'alter table `comments` add `commentable_id` char(26) null', 'alter table `comments` add index `comments_commentable_type_commentable_id_index`(`commentable_type`, `commentable_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testGenerateRelationshipColumnWithIncrementalModel() @@ -383,7 +373,7 @@ public function testGenerateRelationshipColumnWithIncrementalModel() $this->assertEquals([ 'alter table `posts` add `user_id` bigint unsigned not null', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testGenerateRelationshipColumnWithNonIncrementalModel() @@ -396,7 +386,7 @@ public function testGenerateRelationshipColumnWithNonIncrementalModel() $this->assertEquals([ 'alter table `posts` add `model_using_non_incremented_int_id` bigint unsigned not null', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testGenerateRelationshipColumnWithUuidModel() @@ -409,7 +399,7 @@ public function testGenerateRelationshipColumnWithUuidModel() $this->assertEquals([ 'alter table `posts` add `model_using_uuid_id` char(36) not null', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testGenerateRelationshipColumnWithUlidModel() @@ -422,11 +412,11 @@ public function testGenerateRelationshipColumnWithUlidModel() $this->assertEquals([ 'alter table "posts" add column "model_using_ulid_id" char(26) not null', - ], $getSql(new PostgresGrammar)); + ], $getSql('Postgres')); $this->assertEquals([ 'alter table `posts` add `model_using_ulid_id` char(26) not null', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testGenerateRelationshipConstrainedColumn() @@ -440,7 +430,7 @@ public function testGenerateRelationshipConstrainedColumn() $this->assertEquals([ 'alter table `posts` add `user_id` bigint unsigned not null', 'alter table `posts` add constraint `posts_user_id_foreign` foreign key (`user_id`) references `users` (`id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testGenerateRelationshipForModelWithNonStandardPrimaryKeyName() @@ -454,7 +444,7 @@ public function testGenerateRelationshipForModelWithNonStandardPrimaryKeyName() $this->assertEquals([ 'alter table `posts` add `user_internal_id` bigint unsigned not null', 'alter table `posts` add constraint `posts_user_internal_id_foreign` foreign key (`user_internal_id`) references `users` (`internal_id`)', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDropRelationshipColumnWithIncrementalModel() @@ -467,7 +457,7 @@ public function testDropRelationshipColumnWithIncrementalModel() $this->assertEquals([ 'alter table `posts` drop `user_id`', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDropRelationshipColumnWithUuidModel() @@ -480,7 +470,7 @@ public function testDropRelationshipColumnWithUuidModel() $this->assertEquals([ 'alter table `posts` drop `model_using_uuid_id`', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDropConstrainedRelationshipColumnWithIncrementalModel() @@ -494,7 +484,7 @@ public function testDropConstrainedRelationshipColumnWithIncrementalModel() $this->assertEquals([ 'alter table `posts` drop foreign key `posts_user_id_foreign`', 'alter table `posts` drop `user_id`', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testDropConstrainedRelationshipColumnWithUuidModel() @@ -508,7 +498,7 @@ public function testDropConstrainedRelationshipColumnWithUuidModel() $this->assertEquals([ 'alter table `posts` drop foreign key `posts_model_using_uuid_id_foreign`', 'alter table `posts` drop `model_using_uuid_id`', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); } public function testTinyTextColumn() @@ -519,10 +509,10 @@ public function testTinyTextColumn() })->toSql(); }; - $this->assertEquals(['alter table `posts` add `note` tinytext not null'], $getSql(new MySqlGrammar)); - $this->assertEquals(['alter table "posts" add column "note" text not null'], $getSql(new SQLiteGrammar)); - $this->assertEquals(['alter table "posts" add column "note" varchar(255) not null'], $getSql(new PostgresGrammar)); - $this->assertEquals(['alter table "posts" add "note" nvarchar(255) not null'], $getSql(new SqlServerGrammar)); + $this->assertEquals(['alter table `posts` add `note` tinytext not null'], $getSql('MySql')); + $this->assertEquals(['alter table "posts" add column "note" text not null'], $getSql('SQLite')); + $this->assertEquals(['alter table "posts" add column "note" varchar(255) not null'], $getSql('Postgres')); + $this->assertEquals(['alter table "posts" add "note" nvarchar(255) not null'], $getSql('SqlServer')); } public function testTinyTextNullableColumn() @@ -533,10 +523,10 @@ public function testTinyTextNullableColumn() })->toSql(); }; - $this->assertEquals(['alter table `posts` add `note` tinytext null'], $getSql(new MySqlGrammar)); - $this->assertEquals(['alter table "posts" add column "note" text'], $getSql(new SQLiteGrammar)); - $this->assertEquals(['alter table "posts" add column "note" varchar(255) null'], $getSql(new PostgresGrammar)); - $this->assertEquals(['alter table "posts" add "note" nvarchar(255) null'], $getSql(new SqlServerGrammar)); + $this->assertEquals(['alter table `posts` add `note` tinytext null'], $getSql('MySql')); + $this->assertEquals(['alter table "posts" add column "note" text'], $getSql('SQLite')); + $this->assertEquals(['alter table "posts" add column "note" varchar(255) null'], $getSql('Postgres')); + $this->assertEquals(['alter table "posts" add "note" nvarchar(255) null'], $getSql('SqlServer')); } public function testRawColumn() @@ -549,19 +539,19 @@ public function testRawColumn() $this->assertEquals([ 'alter table `posts` add `legacy_boolean` INT(1) null', - ], $getSql(new MySqlGrammar)); + ], $getSql('MySql')); $this->assertEquals([ 'alter table "posts" add column "legacy_boolean" INT(1)', - ], $getSql(new SQLiteGrammar)); + ], $getSql('SQLite')); $this->assertEquals([ 'alter table "posts" add column "legacy_boolean" INT(1) null', - ], $getSql(new PostgresGrammar)); + ], $getSql('Postgres')); $this->assertEquals([ 'alter table "posts" add "legacy_boolean" INT(1) null', - ], $getSql(new SqlServerGrammar)); + ], $getSql('SqlServer')); } public function testTableComment() @@ -572,42 +562,43 @@ public function testTableComment() })->toSql(); }; - $this->assertEquals(['alter table `posts` comment = \'Look at my comment, it is amazing\''], $getSql(new MySqlGrammar)); - $this->assertEquals(['comment on table "posts" is \'Look at my comment, it is amazing\''], $getSql(new PostgresGrammar)); + $this->assertEquals(['alter table `posts` comment = \'Look at my comment, it is amazing\''], $getSql('MySql')); + $this->assertEquals(['comment on table "posts" is \'Look at my comment, it is amazing\''], $getSql('Postgres')); } - protected function getConnection(?Grammar $grammar = null) + protected function getConnection(?string $grammar = null, string $prefix = '') { - $grammar ??= new MySqlGrammar; + $connection = m::mock(Connection::class) + ->shouldReceive('getTablePrefix')->andReturn($prefix) + ->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(true) + ->getMock(); - $builder = mock(match ($grammar::class) { - MySqlGrammar::class => MySqlBuilder::class, - PostgresGrammar::class => PostgresBuilder::class, - SQLiteGrammar::class => SQLiteBuilder::class, - SqlServerGrammar::class => SqlServerBuilder::class, - MariaDbGrammar::class => MariaDbBuilder::class, - default => Builder::class, - }); + $grammar ??= 'MySql'; + $grammarClass = 'Illuminate\Database\Schema\Grammars\\'.$grammar.'Grammar'; + $builderClass = 'Illuminate\Database\Schema\\'.$grammar.'Builder'; - $connection = m::mock(Connection::class) - ->shouldReceive('getSchemaGrammar')->andReturn($grammar) - ->shouldReceive('getSchemaBuilder')->andReturn($builder); + $connection->shouldReceive('getSchemaGrammar')->andReturn(new $grammarClass($connection)); + $connection->shouldReceive('getSchemaBuilder')->andReturn(m::mock($builderClass)); - if ($grammar instanceof SQLiteGrammar) { + if ($grammar === 'SQLite') { $connection->shouldReceive('getServerVersion')->andReturn('3.35'); } - return $connection->getMock(); + if ($grammar === 'MySql') { + $connection->shouldReceive('isMaria')->andReturn(false); + } + + return $connection; } protected function getBlueprint( - ?Grammar $grammar = null, + ?string $grammar = null, string $table = '', ?Closure $callback = null, string $prefix = '' ): Blueprint { - $connection = $this->getConnection($grammar); + $connection = $this->getConnection($grammar, $prefix); - return new Blueprint($connection, $table, $callback, $prefix); + return new Blueprint($connection, $table, $callback); } } diff --git a/tests/Database/DatabaseSchemaBuilderTest.php b/tests/Database/DatabaseSchemaBuilderTest.php index e2f03e36dcc2..c069c5f5e773 100644 --- a/tests/Database/DatabaseSchemaBuilderTest.php +++ b/tests/Database/DatabaseSchemaBuilderTest.php @@ -6,7 +6,6 @@ use Illuminate\Database\Query\Processors\Processor; use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\Grammars\Grammar; -use LogicException; use Mockery as m; use PHPUnit\Framework\TestCase; use stdClass; @@ -22,26 +21,24 @@ public function testCreateDatabase() { $connection = m::mock(Connection::class); $grammar = m::mock(stdClass::class); + $grammar->shouldReceive('compileCreateDatabase')->andReturn('sql'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $connection->shouldReceive('statement')->with('sql')->andReturnTrue(); $builder = new Builder($connection); - $this->expectException(LogicException::class); - $this->expectExceptionMessage('This database driver does not support creating databases.'); - - $builder->createDatabase('foo'); + $this->assertTrue($builder->createDatabase('foo')); } public function testDropDatabaseIfExists() { $connection = m::mock(Connection::class); $grammar = m::mock(stdClass::class); + $grammar->shouldReceive('compileDropDatabaseIfExists')->andReturn('sql'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $connection->shouldReceive('statement')->with('sql')->andReturnTrue(); $builder = new Builder($connection); - $this->expectException(LogicException::class); - $this->expectExceptionMessage('This database driver does not support dropping databases.'); - - $builder->dropDatabaseIfExists('foo'); + $this->assertTrue($builder->dropDatabaseIfExists('foo')); } public function testHasTableCorrectlyCallsGrammar() diff --git a/tests/Database/DatabaseSqlServerQueryGrammarTest.php b/tests/Database/DatabaseSqlServerQueryGrammarTest.php index 2960719672e8..f3052b1250b1 100755 --- a/tests/Database/DatabaseSqlServerQueryGrammarTest.php +++ b/tests/Database/DatabaseSqlServerQueryGrammarTest.php @@ -18,8 +18,7 @@ public function testToRawSql() { $connection = m::mock(Connection::class); $connection->shouldReceive('escape')->with('foo', false)->andReturn("'foo'"); - $grammar = new SqlServerGrammar; - $grammar->setConnection($connection); + $grammar = new SqlServerGrammar($connection); $query = $grammar->substituteBindingsIntoRawSql( "select * from [users] where 'Hello''World?' IS NOT NULL AND [email] = ?", diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 8877e450770a..d06003473498 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -40,7 +40,7 @@ public function testBasicCreateTable() 'alter table "users" add "email" nvarchar(255) not null', ], $statements); - $conn = $this->getConnection($this->getGrammar()->setTablePrefix('prefix_')); + $conn = $this->getConnection(prefix: 'prefix_'); $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); $blueprint->increments('id'); @@ -68,8 +68,7 @@ public function testCreateTemporaryTable() public function testCreateTemporaryTableWithPrefix() { - $connection = $this->getConnection(); - $connection->shouldReceive('getTablePrefix')->andReturn('prefix_'); + $connection = $this->getConnection(prefix: 'prefix_'); $blueprint = new Blueprint($connection, 'users'); $blueprint->create(); $blueprint->temporary(); @@ -90,7 +89,7 @@ public function testDropTable() $this->assertCount(1, $statements); $this->assertSame('drop table "users"', $statements[0]); - $conn = $this->getConnection($this->getGrammar()->setTablePrefix('prefix_')); + $conn = $this->getConnection(prefix: 'prefix_'); $blueprint = new Blueprint($conn, 'users'); $blueprint->drop(); $statements = $blueprint->toSql(); @@ -108,7 +107,7 @@ public function testDropTableIfExists() $this->assertCount(1, $statements); $this->assertSame('if object_id(N\'"users"\', \'U\') is not null drop table "users"', $statements[0]); - $conn = $this->getConnection($this->getGrammar()->setTablePrefix('prefix_')); + $conn = $this->getConnection(prefix: 'prefix_'); $blueprint = new Blueprint($conn, 'users'); $blueprint->dropIfExists(); $statements = $blueprint->toSql(); @@ -932,16 +931,14 @@ public function testQuoteStringOnArray() public function testCreateDatabase() { - $connection = $this->getConnection(); - - $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a'); $this->assertSame( 'create database "my_database_a"', $statement ); - $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b'); $this->assertSame( 'create database "my_database_b"', @@ -968,9 +965,14 @@ public function testDropDatabaseIfExists() protected function getConnection( ?SqlServerGrammar $grammar = null, - ?SqlServerBuilder $builder = null + ?SqlServerBuilder $builder = null, + string $prefix = '' ) { - $connection = m::mock(Connection::class); + $connection = m::mock(Connection::class) + ->shouldReceive('getTablePrefix')->andReturn($prefix) + ->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(null) + ->getMock(); + $grammar ??= $this->getGrammar($connection); $builder ??= $this->getBuilder(); @@ -982,8 +984,7 @@ protected function getConnection( public function getGrammar(?Connection $connection = null) { - return ($grammar = new SqlServerGrammar) - ->setConnection($connection ?? $this->getConnection(grammar: $grammar)); + return new SqlServerGrammar($connection ?? $this->getConnection()); } public function getBuilder() diff --git a/tests/Database/SqlServerBuilderTest.php b/tests/Database/SqlServerBuilderTest.php index 039cadb8394a..5ae3689adfd0 100644 --- a/tests/Database/SqlServerBuilderTest.php +++ b/tests/Database/SqlServerBuilderTest.php @@ -17,9 +17,9 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new SqlServerGrammar; - $connection = m::mock(Connection::class); + $grammar = new SqlServerGrammar($connection); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('statement')->once()->with( 'create database "my_temporary_database_a"' @@ -31,9 +31,9 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new SqlServerGrammar; - $connection = m::mock(Connection::class); + $grammar = new SqlServerGrammar($connection); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); $connection->shouldReceive('statement')->once()->with( 'drop database if exists "my_temporary_database_b"' diff --git a/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php b/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php index 2db84efd5aa7..cf1e71712318 100644 --- a/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php +++ b/tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php @@ -4,11 +4,6 @@ use Closure; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Schema\Grammars\Grammar; -use Illuminate\Database\Schema\Grammars\MySqlGrammar; -use Illuminate\Database\Schema\Grammars\PostgresGrammar; -use Illuminate\Database\Schema\Grammars\SQLiteGrammar; -use Illuminate\Database\Schema\Grammars\SqlServerGrammar; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Orchestra\Testbench\Attributes\RequiresDatabase; @@ -37,7 +32,7 @@ public function testRenamingAndChangingColumnsWork() $table->string('age'); }); - $blueprint = $this->getBlueprint(new SQLiteGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('SQLite', 'users', function ($table) { $table->renameColumn('name', 'first_name'); $table->integer('age')->change(); }); @@ -76,7 +71,7 @@ public function testRenamingColumnsWorks() public function testNativeColumnModifyingOnPostgreSql() { - $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('Postgres', 'users', function ($table) { $table->integer('code')->autoIncrement()->from(10)->comment('my comment')->change(); }); @@ -88,7 +83,7 @@ public function testNativeColumnModifyingOnPostgreSql() 'comment on column "users"."code" is \'my comment\'', ], $blueprint->toSql()); - $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('Postgres', 'users', function ($table) { $table->char('name', 40)->nullable()->default('easy')->collation('unicode')->change(); }); @@ -101,7 +96,7 @@ public function testNativeColumnModifyingOnPostgreSql() 'comment on column "users"."name" is NULL', ], $blueprint->toSql()); - $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('Postgres', 'users', function ($table) { $table->integer('foo')->generatedAs('expression')->always()->change(); }); @@ -115,7 +110,7 @@ public function testNativeColumnModifyingOnPostgreSql() 'comment on column "users"."foo" is NULL', ], $blueprint->toSql()); - $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('Postgres', 'users', function ($table) { $table->geometry('foo', 'point', 1234)->change(); }); @@ -128,7 +123,7 @@ public function testNativeColumnModifyingOnPostgreSql() 'comment on column "users"."foo" is NULL', ], $blueprint->toSql()); - $blueprint = $this->getBlueprint(new PostgresGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('Postgres', 'users', function ($table) { $table->timestamp('added_at', 2)->useCurrent()->storedAs(null)->change(); }); @@ -145,7 +140,7 @@ public function testNativeColumnModifyingOnPostgreSql() public function testNativeColumnModifyingOnSqlServer() { - $blueprint = $this->getBlueprint(new SqlServerGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('SqlServer', 'users', function ($table) { $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->change(); }); @@ -155,7 +150,7 @@ public function testNativeColumnModifyingOnSqlServer() 'alter table "users" add default CURRENT_TIMESTAMP for "added_at"', ], $blueprint->toSql()); - $blueprint = $this->getBlueprint(new SqlServerGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('SqlServer', 'users', function ($table) { $table->char('name', 40)->nullable()->default('easy')->collation('unicode')->change(); }); @@ -165,7 +160,7 @@ public function testNativeColumnModifyingOnSqlServer() 'alter table "users" add default \'easy\' for "name"', ], $blueprint->toSql()); - $blueprint = $this->getBlueprint(new SqlServerGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('SqlServer', 'users', function ($table) { $table->integer('foo')->change(); }); @@ -181,11 +176,11 @@ public function testChangingColumnWithCollationWorks() $table->string('age'); }); - $blueprint = $this->getBlueprint(new SQLiteGrammar, 'users', function ($table) { + $blueprint = $this->getBlueprint('SQLite', 'users', function ($table) { $table->integer('age')->collation('RTRIM')->change(); }); - $blueprint2 = $this->getBlueprint(new SQLiteGrammar, 'users', function ($table) { + $blueprint2 = $this->getBlueprint('SQLite', 'users', function ($table) { $table->integer('age')->collation('NOCASE')->change(); }); @@ -231,7 +226,7 @@ public function testChangingCharColumnsWork() 'alter table "__temp__users" rename to "users"', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); } public function testChangingPrimaryAutoincrementColumnsToNonAutoincrementColumnsWork() @@ -253,7 +248,7 @@ public function testChangingPrimaryAutoincrementColumnsToNonAutoincrementColumns 'alter table "__temp__users" rename to "users"', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); } public function testChangingDoubleColumnsWork() @@ -275,7 +270,7 @@ public function testChangingDoubleColumnsWork() 'alter table "__temp__products" rename to "products"', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); } public function testChangingColumnsWithDefaultWorks() @@ -300,7 +295,7 @@ public function testChangingColumnsWithDefaultWorks() 'alter table "__temp__products" rename to "products"', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); } public function testRenameIndexWorks() @@ -324,25 +319,25 @@ public function testRenameIndexWorks() 'create index "index2" on "users" ("name")', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); $expected = [ 'sp_rename N\'"users"."index1"\', "index2", N\'INDEX\'', ]; - $this->assertEquals($expected, $getSql(new SqlServerGrammar)); + $this->assertEquals($expected, $getSql('SqlServer')); $expected = [ 'alter table `users` rename index `index1` to `index2`', ]; - $this->assertEquals($expected, $getSql(new MySqlGrammar)); + $this->assertEquals($expected, $getSql('MySql')); $expected = [ 'alter index "index1" rename to "index2"', ]; - $this->assertEquals($expected, $getSql(new PostgresGrammar)); + $this->assertEquals($expected, $getSql('Postgres')); } public function testAddUniqueIndexWithoutNameWorks() @@ -362,7 +357,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'alter table `users` add unique `users_name_unique`(`name`)', ]; - $this->assertEquals($expected, $getSql(new MySqlGrammar)); + $this->assertEquals($expected, $getSql('MySql')); $expected = [ 'alter table "users" alter column "name" type varchar(255), alter column "name" drop not null, alter column "name" drop default, alter column "name" drop identity if exists', @@ -370,7 +365,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'comment on column "users"."name" is NULL', ]; - $this->assertEquals($expected, $getSql(new PostgresGrammar)); + $this->assertEquals($expected, $getSql('Postgres')); $expected = [ 'create table "__temp__users" ("name" varchar)', @@ -380,7 +375,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'create unique index "users_name_unique" on "users" ("name")', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); $expected = [ "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('name') AND [default_object_id] <> 0;EXEC(@sql)", @@ -388,7 +383,7 @@ public function testAddUniqueIndexWithoutNameWorks() 'create unique index "users_name_unique" on "users" ("name")', ]; - $this->assertEquals($expected, $getSql(new SqlServerGrammar)); + $this->assertEquals($expected, $getSql('SqlServer')); } public function testAddUniqueIndexWithNameWorks() @@ -408,7 +403,7 @@ public function testAddUniqueIndexWithNameWorks() 'alter table `users` add unique `index1`(`name`)', ]; - $this->assertEquals($expected, $getSql(new MySqlGrammar)); + $this->assertEquals($expected, $getSql('MySql')); $expected = [ 'alter table "users" alter column "name" type integer, alter column "name" drop not null, alter column "name" drop default, alter column "name" drop identity if exists', @@ -416,7 +411,7 @@ public function testAddUniqueIndexWithNameWorks() 'comment on column "users"."name" is NULL', ]; - $this->assertEquals($expected, $getSql(new PostgresGrammar)); + $this->assertEquals($expected, $getSql('Postgres')); $expected = [ 'create table "__temp__users" ("name" integer)', @@ -426,7 +421,7 @@ public function testAddUniqueIndexWithNameWorks() 'create unique index "index1" on "users" ("name")', ]; - $this->assertEquals($expected, $getSql(new SQLiteGrammar)); + $this->assertEquals($expected, $getSql('SQLite')); $expected = [ "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE \"users\" DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID(N'\"users\"') AND [name] in ('name') AND [default_object_id] <> 0;EXEC(@sql)", @@ -434,7 +429,7 @@ public function testAddUniqueIndexWithNameWorks() 'create unique index "index1" on "users" ("name")', ]; - $this->assertEquals($expected, $getSql(new SqlServerGrammar)); + $this->assertEquals($expected, $getSql('SqlServer')); } public function testAddColumnNamedCreateWorks() @@ -464,22 +459,22 @@ public function testDropIndexOnColumnChangeWorks() $this->assertContains( 'alter table `users` drop index `users_name_unique`', - $getSql(new MySqlGrammar), + $getSql('MySql'), ); $this->assertContains( 'alter table "users" drop constraint "users_name_unique"', - $getSql(new PostgresGrammar), + $getSql('Postgres'), ); $this->assertContains( 'drop index "users_name_unique"', - $getSql(new SQLiteGrammar), + $getSql('SQLite'), ); $this->assertContains( 'drop index "users_name_unique" on "users"', - $getSql(new SqlServerGrammar), + $getSql('SqlServer'), ); } @@ -515,12 +510,14 @@ public function testItEnsuresDroppingForeignKeyIsAvailable() } protected function getBlueprint( - Grammar $grammar, + string $grammar, string $table, Closure $callback, ): Blueprint { - $connection = DB::connection()->setSchemaGrammar($grammar); - $grammar->setConnection($connection); + $grammarClass = 'Illuminate\Database\Schema\Grammars\\'.$grammar.'Grammar'; + + $connection = DB::connection(); + $connection->setSchemaGrammar(new $grammarClass($connection)); return new Blueprint($connection, $table, $callback); } diff --git a/tests/Testing/Concerns/InteractsWithDatabaseTest.php b/tests/Testing/Concerns/InteractsWithDatabaseTest.php index 9b9168930c61..eb6b7cd42655 100644 --- a/tests/Testing/Concerns/InteractsWithDatabaseTest.php +++ b/tests/Testing/Concerns/InteractsWithDatabaseTest.php @@ -2,13 +2,8 @@ namespace Illuminate\Tests\Testing\Concerns; -use Illuminate\Database\ConnectionInterface; +use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; -use Illuminate\Database\Query\Grammars\MariaDbGrammar; -use Illuminate\Database\Query\Grammars\MySqlGrammar; -use Illuminate\Database\Query\Grammars\PostgresGrammar; -use Illuminate\Database\Query\Grammars\SQLiteGrammar; -use Illuminate\Database\Query\Grammars\SqlServerGrammar; use Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Facade; @@ -30,7 +25,7 @@ protected function tearDown(): void public function testCastToJsonSqlite() { - $grammar = new SQLiteGrammar(); + $grammar = 'SQLite'; $this->assertEquals(<<<'TEXT' '["foo","bar"]' @@ -53,7 +48,7 @@ public function testCastToJsonSqlite() public function testCastToJsonPostgres() { - $grammar = new PostgresGrammar(); + $grammar = 'Postgres'; $this->assertEquals(<<<'TEXT' '["foo","bar"]' @@ -76,7 +71,7 @@ public function testCastToJsonPostgres() public function testCastToJsonSqlServer() { - $grammar = new SqlServerGrammar(); + $grammar = 'SqlServer'; $this->assertEquals(<<<'TEXT' json_query('["foo","bar"]') @@ -99,7 +94,7 @@ public function testCastToJsonSqlServer() public function testCastToJsonMySql() { - $grammar = new MySqlGrammar(); + $grammar = 'MySql'; $this->assertEquals(<<<'TEXT' cast('["foo","bar"]' as json) @@ -122,7 +117,7 @@ public function testCastToJsonMySql() public function testCastToJsonMariaDb() { - $grammar = new MariaDbGrammar(); + $grammar = 'MariaDb'; $this->assertEquals(<<<'TEXT' json_query('["foo","bar"]', '$') @@ -145,7 +140,9 @@ public function testCastToJsonMariaDb() protected function castAsJson($value, $grammar) { - $connection = m::mock(ConnectionInterface::class); + $connection = m::mock(Connection::class); + $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$grammar.'Grammar'; + $grammar = new $grammarClass($connection); $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); From 3f801fae70c1c4abd265b1e66b22a5cfd053667c Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 12 Feb 2025 16:31:29 +0000 Subject: [PATCH 082/455] Update facade docblocks --- src/Illuminate/Support/Facades/Schema.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 6204dde9f100..09d0844c8610 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -44,7 +44,6 @@ * @method static string|null getCurrentSchemaName() * @method static array parseSchemaAndTable(string $reference, string|bool|null $withDefaultSchema = null) * @method static \Illuminate\Database\Connection getConnection() - * @method static \Illuminate\Database\Schema\Builder setConnection(\Illuminate\Database\Connection $connection) * @method static void blueprintResolver(\Closure $resolver) * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) From 4d73980dd418745f2cb8462d008b3018707d4869 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Thu, 13 Feb 2025 19:10:31 +0330 Subject: [PATCH 083/455] [12.x] Configure connection on SQLite connector (#54588) * fix SQLite connector * formatting --- .../Database/Connectors/SQLiteConnector.php | 104 ++++++++++++++-- src/Illuminate/Database/SQLiteConnection.php | 111 ------------------ .../Schema/Grammars/SQLiteGrammar.php | 77 +++--------- .../Database/Schema/SQLiteBuilder.php | 86 +++++--------- .../Database/DatabaseEloquentBuilderTest.php | 4 +- .../Database/SchemaBuilderTest.php | 12 -- .../Database/Sqlite/ConnectorTest.php | 61 ++++++++++ 7 files changed, 206 insertions(+), 249 deletions(-) create mode 100644 tests/Integration/Database/Sqlite/ConnectorTest.php diff --git a/src/Illuminate/Database/Connectors/SQLiteConnector.php b/src/Illuminate/Database/Connectors/SQLiteConnector.php index 8ffdd81aa1c3..d68b42718044 100755 --- a/src/Illuminate/Database/Connectors/SQLiteConnector.php +++ b/src/Illuminate/Database/Connectors/SQLiteConnector.php @@ -11,32 +11,118 @@ class SQLiteConnector extends Connector implements ConnectorInterface * * @param array $config * @return \PDO - * - * @throws \Illuminate\Database\SQLiteDatabaseDoesNotExistException */ public function connect(array $config) { $options = $this->getOptions($config); + $path = $this->parseDatabasePath($config['database']); + + $connection = $this->createConnection("sqlite:{$path}", $config, $options); + + $this->configureForeignKeyConstraints($connection, $config); + $this->configureBusyTimeout($connection, $config); + $this->configureJournalMode($connection, $config); + $this->configureSynchronous($connection, $config); + + return $connection; + } + + /** + * Get the absolute database path. + * + * @param string $path + * @return string + * + * @throws \Illuminate\Database\SQLiteDatabaseDoesNotExistException + */ + protected function parseDatabasePath(string $path): string + { // SQLite supports "in-memory" databases that only last as long as the owning // connection does. These are useful for tests or for short lifetime store // querying. In-memory databases shall be anonymous (:memory:) or named. - if ($config['database'] === ':memory:' || - str_contains($config['database'], '?mode=memory') || - str_contains($config['database'], '&mode=memory') + if ($path === ':memory:' || + str_contains($path, '?mode=memory') || + str_contains($path, '&mode=memory') ) { - return $this->createConnection('sqlite:'.$config['database'], $config, $options); + return $path; } - $path = realpath($config['database']) ?: realpath(base_path($config['database'])); + $path = realpath($path) ?: realpath(base_path($path)); // Here we'll verify that the SQLite database exists before going any further // as the developer probably wants to know if the database exists and this // SQLite driver will not throw any exception if it does not by default. if ($path === false) { - throw new SQLiteDatabaseDoesNotExistException($config['database']); + throw new SQLiteDatabaseDoesNotExistException($path); + } + + return $path; + } + + /** + * Enable or disable foreign key constraints if configured. + * + * @param \PDO $connection + * @param array $config + * @return void + */ + protected function configureForeignKeyConstraints($connection, array $config): void + { + if (! isset($config['foreign_key_constraints'])) { + return; + } + + $foreignKeys = $config['foreign_key_constraints'] ? 1 : 0; + + $connection->prepare("pragma foreign_keys = {$foreignKeys}")->execute(); + } + + /** + * Set the busy timeout if configured. + * + * @param \PDO $connection + * @param array $config + * @return void + */ + protected function configureBusyTimeout($connection, array $config): void + { + if (! isset($config['busy_timeout'])) { + return; + } + + $connection->prepare("pragma busy_timeout = {$config['busy_timeout']}")->execute(); + } + + /** + * Set the journal mode if configured. + * + * @param \PDO $connection + * @param array $config + * @return void + */ + protected function configureJournalMode($connection, array $config): void + { + if (! isset($config['journal_mode'])) { + return; + } + + $connection->prepare("pragma journal_mode = {$config['journal_mode']}")->execute(); + } + + /** + * Set the synchronous mode if configured. + * + * @param \PDO $connection + * @param array $config + * @return void + */ + protected function configureSynchronous($connection, array $config): void + { + if (! isset($config['synchronous'])) { + return; } - return $this->createConnection("sqlite:{$path}", $config, $options); + $connection->prepare("pragma synchronous = {$config['synchronous']}")->execute(); } } diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 997afb3934e6..53cbfad42c9d 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -12,25 +12,6 @@ class SQLiteConnection extends Connection { - /** - * Create a new database connection instance. - * - * @param \PDO|\Closure $pdo - * @param string $database - * @param string $tablePrefix - * @param array $config - * @return void - */ - public function __construct($pdo, $database = '', $tablePrefix = '', array $config = []) - { - parent::__construct($pdo, $database, $tablePrefix, $config); - - $this->configureForeignKeyConstraints(); - $this->configureBusyTimeout(); - $this->configureJournalMode(); - $this->configureSynchronous(); - } - /** * {@inheritdoc} */ @@ -39,98 +20,6 @@ public function getDriverTitle() return 'SQLite'; } - /** - * Enable or disable foreign key constraints if configured. - * - * @return void - */ - protected function configureForeignKeyConstraints(): void - { - $enableForeignKeyConstraints = $this->getConfig('foreign_key_constraints'); - - if ($enableForeignKeyConstraints === null) { - return; - } - - $schemaBuilder = $this->getSchemaBuilder(); - - try { - $enableForeignKeyConstraints - ? $schemaBuilder->enableForeignKeyConstraints() - : $schemaBuilder->disableForeignKeyConstraints(); - } catch (QueryException $e) { - if (! $e->getPrevious() instanceof SQLiteDatabaseDoesNotExistException) { - throw $e; - } - } - } - - /** - * Set the busy timeout if configured. - * - * @return void - */ - protected function configureBusyTimeout(): void - { - $milliseconds = $this->getConfig('busy_timeout'); - - if ($milliseconds === null) { - return; - } - - try { - $this->getSchemaBuilder()->setBusyTimeout($milliseconds); - } catch (QueryException $e) { - if (! $e->getPrevious() instanceof SQLiteDatabaseDoesNotExistException) { - throw $e; - } - } - } - - /** - * Set the journal mode if configured. - * - * @return void - */ - protected function configureJournalMode(): void - { - $mode = $this->getConfig('journal_mode'); - - if ($mode === null) { - return; - } - - try { - $this->getSchemaBuilder()->setJournalMode($mode); - } catch (QueryException $e) { - if (! $e->getPrevious() instanceof SQLiteDatabaseDoesNotExistException) { - throw $e; - } - } - } - - /** - * Set the synchronous mode if configured. - * - * @return void - */ - protected function configureSynchronous(): void - { - $mode = $this->getConfig('synchronous'); - - if ($mode === null) { - return; - } - - try { - $this->getSchemaBuilder()->setSynchronous($mode); - } catch (QueryException $e) { - if (! $e->getPrevious() instanceof SQLiteDatabaseDoesNotExistException) { - throw $e; - } - } - } - /** * Escape a binary value for safe SQL embedding. * diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 6f4b7c49217f..624d98c8b800 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -354,7 +354,7 @@ public function compileAlter(Blueprint $blueprint, Fluent $command) $table = $this->wrapTable($blueprint); $columnNames = implode(', ', $columnNames); - $foreignKeyConstraintsEnabled = $this->connection->scalar('pragma foreign_keys'); + $foreignKeyConstraintsEnabled = $this->connection->scalar($this->pragma('foreign_keys')); return array_filter(array_merge([ $foreignKeyConstraintsEnabled ? $this->compileDisableForeignKeyConstraints() : null, @@ -511,11 +511,14 @@ public function compileDropAllViews($schema = null) /** * Compile the SQL needed to rebuild the database. * + * @param string|null $schema * @return string */ - public function compileRebuild() + public function compileRebuild($schema = null) { - return 'vacuum'; + return sprintf('vacuum %s', + $this->wrapValue($schema ?? 'main') + ); } /** @@ -672,7 +675,7 @@ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) */ public function compileEnableForeignKeyConstraints() { - return $this->pragma('foreign_keys', 'ON'); + return $this->pragma('foreign_keys', 1); } /** @@ -682,72 +685,22 @@ public function compileEnableForeignKeyConstraints() */ public function compileDisableForeignKeyConstraints() { - return $this->pragma('foreign_keys', 'OFF'); - } - - /** - * Compile the command to set the busy timeout. - * - * @param int $milliseconds - * @return string - */ - public function compileSetBusyTimeout($milliseconds) - { - return $this->pragma('busy_timeout', $milliseconds); - } - - /** - * Compile the command to set the journal mode. - * - * @param string $mode - * @return string - */ - public function compileSetJournalMode($mode) - { - return $this->pragma('journal_mode', $mode); - } - - /** - * Compile the command to set the synchronous mode. - * - * @param string $mode - * @return string - */ - public function compileSetSynchronous($mode) - { - return $this->pragma('synchronous', $mode); - } - - /** - * Compile the SQL needed to enable a writable schema. - * - * @return string - */ - public function compileEnableWriteableSchema() - { - return $this->pragma('writable_schema', 1); - } - - /** - * Compile the SQL needed to disable a writable schema. - * - * @return string - */ - public function compileDisableWriteableSchema() - { - return $this->pragma('writable_schema', 0); + return $this->pragma('foreign_keys', 0); } /** - * Get the SQL to set a PRAGMA value. + * Get the SQL to get or set a PRAGMA value. * - * @param string $name + * @param string $key * @param mixed $value * @return string */ - protected function pragma(string $name, mixed $value): string + public function pragma(string $key, mixed $value = null): string { - return sprintf('PRAGMA %s = %s;', $name, $value); + return sprintf('pragma %s%s', + $key, + is_null($value) ? '' : ' = '.$value + ); } /** diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 6e818c37db9c..a473768414d2 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -111,24 +111,26 @@ public function getColumns($table) */ public function dropAllTables() { - $database = $this->connection->getDatabaseName(); + foreach ($this->getCurrentSchemaListing() as $schema) { + $database = $schema === 'main' + ? $this->connection->getDatabaseName() + : (array_column($this->getSchemas(), 'path', 'name')[$schema] ?: ':memory:'); - if ($database !== ':memory:' && - ! str_contains($database, '?mode=memory') && - ! str_contains($database, '&mode=memory') - ) { - return $this->refreshDatabaseFile(); - } + if ($database !== ':memory:' && + ! str_contains($database, '?mode=memory') && + ! str_contains($database, '&mode=memory') + ) { + $this->refreshDatabaseFile($database); + } else { + $this->pragma('writable_schema', 1); - $this->connection->select($this->grammar->compileEnableWriteableSchema()); + $this->connection->statement($this->grammar->compileDropAllTables($schema)); - foreach ($this->getCurrentSchemaListing() as $schema) { - $this->connection->select($this->grammar->compileDropAllTables($schema)); - } + $this->pragma('writable_schema', 0); - $this->connection->select($this->grammar->compileDisableWriteableSchema()); - - $this->connection->select($this->grammar->compileRebuild()); + $this->connection->statement($this->grammar->compileRebuild($schema)); + } + } } /** @@ -138,64 +140,40 @@ public function dropAllTables() */ public function dropAllViews() { - $this->connection->select($this->grammar->compileEnableWriteableSchema()); - foreach ($this->getCurrentSchemaListing() as $schema) { - $this->connection->select($this->grammar->compileDropAllViews($schema)); - } + $this->pragma('writable_schema', 1); - $this->connection->select($this->grammar->compileDisableWriteableSchema()); + $this->connection->statement($this->grammar->compileDropAllViews($schema)); - $this->connection->select($this->grammar->compileRebuild()); - } + $this->pragma('writable_schema', 0); - /** - * Set the busy timeout. - * - * @param int $milliseconds - * @return bool - */ - public function setBusyTimeout($milliseconds) - { - return $this->connection->statement( - $this->grammar->compileSetBusyTimeout($milliseconds) - ); - } - - /** - * Set the journal mode. - * - * @param string $mode - * @return bool - */ - public function setJournalMode($mode) - { - return $this->connection->statement( - $this->grammar->compileSetJournalMode($mode) - ); + $this->connection->statement($this->grammar->compileRebuild($schema)); + } } /** - * Set the synchronous mode. + * Get the value for the given pragma name or set the given value. * - * @param int $mode - * @return bool + * @param string $key + * @param mixed $value + * @return mixed */ - public function setSynchronous($mode) + public function pragma($key, $value = null) { - return $this->connection->statement( - $this->grammar->compileSetSynchronous($mode) - ); + return is_null($value) + ? $this->connection->scalar($this->grammar->pragma($key)) + : $this->connection->statement($this->grammar->pragma($key, $value)); } /** * Empty the database file. * + * @param string|null $path * @return void */ - public function refreshDatabaseFile() + public function refreshDatabaseFile($path = null) { - file_put_contents($this->connection->getDatabaseName(), ''); + file_put_contents($path ?? $this->connection->getDatabaseName(), ''); } /** diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 29a9cb9ff346..7bbc69abdbb1 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -2523,7 +2523,9 @@ public function testClone() public function testCloneModelMakesAFreshCopyOfTheModel() { - $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class)); + $connection = m::mock(Connection::class); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $query = new BaseBuilder($connection, new Grammar($connection), m::mock(Processor::class)); $builder = (new Builder($query))->setModel(new EloquentBuilderTestStub); $builder->select('*')->from('users'); diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 85c32aec98fa..6fca5a006116 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -792,18 +792,6 @@ public function testAddAndDropPrimaryOnSqlite() $this->assertTrue(Schema::hasIndex('posts', ['user_name'], 'unique')); } - #[RequiresDatabase('sqlite')] - public function testSetJournalModeOnSqlite() - { - file_put_contents(DB::connection('sqlite')->getConfig('database'), ''); - - $this->assertSame('delete', DB::connection('sqlite')->select('PRAGMA journal_mode')[0]->journal_mode); - - Schema::connection('sqlite')->setJournalMode('WAL'); - - $this->assertSame('wal', DB::connection('sqlite')->select('PRAGMA journal_mode')[0]->journal_mode); - } - public function testAddingMacros() { Schema::macro('foo', fn () => 'foo'); diff --git a/tests/Integration/Database/Sqlite/ConnectorTest.php b/tests/Integration/Database/Sqlite/ConnectorTest.php new file mode 100644 index 000000000000..04ead4ba1ff9 --- /dev/null +++ b/tests/Integration/Database/Sqlite/ConnectorTest.php @@ -0,0 +1,61 @@ +databasePath = database_path('secondary.sqlite')); + } + + protected function destroyDatabaseMigrations() + { + Schema::dropDatabaseIfExists($this->databasePath); + } + + public function testConnectionConfigurations() + { + $schema = DB::build([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ])->getSchemaBuilder(); + + $this->assertSame(0, $schema->pragma('foreign_keys')); + $this->assertSame(60000, $schema->pragma('busy_timeout')); + $this->assertSame('memory', $schema->pragma('journal_mode')); + $this->assertSame(2, $schema->pragma('synchronous')); + + $schema = DB::build([ + 'driver' => 'sqlite', + 'database' => $this->databasePath, + 'foreign_key_constraints' => true, + 'busy_timeout' => 12345, + 'journal_mode' => 'wal', + 'synchronous' => 'normal', + ])->getSchemaBuilder(); + + $this->assertSame(1, $schema->pragma('foreign_keys')); + $this->assertSame(12345, $schema->pragma('busy_timeout')); + $this->assertSame('wal', $schema->pragma('journal_mode')); + $this->assertSame(1, $schema->pragma('synchronous')); + + $schema->pragma('foreign_keys', 0); + $schema->pragma('busy_timeout', 54321); + $schema->pragma('journal_mode', 'delete'); + $schema->pragma('synchronous', 0); + + $this->assertSame(0, $schema->pragma('foreign_keys')); + $this->assertSame(54321, $schema->pragma('busy_timeout')); + $this->assertSame('delete', $schema->pragma('journal_mode')); + $this->assertSame(0, $schema->pragma('synchronous')); + } +} From dc63a5dd9ce521f8125bf4523210ae273f0497c9 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Fri, 14 Feb 2025 10:24:14 -0500 Subject: [PATCH 084/455] [12.x] Introduce Job@resolveQueuedJobClass() (#54613) * introduce Job@resolveQueuedJobClass * remove unused method * style --- src/Illuminate/Contracts/Queue/Job.php | 11 ++- src/Illuminate/Queue/CallQueuedHandler.php | 2 +- src/Illuminate/Queue/Jobs/Job.php | 14 ++- src/Illuminate/Queue/Jobs/JobName.php | 16 ++++ .../Queue/CallQueuedHandlerTest.php | 6 +- .../Queue/DeleteModelWhenMissingTest.php | 93 +++++++++++++++++++ tests/Queue/QueueWorkerTest.php | 5 + 7 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 tests/Integration/Queue/DeleteModelWhenMissingTest.php diff --git a/src/Illuminate/Contracts/Queue/Job.php b/src/Illuminate/Contracts/Queue/Job.php index 9efd17d14d92..68f9d0bec131 100644 --- a/src/Illuminate/Contracts/Queue/Job.php +++ b/src/Illuminate/Contracts/Queue/Job.php @@ -133,7 +133,7 @@ public function retryUntil(); public function getName(); /** - * Get the resolved name of the queued job class. + * Get the display name of the queued job class. * * Resolves the name of "wrapped" jobs such as class-based handlers. * @@ -141,6 +141,15 @@ public function getName(); */ public function resolveName(); + /** + * Get the class of the queued job. + * + * Resolves the class of "wrapped" jobs such as class-based handlers. + * + * @return string + */ + public function resolveQueuedJobClass(); + /** * Get the name of the connection the job belongs to. * diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index 12f49b495152..c767fea8db47 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -218,7 +218,7 @@ protected function ensureUniqueJobLockIsReleased($command) */ protected function handleModelNotFound(Job $job, $e) { - $class = $job->resolveName(); + $class = $job->resolveQueuedJobClass(); try { $reflectionClass = new ReflectionClass($class); diff --git a/src/Illuminate/Queue/Jobs/Job.php b/src/Illuminate/Queue/Jobs/Job.php index f690b64963be..0dee23712fa9 100755 --- a/src/Illuminate/Queue/Jobs/Job.php +++ b/src/Illuminate/Queue/Jobs/Job.php @@ -357,7 +357,7 @@ public function getName() } /** - * Get the resolved name of the queued job class. + * Get the resolved display name of the queued job class. * * Resolves the name of "wrapped" jobs such as class-based handlers. * @@ -368,6 +368,18 @@ public function resolveName() return JobName::resolve($this->getName(), $this->payload()); } + /** + * Get the class of the queued job. + * + * Resolves the class of "wrapped" jobs such as class-based handlers. + * + * @return string + */ + public function resolveQueuedJobClass() + { + return JobName::resolveClassName($this->getName(), $this->payload()); + } + /** * Get the name of the connection the job belongs to. * diff --git a/src/Illuminate/Queue/Jobs/JobName.php b/src/Illuminate/Queue/Jobs/JobName.php index 0db53bb47e9c..fca1eebe9403 100644 --- a/src/Illuminate/Queue/Jobs/JobName.php +++ b/src/Illuminate/Queue/Jobs/JobName.php @@ -32,4 +32,20 @@ public static function resolve($name, $payload) return $name; } + + /** + * Get the class name for queued job class. + * + * @param string $name + * @param array $payload + * @return string + */ + public static function resolveClassName($name, $payload) + { + if (is_string($payload['data']['commandName'] ?? null)) { + return $payload['data']['commandName']; + } + + return $name; + } } diff --git a/tests/Integration/Queue/CallQueuedHandlerTest.php b/tests/Integration/Queue/CallQueuedHandlerTest.php index 8afa8fe9e025..b97d8d530a58 100644 --- a/tests/Integration/Queue/CallQueuedHandlerTest.php +++ b/tests/Integration/Queue/CallQueuedHandlerTest.php @@ -90,7 +90,7 @@ public function testJobIsMarkedAsFailedIfModelNotFoundExceptionIsThrown() $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); $job = m::mock(Job::class); - $job->shouldReceive('resolveName')->andReturn(__CLASS__); + $job->shouldReceive('resolveQueuedJobClass')->andReturn(__CLASS__); $job->shouldReceive('fail')->once(); $instance->call($job, [ @@ -106,7 +106,7 @@ public function testJobIsDeletedIfHasDeleteProperty() $job = m::mock(Job::class); $job->shouldReceive('getConnectionName')->andReturn('connection'); - $job->shouldReceive('resolveName')->andReturn(CallQueuedHandlerExceptionThrower::class); + $job->shouldReceive('resolveQueuedJobClass')->andReturn(CallQueuedHandlerExceptionThrower::class); $job->shouldReceive('markAsFailed')->never(); $job->shouldReceive('isDeleted')->andReturn(false); $job->shouldReceive('delete')->once(); @@ -127,7 +127,7 @@ public function testJobIsDeletedIfHasDeleteAttribute() $job = m::mock(Job::class); $job->shouldReceive('getConnectionName')->andReturn('connection'); - $job->shouldReceive('resolveName')->andReturn(CallQueuedHandlerAttributeExceptionThrower::class); + $job->shouldReceive('resolveQueuedJobClass')->andReturn(CallQueuedHandlerAttributeExceptionThrower::class); $job->shouldReceive('markAsFailed')->never(); $job->shouldReceive('isDeleted')->andReturn(false); $job->shouldReceive('delete')->once(); diff --git a/tests/Integration/Queue/DeleteModelWhenMissingTest.php b/tests/Integration/Queue/DeleteModelWhenMissingTest.php new file mode 100644 index 000000000000..f05564db59b9 --- /dev/null +++ b/tests/Integration/Queue/DeleteModelWhenMissingTest.php @@ -0,0 +1,93 @@ +set('queue.default', 'database'); + $this->driver = 'database'; + } + + protected function defineDatabaseMigrations() + { + Schema::create('delete_model_test_models', function (Blueprint $table) { + $table->id(); + $table->string('name'); + }); + } + + protected function destroyDatabaseMigrations() + { + Schema::dropIfExists('delete_model_test_models'); + } + + #[\Override] + protected function tearDown(): void + { + parent::tearDown(); + + DeleteMissingModelJob::$handled = false; + } + + public function test_deleteModelWhenMissing_and_display_name(): void + { + $model = MyTestModel::query()->create(['name' => 'test']); + + DeleteMissingModelJob::dispatch($model); + + MyTestModel::query()->where('name', 'test')->delete(); + + $this->runQueueWorkerCommand(['--once' => '1']); + + $this->assertFalse(DeleteMissingModelJob::$handled); + $this->assertNull(\DB::table('failed_jobs')->first()); + } +} + +class DeleteMissingModelJob implements ShouldQueue +{ + use InteractsWithQueue; + use Dispatchable; + use SerializesModels; + + public static bool $handled = false; + + public $deleteWhenMissingModels = true; + + public function __construct(public MyTestModel $model) + { + } + + public function displayName(): string + { + return 'sorry-ma-forgot-to-take-out-the-trash'; + } + + public function handle() + { + self::$handled = true; + } +} + +class MyTestModel extends Model +{ + protected $table = 'delete_model_test_models'; + + public $timestamps = false; + + protected $guarded = []; +} diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index 6c511807a50c..a9eebdeae4b4 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -662,6 +662,11 @@ public function timeout() { return time() + 60; } + + public function resolveQueuedJobClass() + { + return 'WorkerFakeJob'; + } } class LoopBreakerException extends RuntimeException From 834cf27cbe6ad6e720b2efbe06da2538a7b807a2 Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Mon, 17 Feb 2025 16:39:31 +0000 Subject: [PATCH 085/455] [12.x] Bind abstract from concrete's return type (#54628) * Proof of concept * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Container/Container.php | 72 +++++++++++++++++-- .../Contracts/Container/Container.php | 18 ++--- tests/Container/ContainerTest.php | 18 +++++ 3 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index c6e4be09db1b..bdfe7dd13cc5 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -9,12 +9,15 @@ use Illuminate\Contracts\Container\CircularDependencyException; use Illuminate\Contracts\Container\Container as ContainerContract; use Illuminate\Contracts\Container\ContextualAttribute; +use Illuminate\Support\Collection; use LogicException; use ReflectionAttribute; use ReflectionClass; use ReflectionException; use ReflectionFunction; +use ReflectionIntersectionType; use ReflectionParameter; +use ReflectionUnionType; use TypeError; class Container implements ArrayAccess, ContainerContract @@ -268,15 +271,22 @@ public function isAlias($name) /** * Register a binding with the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void * * @throws \TypeError + * @throws ReflectionException */ public function bind($abstract, $concrete = null, $shared = false) { + if ($abstract instanceof Closure) { + return $this->bindBasedOnClosureReturnTypes( + $abstract, $concrete, $shared + ); + } + $this->dropStaleInstances($abstract); // If no concrete type was given, we will simply set the concrete type to the @@ -381,7 +391,7 @@ public function callMethodBinding($method, $instance) * Add a contextual binding to the container. * * @param string $concrete - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string $implementation * @return void */ @@ -393,7 +403,7 @@ public function addContextualBinding($concrete, $abstract, $implementation) /** * Register a binding if it hasn't already been registered. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void @@ -408,7 +418,7 @@ public function bindIf($abstract, $concrete = null, $shared = false) /** * Register a shared binding in the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -420,7 +430,7 @@ public function singleton($abstract, $concrete = null) /** * Register a shared binding if it hasn't already been registered. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -434,7 +444,7 @@ public function singletonIf($abstract, $concrete = null) /** * Register a scoped binding in the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -448,7 +458,7 @@ public function scoped($abstract, $concrete = null) /** * Register a scoped binding if it hasn't already been registered. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -459,6 +469,54 @@ public function scopedIf($abstract, $concrete = null) } } + /** + * Register a binding with the container based on the given Closure's return types. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + */ + protected function bindBasedOnClosureReturnTypes($abstract, $concrete = null, $shared = false) + { + $abstracts = $this->closureReturnTypes($abstract); + + $concrete = $abstract; + + foreach ($abstracts as $abstract) { + $this->bind($abstract, $concrete, $shared); + } + } + + /** + * Get the class names / types of the return type of the given Closure. + * + * @param \Closure $closure + * @return list + * + * @throws \ReflectionException + */ + protected function closureReturnTypes(Closure $closure) + { + $reflection = new ReflectionFunction($closure); + + if ($reflection->getReturnType() === null || + $reflection->getReturnType() instanceof ReflectionIntersectionType) { + return []; + } + + $types = $reflection->getReturnType() instanceof ReflectionUnionType + ? $reflection->getReturnType()->getTypes() + : [$reflection->getReturnType()]; + + return (new Collection($types)) + ->reject(fn ($type) => $type->isBuiltin()) + ->reject(fn ($type) => in_array($type->getName(), ['static', 'self'])) + ->map(fn ($type) => $type->getName()) + ->values() + ->all(); + } + /** * "Extend" an abstract type in the container. * diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index acd5dcf5eb9b..c00ddf5cafdb 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -56,7 +56,7 @@ public function tagged($tag); /** * Register a binding with the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void @@ -75,7 +75,7 @@ public function bindMethod($method, $callback); /** * Register a binding if it hasn't already been registered. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @param bool $shared * @return void @@ -85,7 +85,7 @@ public function bindIf($abstract, $concrete = null, $shared = false); /** * Register a shared binding in the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -94,7 +94,7 @@ public function singleton($abstract, $concrete = null); /** * Register a shared binding if it hasn't already been registered. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -103,7 +103,7 @@ public function singletonIf($abstract, $concrete = null); /** * Register a scoped binding in the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -112,7 +112,7 @@ public function scoped($abstract, $concrete = null); /** * Register a scoped binding if it hasn't already been registered. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string|null $concrete * @return void */ @@ -121,7 +121,7 @@ public function scopedIf($abstract, $concrete = null); /** * "Extend" an abstract type in the container. * - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure $closure * @return void * @@ -134,7 +134,7 @@ public function extend($abstract, Closure $closure); * * @template TInstance of mixed * - * @param string $abstract + * @param \Closure|string $abstract * @param TInstance $instance * @return TInstance */ @@ -144,7 +144,7 @@ public function instance($abstract, $instance); * Add a contextual binding to the container. * * @param string $concrete - * @param string $abstract + * @param \Closure|string $abstract * @param \Closure|string $implementation * @return void */ diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index fbe4414521fe..2ef9189cba19 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -40,6 +40,24 @@ public function testClosureResolution() $this->assertSame('Taylor', $container->make('name')); } + public function testAbstractCanBeBoundFromConcreteReturnType() + { + $container = new Container; + $container->bind(function (): IContainerContractStub|ContainerImplementationStub { + return new ContainerImplementationStub; + }); + $container->singleton(function (): ContainerConcreteStub { + return new ContainerConcreteStub; + }); + + $this->assertInstanceOf( + IContainerContractStub::class, + $container->make(IContainerContractStub::class) + ); + + $this->assertTrue($container->isShared(ContainerConcreteStub::class)); + } + public function testBindIfDoesntRegisterIfServiceAlreadyRegistered() { $container = new Container; From 156713352d0355825cfc31440b050aad628060a2 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:40:14 +0000 Subject: [PATCH 086/455] Update facade docblocks --- src/Illuminate/Support/Facades/App.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index fbf1035e54e6..ed8a9d6dce10 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -101,16 +101,16 @@ * @method static bool has(string $id) * @method static bool isShared(string $abstract) * @method static bool isAlias(string $name) - * @method static void bind(string $abstract, \Closure|string|null $concrete = null, bool $shared = false) + * @method static void bind(\Closure|string $abstract, \Closure|string|null $concrete = null, bool $shared = false) * @method static bool hasMethodBinding(string $method) * @method static void bindMethod(array|string $method, \Closure $callback) * @method static mixed callMethodBinding(string $method, mixed $instance) - * @method static void addContextualBinding(string $concrete, string $abstract, \Closure|string $implementation) - * @method static void bindIf(string $abstract, \Closure|string|null $concrete = null, bool $shared = false) - * @method static void singleton(string $abstract, \Closure|string|null $concrete = null) - * @method static void singletonIf(string $abstract, \Closure|string|null $concrete = null) - * @method static void scoped(string $abstract, \Closure|string|null $concrete = null) - * @method static void scopedIf(string $abstract, \Closure|string|null $concrete = null) + * @method static void addContextualBinding(string $concrete, \Closure|string $abstract, \Closure|string $implementation) + * @method static void bindIf(\Closure|string $abstract, \Closure|string|null $concrete = null, bool $shared = false) + * @method static void singleton(\Closure|string $abstract, \Closure|string|null $concrete = null) + * @method static void singletonIf(\Closure|string $abstract, \Closure|string|null $concrete = null) + * @method static void scoped(\Closure|string $abstract, \Closure|string|null $concrete = null) + * @method static void scopedIf(\Closure|string $abstract, \Closure|string|null $concrete = null) * @method static void extend(string $abstract, \Closure $closure) * @method static mixed instance(string $abstract, mixed $instance) * @method static void tag(array|string $abstracts, array|mixed $tags) From ca7ca2cddeff32427ca67c8bfd1e0f8a778a074c Mon Sep 17 00:00:00 2001 From: Bert Date: Mon, 17 Feb 2025 19:16:55 +0100 Subject: [PATCH 087/455] [12.x] Query builder PDO fetch modes (#54443) * fetchargs * add fetchArgs() function * fetchargs * add fetchArgs() function * add afterquery callbacks * fix typo * flip afterquerycallback * fix expectations * add expectations * add expectations * add expectations * add raw expression test * rename to fetchUsing * style * Remove test from PR #54396 * Revert most Query\Builder changes * remove DB::raw test * Revert QueryBuilder pluck tests * Add base tests for $query->fetchUsing() * style * formatting * Update Builder.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Connection.php | 19 +++-- .../Database/ConnectionInterface.php | 6 +- src/Illuminate/Database/Query/Builder.php | 75 +++++++++--------- ...EloquentBelongsToManyCreateOrFirstTest.php | 10 ++- ...tabaseEloquentBuilderCreateOrFirstTest.php | 28 +++---- ...tabaseEloquentHasManyCreateOrFirstTest.php | 18 ++--- ...loquentHasManyThroughCreateOrFirstTest.php | 9 +++ tests/Database/DatabaseQueryBuilderTest.php | 76 +++++++++---------- .../Integration/Database/QueryBuilderTest.php | 48 ++++++++++++ 9 files changed, 179 insertions(+), 110 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 69780f78a2b4..5d5be92e936f 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -389,11 +389,12 @@ public function selectFromWriteConnection($query, $bindings = []) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchUsing * @return array */ - public function select($query, $bindings = [], $useReadPdo = true) + public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) { if ($this->pretending()) { return []; } @@ -409,7 +410,7 @@ public function select($query, $bindings = [], $useReadPdo = true) $statement->execute(); - return $statement->fetchAll(); + return $statement->fetchAll(...$fetchUsing); }); } @@ -419,11 +420,12 @@ public function select($query, $bindings = [], $useReadPdo = true) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchUsing * @return array */ - public function selectResultSets($query, $bindings = [], $useReadPdo = true) + public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) { if ($this->pretending()) { return []; } @@ -439,7 +441,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true) $sets = []; do { - $sets[] = $statement->fetchAll(); + $sets[] = $statement->fetchAll(...$fetchUsing); } while ($statement->nextRowset()); return $sets; @@ -452,9 +454,10 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchUsing * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true) + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) { $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { @@ -479,7 +482,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true) return $statement; }); - while ($record = $statement->fetch()) { + while ($record = $statement->fetch(...$fetchUsing)) { yield $record; } } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 288adb4206e3..22f866b43763 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -51,9 +51,10 @@ public function scalar($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchUsing * @return array */ - public function select($query, $bindings = [], $useReadPdo = true); + public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []); /** * Run a select statement against the database and returns a generator. @@ -61,9 +62,10 @@ public function select($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchUsing * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true); + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []); /** * Run an insert statement against the database. diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 98e9a8eff5e3..108112b13f43 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -249,6 +249,13 @@ class Builder implements BuilderContract */ public $useWritePdo = false; + /** + * The custom arguments for the PDOStatement::fetchAll / fetch functions. + * + * @var array + */ + public array $fetchUsing = []; + /** * Create a new query builder instance. * @@ -3087,9 +3094,13 @@ public function soleValue($column) */ public function get($columns = ['*']) { - $items = new Collection($this->onceWithColumns(Arr::wrap($columns), function () { - return $this->processor->processSelect($this, $this->runSelect()); - })); + $original = $this->columns; + + $this->columns ??= Arr::wrap($columns); + + $items = new Collection($this->processor->processSelect($this, $this->runSelect())); + + $this->columns = $original; return $this->applyAfterQueryCallbacks( isset($this->groupLimit) ? $this->withoutGroupLimitKeys($items) : $items @@ -3104,7 +3115,7 @@ public function get($columns = ['*']) protected function runSelect() { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing ); } @@ -3322,7 +3333,7 @@ public function cursor() return (new LazyCollection(function () { yield from $this->connection->cursor( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing ); }))->map(function ($item) { return $this->applyAfterQueryCallbacks(new Collection([$item]))->first(); @@ -3352,17 +3363,18 @@ protected function enforceOrderBy() */ public function pluck($column, $key = null) { + $original = $this->columns; + // First, we will need to select the results of the query accounting for the // given columns / key. Once we have the results, we will be able to take // the results and get the exact data that was requested for the query. - $queryResult = $this->onceWithColumns( - is_null($key) || $key === $column ? [$column] : [$column, $key], - function () { - return $this->processor->processSelect( - $this, $this->runSelect() - ); - } - ); + $this->columns = is_null($key) || $key === $column + ? [$column] + : [$column, $key]; + + $queryResult = $this->processor->processSelect($this, $this->runSelect()); + + $this->columns = $original; if (empty($queryResult)) { return new Collection; @@ -3656,30 +3668,6 @@ protected function setAggregate($function, $columns) return $this; } - /** - * Execute the given callback while selecting the given columns. - * - * After running the callback, the columns are reset to the original value. - * - * @param array $columns - * @param callable $callback - * @return mixed - */ - protected function onceWithColumns($columns, $callback) - { - $original = $this->columns; - - if (is_null($original)) { - $this->columns = $columns; - } - - $result = $callback(); - - $this->columns = $original; - - return $result; - } - /** * Insert new records into the database. * @@ -4293,6 +4281,19 @@ public function useWritePdo() return $this; } + /** + * Specify arguments for the PDOStatement::fetchAll / fetch functions. + * + * @param mixed ...$fetchUsing + * @return $this + */ + public function fetchUsing(...$fetchUsing) + { + $this->fetchUsing = $fetchUsing; + + return $this; + } + /** * Determine if the value is a query builder instance or a Closure. * diff --git a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php index 8fb7dab36607..886bc47ef6c4 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php @@ -84,7 +84,7 @@ public function testCreateOrFirstMethodAssociatesExistingRelated(): void $source->getConnection() ->expects('select') - ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 456, 'attr' => 'foo', @@ -128,6 +128,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAlreadyAssociated 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 456, @@ -176,7 +177,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow $source->getConnection() ->expects('select') - ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 456, 'attr' => 'foo', @@ -199,6 +200,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], false, + [], ) ->andReturn([[ 'id' => 456, @@ -243,6 +245,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt() 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -252,6 +255,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt() 'select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, + [], ) ->andReturn([[ 'id' => 456, @@ -326,6 +330,7 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -335,6 +340,7 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore 'select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, + [], ) ->andReturn([]); diff --git a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php index 63cffe311f53..dcf9d912fe79 100755 --- a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php @@ -66,7 +66,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -95,7 +95,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -124,7 +124,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -152,7 +152,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -165,7 +165,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -194,7 +194,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -231,7 +231,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -259,7 +259,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -272,7 +272,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -309,7 +309,7 @@ public function testIncrementOrCreateMethodIncrementsExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -351,7 +351,7 @@ public function testIncrementOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -379,7 +379,7 @@ public function testIncrementOrCreateMethodIncrementParametersArePassed(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -423,7 +423,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $sql = 'insert into "table" ("attr", "count", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -436,7 +436,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', diff --git a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php index 5a3b9e5c1c06..38802b80f335 100755 --- a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php @@ -70,7 +70,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -102,7 +102,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -132,7 +132,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -164,7 +164,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $sql = 'insert into "child_table" ("attr", "val", "parent_id", "updated_at", "created_at") values (?, ?, ?, ?, ?)'; @@ -177,7 +177,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -209,7 +209,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -239,7 +239,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -276,7 +276,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $sql = 'insert into "child_table" ("attr", "val", "parent_id", "updated_at", "created_at") values (?, ?, ?, ?, ?)'; @@ -289,7 +289,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, diff --git a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php index b499100ef406..62acbbfe9e87 100644 --- a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php @@ -75,6 +75,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -114,6 +115,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -148,6 +150,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -187,6 +190,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -204,6 +208,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1', [123, 'foo', 'bar'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -243,6 +248,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -280,6 +286,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -327,6 +334,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -344,6 +352,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1', [123, 'foo', 'bar'], true, + [], ) ->andReturn([[ 'id' => 789, diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 1773aff32783..3671b47e90aa 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -82,12 +82,12 @@ public function testBasicSelectUseWritePdo() { $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with('select * from `users`', [], false); + ->with('select * from `users`', [], false, []); $builder->useWritePdo()->select('*')->from('users')->get(); $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with('select * from `users`', [], true); + ->with('select * from `users`', [], true, []); $builder->select('*')->from('users')->get(); } @@ -1747,31 +1747,31 @@ public function testUnionAggregate() { $expected = 'select count(*) as aggregate from ((select * from `posts`) union (select * from `videos`)) as `temp_table`'; $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from ((select `id` from `posts`) union (select `id` from `videos`)) as `temp_table`'; $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->select('id')->union($this->getMySqlBuilder()->from('videos')->select('id'))->count(); $expected = 'select count(*) as aggregate from ((select * from "posts") union (select * from "videos")) as "temp_table"'; $builder = $this->getPostgresBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getPostgresBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from (select * from (select * from "posts") union select * from (select * from "videos")) as "temp_table"'; $builder = $this->getSQLiteBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getSQLiteBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from (select * from (select * from [posts]) as [temp_table] union select * from (select * from [videos]) as [temp_table]) as [temp_table]'; $builder = $this->getSqlServerBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getSqlServerBuilder()->from('videos'))->count(); } @@ -1781,7 +1781,7 @@ public function testHavingAggregate() $expected = 'select count(*) as aggregate from (select (select `count(*)` from `videos` where `posts`.`id` = `videos`.`post_id`) as `videos_count` from `posts` having `videos_count` > ?) as `temp_table`'; $builder = $this->getMySqlBuilder(); $builder->getConnection()->shouldReceive('getDatabaseName'); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [0 => 1], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [0 => 1], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2263,7 +2263,7 @@ public function testHavingFollowedBySelectGet() { $builder = $this->getBuilder(); $query = 'select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > ?'; - $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular', 3], true)->andReturn([['category' => 'rock', 'total' => 5]]); + $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular', 3], true, [])->andReturn([['category' => 'rock', 'total' => 5]]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2274,7 +2274,7 @@ public function testHavingFollowedBySelectGet() // Using \Raw value $builder = $this->getBuilder(); $query = 'select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > 3'; - $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular'], true)->andReturn([['category' => 'rock', 'total' => 5]]); + $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular'], true, [])->andReturn([['category' => 'rock', 'total' => 5]]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2367,7 +2367,7 @@ public function testGetCountForPaginationWithBindings() $q->select('body')->from('posts')->where('id', 4); }, 'post'); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2383,7 +2383,7 @@ public function testGetCountForPaginationWithColumnAliases() $columns = ['body as post_body', 'teaser', 'posts.created as published']; $builder->from('posts')->select($columns); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("body", "teaser", "posts"."created") as aggregate from "posts"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("body", "teaser", "posts"."created") as aggregate from "posts"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2397,7 +2397,7 @@ public function testGetCountForPaginationWithUnion() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id')); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2411,7 +2411,7 @@ public function testGetCountForPaginationWithUnionOrders() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'))->latest(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2425,7 +2425,7 @@ public function testGetCountForPaginationWithUnionLimitAndOffset() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'))->take(15)->skip(1); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3412,7 +3412,7 @@ public function testRawExpressionsInSelect() public function testFindReturnsFirstResultByID() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3436,7 +3436,7 @@ public function testFindOrReturnsFirstResultByID() public function testFirstMethodReturnsFirstResult() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3447,7 +3447,7 @@ public function testFirstMethodReturnsFirstResult() public function testFirstOrFailMethodReturnsFirstResult() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3458,7 +3458,7 @@ public function testFirstOrFailMethodReturnsFirstResult() public function testFirstOrFailMethodThrowsRecordNotFoundException() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [])->andReturn([]); @@ -3490,7 +3490,7 @@ public function testPluckMethodGetsCollectionOfColumnValues() public function testPluckAvoidsDuplicateColumnSelection() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ?', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ?', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3522,7 +3522,7 @@ public function testImplode() public function testValueMethodReturnsSingleColumn() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturn([['foo' => 'bar']]); $results = $builder->from('users')->where('id', '=', 1)->value('foo'); $this->assertSame('bar', $results); @@ -3531,7 +3531,7 @@ public function testValueMethodReturnsSingleColumn() public function testRawValueMethodReturnsSingleColumn() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select UPPER("foo") from "users" where "id" = ? limit 1', [1], true)->andReturn([['UPPER("foo")' => 'BAR']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select UPPER("foo") from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['UPPER("foo")' => 'BAR']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['UPPER("foo")' => 'BAR']])->andReturn([['UPPER("foo")' => 'BAR']]); $results = $builder->from('users')->where('id', '=', 1)->rawValue('UPPER("foo")'); $this->assertSame('BAR', $results); @@ -3540,7 +3540,7 @@ public function testRawValueMethodReturnsSingleColumn() public function testAggregateFunctions() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3558,7 +3558,7 @@ public function testAggregateFunctions() $this->assertTrue($results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select max("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select max("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3566,7 +3566,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select min("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select min("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3574,7 +3574,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3582,7 +3582,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3590,7 +3590,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3641,9 +3641,9 @@ public function testDoesntExistsOr() public function testAggregateResetFollowedByGet() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 2]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column1", "column2" from "users"', [], true)->andReturn([['column1' => 'foo', 'column2' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 2]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column1", "column2" from "users"', [], true, [])->andReturn([['column1' => 'foo', 'column2' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3659,8 +3659,8 @@ public function testAggregateResetFollowedByGet() public function testAggregateResetFollowedBySelectGet() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true)->andReturn([['column2' => 'foo', 'column3' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true, [])->andReturn([['column2' => 'foo', 'column3' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3674,8 +3674,8 @@ public function testAggregateResetFollowedBySelectGet() public function testAggregateResetFollowedByGetWithColumns() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true)->andReturn([['column2' => 'foo', 'column3' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true, [])->andReturn([['column2' => 'foo', 'column3' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3689,7 +3689,7 @@ public function testAggregateResetFollowedByGetWithColumns() public function testAggregateWithSubSelect() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -5171,12 +5171,12 @@ public function testSelectWithLockUsesWritePdo() { $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with(m::any(), m::any(), false); + ->with(m::any(), m::any(), false, []); $builder->select('*')->from('foo')->where('bar', '=', 'baz')->lock()->get(); $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with(m::any(), m::any(), false); + ->with(m::any(), m::any(), false, []); $builder->select('*')->from('foo')->where('bar', '=', 'baz')->lock(false)->get(); } diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index c323ff0e1513..4e964149659a 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Testing\Assert as PHPUnit; use Orchestra\Testbench\Attributes\DefineEnvironment; +use PDO; use PDOException; class QueryBuilderTest extends DatabaseTestCase @@ -600,6 +601,12 @@ public function testChunkMap() public function testPluck() { + // Test empty result set. + $this->assertSame( + [], + DB::table('posts')->whereRaw('0=1')->pluck('title')->toArray() + ); + // Test SELECT override, since pluck will take the first column. $this->assertSame([ 'Foo Post', @@ -636,6 +643,47 @@ public function testPluck() ], DB::table('posts')->pluck('title', 'content')->toArray()); } + public function testFetchUsing() + { + // Fetch column as a list. + $this->assertSame([ + 'Foo Post', + 'Bar Post', + ], DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_COLUMN)->get()->toArray()); + + // Fetch the second column as a list (zero-indexed). + $this->assertSame([ + 'Lorem Ipsum.', + 'Lorem Ipsum.', + ], DB::table('posts')->select(['title', 'content'])->fetchUsing(PDO::FETCH_COLUMN, 1)->get()->toArray()); + + // Fetch two columns as key value pairs. + $this->assertSame([ + 1 => 'Foo Post', + 2 => 'Bar Post', + ], DB::table('posts')->select(['id', 'title'])->fetchUsing(PDO::FETCH_KEY_PAIR)->get()->toArray()); + + // Fetch data as associative array with custom key. + $result = DB::table('posts')->select(['id', 'title'])->fetchUsing(PDO::FETCH_UNIQUE)->get()->toArray(); + // Note: results are keyed by their post id here. + $this->assertSame('Foo Post', $result[1]->title); + $this->assertSame('Bar Post', $result[2]->title); + + // Use a cursor. + $this->assertSame([ + 'Foo Post', + 'Bar Post', + ], DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_COLUMN)->cursor()->collect()->toArray()); + + // Test the default 'object' fetch mode. + $result = DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_OBJ)->get()->toArray(); + $result2 = DB::table('posts')->select(['title'])->fetchUsing()->get()->toArray(); + $this->assertSame('Foo Post', $result[0]->title); + $this->assertSame('Bar Post', $result[1]->title); + $this->assertSame('Foo Post', $result2[0]->title); + $this->assertSame('Bar Post', $result2[1]->title); + } + protected function defineEnvironmentWouldThrowsPDOException($app) { $this->afterApplicationCreated(function () { From 3095072a9e0c3c8dd155f1ed5833076c434f2a3c Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 17 Feb 2025 18:17:35 +0000 Subject: [PATCH 088/455] Update facade docblocks --- src/Illuminate/Support/Facades/DB.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 3ddeae76298a..233816bf5767 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -40,9 +40,9 @@ * @method static mixed selectOne(string $query, array $bindings = [], bool $useReadPdo = true) * @method static mixed scalar(string $query, array $bindings = [], bool $useReadPdo = true) * @method static array selectFromWriteConnection(string $query, array $bindings = []) - * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static array selectResultSets(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static \Generator cursor(string $query, array $bindings = [], bool $useReadPdo = true) + * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true, array $fetchUsing = []) + * @method static array selectResultSets(string $query, array $bindings = [], bool $useReadPdo = true, array $fetchUsing = []) + * @method static \Generator cursor(string $query, array $bindings = [], bool $useReadPdo = true, array $fetchUsing = []) * @method static bool insert(string $query, array $bindings = []) * @method static int update(string $query, array $bindings = []) * @method static int delete(string $query, array $bindings = []) From 4f0f61019af32ad2a4b8be57babe413b19cc92bb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 18 Feb 2025 09:40:12 -0600 Subject: [PATCH 089/455] update split script --- bin/split.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/split.sh b/bin/split.sh index 9536ec7a4f31..ae4cdf01f8f3 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="master" +CURRENT_BRANCH="12.x" function split() { From 1bdd27064d0e02281eea561120de3f0b269de728 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Thu, 20 Feb 2025 03:08:33 +0800 Subject: [PATCH 090/455] [12.x] Fix Illuminate components `composer.json` (#54700) * [12.x] Fixes `illuminate/concurrency` and `illuminate/process` deps Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Bus/composer.json | 2 +- src/Illuminate/Concurrency/composer.json | 8 ++++---- src/Illuminate/Conditionable/composer.json | 2 +- src/Illuminate/Filesystem/composer.json | 2 +- src/Illuminate/Process/composer.json | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index 4f255d33abfa..dc3385da5120 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -31,7 +31,7 @@ } }, "suggest": { - "illuminate/queue": "Required to use closures when chaining jobs (^7.0)." + "illuminate/queue": "Required to use closures when chaining jobs (^12.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Concurrency/composer.json b/src/Illuminate/Concurrency/composer.json index 8d542d699155..eb4e9467f66e 100644 --- a/src/Illuminate/Concurrency/composer.json +++ b/src/Illuminate/Concurrency/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^8.2", - "illuminate/console": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/process": "^11.0", - "illuminate/support": "^11.0", + "illuminate/console": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/process": "^12.0", + "illuminate/support": "^12.0", "laravel/serializable-closure": "^1.3|^2.0" }, "autoload": { diff --git a/src/Illuminate/Conditionable/composer.json b/src/Illuminate/Conditionable/composer.json index 919f09ef4611..9e0ddfbbdcf1 100644 --- a/src/Illuminate/Conditionable/composer.json +++ b/src/Illuminate/Conditionable/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "^8.0.2" + "php": "^8.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 8e4352665cb4..f5fa95db75a5 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -38,7 +38,7 @@ "ext-fileinfo": "Required to use the Filesystem class.", "ext-ftp": "Required to use the Flysystem FTP driver.", "ext-hash": "Required to use the Filesystem class.", - "illuminate/http": "Required for handling uploaded files (^7.2).", + "illuminate/http": "Required for handling uploaded files (^12.0).", "league/flysystem": "Required to use the Flysystem local driver (^3.25.1).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", diff --git a/src/Illuminate/Process/composer.json b/src/Illuminate/Process/composer.json index 0f2a57773644..63c4afad444f 100644 --- a/src/Illuminate/Process/composer.json +++ b/src/Illuminate/Process/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^8.2", - "illuminate/collections": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/macroable": "^11.0", - "illuminate/support": "^11.0", + "illuminate/collections": "^12.0", + "illuminate/contracts": "^12.0", + "illuminate/macroable": "^12.0", + "illuminate/support": "^12.0", "symfony/process": "^7.2.0" }, "autoload": { From f94f70c3edaeaf83a6e3031966bd9b38d5020c31 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Thu, 20 Feb 2025 03:08:52 +0800 Subject: [PATCH 091/455] [12.x] Bump minimum `brick/math` (#54694) * [12.x] Bump minimum `brick/math` Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- composer.json | 2 +- src/Illuminate/Database/composer.json | 2 +- src/Illuminate/Validation/composer.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index af09d946e602..46b926adcf40 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "ext-session": "*", "ext-tokenizer": "*", "composer-runtime-api": "^2.2", - "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", + "brick/math": "^0.11|^0.12", "doctrine/inflector": "^2.0.5", "dragonmantank/cron-expression": "^3.4", "egulias/email-validator": "^3.2.1|^4.0", diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 65829cdf56f3..24ac5a219201 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -17,7 +17,7 @@ "require": { "php": "^8.2", "ext-pdo": "*", - "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", + "brick/math": "^0.11|^0.12", "illuminate/collections": "^12.0", "illuminate/container": "^12.0", "illuminate/contracts": "^12.0", diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 93a4c2e071dc..020433ac0016 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -17,7 +17,7 @@ "php": "^8.2", "ext-filter": "*", "ext-mbstring": "*", - "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", + "brick/math": "^0.11|^0.12", "egulias/email-validator": "^3.2.5|^4.0", "illuminate/collections": "^12.0", "illuminate/container": "^12.0", From 8c382079da9d394c1f7caa2c0558cc98aa1232fb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 19 Feb 2025 10:00:17 -0600 Subject: [PATCH 092/455] Revert "[12.x] Query builder PDO fetch modes (#54443)" (#54709) This reverts commit ca7ca2cddeff32427ca67c8bfd1e0f8a778a074c. --- src/Illuminate/Database/Connection.php | 19 ++--- .../Database/ConnectionInterface.php | 6 +- src/Illuminate/Database/Query/Builder.php | 75 +++++++++--------- ...EloquentBelongsToManyCreateOrFirstTest.php | 10 +-- ...tabaseEloquentBuilderCreateOrFirstTest.php | 28 +++---- ...tabaseEloquentHasManyCreateOrFirstTest.php | 18 ++--- ...loquentHasManyThroughCreateOrFirstTest.php | 9 --- tests/Database/DatabaseQueryBuilderTest.php | 76 +++++++++---------- .../Integration/Database/QueryBuilderTest.php | 48 ------------ 9 files changed, 110 insertions(+), 179 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 5d5be92e936f..69780f78a2b4 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -389,12 +389,11 @@ public function selectFromWriteConnection($query, $bindings = []) * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchUsing * @return array */ - public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) + public function select($query, $bindings = [], $useReadPdo = true) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } @@ -410,7 +409,7 @@ public function select($query, $bindings = [], $useReadPdo = true, array $fetchU $statement->execute(); - return $statement->fetchAll(...$fetchUsing); + return $statement->fetchAll(); }); } @@ -420,12 +419,11 @@ public function select($query, $bindings = [], $useReadPdo = true, array $fetchU * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchUsing * @return array */ - public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) + public function selectResultSets($query, $bindings = [], $useReadPdo = true) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } @@ -441,7 +439,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true, arr $sets = []; do { - $sets[] = $statement->fetchAll(...$fetchUsing); + $sets[] = $statement->fetchAll(); } while ($statement->nextRowset()); return $sets; @@ -454,10 +452,9 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true, arr * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchUsing * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) + public function cursor($query, $bindings = [], $useReadPdo = true) { $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { @@ -482,7 +479,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchU return $statement; }); - while ($record = $statement->fetch(...$fetchUsing)) { + while ($record = $statement->fetch()) { yield $record; } } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 22f866b43763..288adb4206e3 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -51,10 +51,9 @@ public function scalar($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchUsing * @return array */ - public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []); + public function select($query, $bindings = [], $useReadPdo = true); /** * Run a select statement against the database and returns a generator. @@ -62,10 +61,9 @@ public function select($query, $bindings = [], $useReadPdo = true, array $fetchU * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchUsing * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []); + public function cursor($query, $bindings = [], $useReadPdo = true); /** * Run an insert statement against the database. diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0266f24cfe69..c5db6b31060e 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -249,13 +249,6 @@ class Builder implements BuilderContract */ public $useWritePdo = false; - /** - * The custom arguments for the PDOStatement::fetchAll / fetch functions. - * - * @var array - */ - public array $fetchUsing = []; - /** * Create a new query builder instance. * @@ -3094,13 +3087,9 @@ public function soleValue($column) */ public function get($columns = ['*']) { - $original = $this->columns; - - $this->columns ??= Arr::wrap($columns); - - $items = new Collection($this->processor->processSelect($this, $this->runSelect())); - - $this->columns = $original; + $items = new Collection($this->onceWithColumns(Arr::wrap($columns), function () { + return $this->processor->processSelect($this, $this->runSelect()); + })); return $this->applyAfterQueryCallbacks( isset($this->groupLimit) ? $this->withoutGroupLimitKeys($items) : $items @@ -3115,7 +3104,7 @@ public function get($columns = ['*']) protected function runSelect() { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing + $this->toSql(), $this->getBindings(), ! $this->useWritePdo ); } @@ -3333,7 +3322,7 @@ public function cursor() return (new LazyCollection(function () { yield from $this->connection->cursor( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing + $this->toSql(), $this->getBindings(), ! $this->useWritePdo ); }))->map(function ($item) { return $this->applyAfterQueryCallbacks(new Collection([$item]))->first(); @@ -3363,18 +3352,17 @@ protected function enforceOrderBy() */ public function pluck($column, $key = null) { - $original = $this->columns; - // First, we will need to select the results of the query accounting for the // given columns / key. Once we have the results, we will be able to take // the results and get the exact data that was requested for the query. - $this->columns = is_null($key) || $key === $column - ? [$column] - : [$column, $key]; - - $queryResult = $this->processor->processSelect($this, $this->runSelect()); - - $this->columns = $original; + $queryResult = $this->onceWithColumns( + is_null($key) || $key === $column ? [$column] : [$column, $key], + function () { + return $this->processor->processSelect( + $this, $this->runSelect() + ); + } + ); if (empty($queryResult)) { return new Collection; @@ -3668,6 +3656,30 @@ protected function setAggregate($function, $columns) return $this; } + /** + * Execute the given callback while selecting the given columns. + * + * After running the callback, the columns are reset to the original value. + * + * @param array $columns + * @param callable $callback + * @return mixed + */ + protected function onceWithColumns($columns, $callback) + { + $original = $this->columns; + + if (is_null($original)) { + $this->columns = $columns; + } + + $result = $callback(); + + $this->columns = $original; + + return $result; + } + /** * Insert new records into the database. * @@ -4281,19 +4293,6 @@ public function useWritePdo() return $this; } - /** - * Specify arguments for the PDOStatement::fetchAll / fetch functions. - * - * @param mixed ...$fetchUsing - * @return $this - */ - public function fetchUsing(...$fetchUsing) - { - $this->fetchUsing = $fetchUsing; - - return $this; - } - /** * Determine if the value is a query builder instance or a Closure. * diff --git a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php index 886bc47ef6c4..8fb7dab36607 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php @@ -84,7 +84,7 @@ public function testCreateOrFirstMethodAssociatesExistingRelated(): void $source->getConnection() ->expects('select') - ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([[ 'id' => 456, 'attr' => 'foo', @@ -128,7 +128,6 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAlreadyAssociated 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([[ 'id' => 456, @@ -177,7 +176,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow $source->getConnection() ->expects('select') - ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([[ 'id' => 456, 'attr' => 'foo', @@ -200,7 +199,6 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], false, - [], ) ->andReturn([[ 'id' => 456, @@ -245,7 +243,6 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt() 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([]); @@ -255,7 +252,6 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt() 'select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, - [], ) ->andReturn([[ 'id' => 456, @@ -330,7 +326,6 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([]); @@ -340,7 +335,6 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore 'select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, - [], ) ->andReturn([]); diff --git a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php index dcf9d912fe79..63cffe311f53 100755 --- a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php @@ -66,7 +66,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -95,7 +95,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -124,7 +124,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -152,7 +152,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([]); $sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -165,7 +165,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -194,7 +194,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -231,7 +231,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -259,7 +259,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([]); $sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -272,7 +272,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -309,7 +309,7 @@ public function testIncrementOrCreateMethodIncrementsExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -351,7 +351,7 @@ public function testIncrementOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -379,7 +379,7 @@ public function testIncrementOrCreateMethodIncrementParametersArePassed(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -423,7 +423,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) ->andReturn([]); $sql = 'insert into "table" ("attr", "count", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -436,7 +436,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) ->andReturn([[ 'id' => 123, 'attr' => 'foo', diff --git a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php index 38802b80f335..5a3b9e5c1c06 100755 --- a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php @@ -70,7 +70,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -102,7 +102,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -132,7 +132,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -164,7 +164,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) ->andReturn([]); $sql = 'insert into "child_table" ("attr", "val", "parent_id", "updated_at", "created_at") values (?, ?, ?, ?, ?)'; @@ -177,7 +177,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -209,7 +209,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -239,7 +239,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -276,7 +276,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) ->andReturn([]); $sql = 'insert into "child_table" ("attr", "val", "parent_id", "updated_at", "created_at") values (?, ?, ?, ?, ?)'; @@ -289,7 +289,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) ->andReturn([[ 'id' => 456, 'parent_id' => 123, diff --git a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php index 62acbbfe9e87..b499100ef406 100644 --- a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php @@ -75,7 +75,6 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([[ 'id' => 789, @@ -115,7 +114,6 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([]); @@ -150,7 +148,6 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([[ 'id' => 789, @@ -190,7 +187,6 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([]); @@ -208,7 +204,6 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1', [123, 'foo', 'bar'], true, - [], ) ->andReturn([[ 'id' => 789, @@ -248,7 +243,6 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([]); @@ -286,7 +280,6 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([[ 'id' => 789, @@ -334,7 +327,6 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, - [], ) ->andReturn([]); @@ -352,7 +344,6 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1', [123, 'foo', 'bar'], true, - [], ) ->andReturn([[ 'id' => 789, diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 3671b47e90aa..1773aff32783 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -82,12 +82,12 @@ public function testBasicSelectUseWritePdo() { $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with('select * from `users`', [], false, []); + ->with('select * from `users`', [], false); $builder->useWritePdo()->select('*')->from('users')->get(); $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with('select * from `users`', [], true, []); + ->with('select * from `users`', [], true); $builder->select('*')->from('users')->get(); } @@ -1747,31 +1747,31 @@ public function testUnionAggregate() { $expected = 'select count(*) as aggregate from ((select * from `posts`) union (select * from `videos`)) as `temp_table`'; $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from ((select `id` from `posts`) union (select `id` from `videos`)) as `temp_table`'; $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->select('id')->union($this->getMySqlBuilder()->from('videos')->select('id'))->count(); $expected = 'select count(*) as aggregate from ((select * from "posts") union (select * from "videos")) as "temp_table"'; $builder = $this->getPostgresBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getPostgresBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from (select * from (select * from "posts") union select * from (select * from "videos")) as "temp_table"'; $builder = $this->getSQLiteBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getSQLiteBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from (select * from (select * from [posts]) as [temp_table] union select * from (select * from [videos]) as [temp_table]) as [temp_table]'; $builder = $this->getSqlServerBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getSqlServerBuilder()->from('videos'))->count(); } @@ -1781,7 +1781,7 @@ public function testHavingAggregate() $expected = 'select count(*) as aggregate from (select (select `count(*)` from `videos` where `posts`.`id` = `videos`.`post_id`) as `videos_count` from `posts` having `videos_count` > ?) as `temp_table`'; $builder = $this->getMySqlBuilder(); $builder->getConnection()->shouldReceive('getDatabaseName'); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [0 => 1], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [0 => 1], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2263,7 +2263,7 @@ public function testHavingFollowedBySelectGet() { $builder = $this->getBuilder(); $query = 'select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > ?'; - $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular', 3], true, [])->andReturn([['category' => 'rock', 'total' => 5]]); + $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular', 3], true)->andReturn([['category' => 'rock', 'total' => 5]]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2274,7 +2274,7 @@ public function testHavingFollowedBySelectGet() // Using \Raw value $builder = $this->getBuilder(); $query = 'select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > 3'; - $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular'], true, [])->andReturn([['category' => 'rock', 'total' => 5]]); + $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular'], true)->andReturn([['category' => 'rock', 'total' => 5]]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2367,7 +2367,7 @@ public function testGetCountForPaginationWithBindings() $q->select('body')->from('posts')->where('id', 4); }, 'post'); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2383,7 +2383,7 @@ public function testGetCountForPaginationWithColumnAliases() $columns = ['body as post_body', 'teaser', 'posts.created as published']; $builder->from('posts')->select($columns); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("body", "teaser", "posts"."created") as aggregate from "posts"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("body", "teaser", "posts"."created") as aggregate from "posts"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2397,7 +2397,7 @@ public function testGetCountForPaginationWithUnion() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id')); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2411,7 +2411,7 @@ public function testGetCountForPaginationWithUnionOrders() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'))->latest(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2425,7 +2425,7 @@ public function testGetCountForPaginationWithUnionLimitAndOffset() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'))->take(15)->skip(1); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3412,7 +3412,7 @@ public function testRawExpressionsInSelect() public function testFindReturnsFirstResultByID() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3436,7 +3436,7 @@ public function testFindOrReturnsFirstResultByID() public function testFirstMethodReturnsFirstResult() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3447,7 +3447,7 @@ public function testFirstMethodReturnsFirstResult() public function testFirstOrFailMethodReturnsFirstResult() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3458,7 +3458,7 @@ public function testFirstOrFailMethodReturnsFirstResult() public function testFirstOrFailMethodThrowsRecordNotFoundException() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [])->andReturn([]); @@ -3490,7 +3490,7 @@ public function testPluckMethodGetsCollectionOfColumnValues() public function testPluckAvoidsDuplicateColumnSelection() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ?', [1], true, [])->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ?', [1], true)->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3522,7 +3522,7 @@ public function testImplode() public function testValueMethodReturnsSingleColumn() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturn([['foo' => 'bar']]); $results = $builder->from('users')->where('id', '=', 1)->value('foo'); $this->assertSame('bar', $results); @@ -3531,7 +3531,7 @@ public function testValueMethodReturnsSingleColumn() public function testRawValueMethodReturnsSingleColumn() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select UPPER("foo") from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['UPPER("foo")' => 'BAR']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select UPPER("foo") from "users" where "id" = ? limit 1', [1], true)->andReturn([['UPPER("foo")' => 'BAR']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['UPPER("foo")' => 'BAR']])->andReturn([['UPPER("foo")' => 'BAR']]); $results = $builder->from('users')->where('id', '=', 1)->rawValue('UPPER("foo")'); $this->assertSame('BAR', $results); @@ -3540,7 +3540,7 @@ public function testRawValueMethodReturnsSingleColumn() public function testAggregateFunctions() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3558,7 +3558,7 @@ public function testAggregateFunctions() $this->assertTrue($results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select max("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select max("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3566,7 +3566,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select min("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select min("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3574,7 +3574,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3582,7 +3582,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3590,7 +3590,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3641,9 +3641,9 @@ public function testDoesntExistsOr() public function testAggregateResetFollowedByGet() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 2]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column1", "column2" from "users"', [], true, [])->andReturn([['column1' => 'foo', 'column2' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 2]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column1", "column2" from "users"', [], true)->andReturn([['column1' => 'foo', 'column2' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3659,8 +3659,8 @@ public function testAggregateResetFollowedByGet() public function testAggregateResetFollowedBySelectGet() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true, [])->andReturn([['column2' => 'foo', 'column3' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true)->andReturn([['column2' => 'foo', 'column3' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3674,8 +3674,8 @@ public function testAggregateResetFollowedBySelectGet() public function testAggregateResetFollowedByGetWithColumns() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true, [])->andReturn([['column2' => 'foo', 'column3' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true)->andReturn([['column2' => 'foo', 'column3' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3689,7 +3689,7 @@ public function testAggregateResetFollowedByGetWithColumns() public function testAggregateWithSubSelect() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -5171,12 +5171,12 @@ public function testSelectWithLockUsesWritePdo() { $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with(m::any(), m::any(), false, []); + ->with(m::any(), m::any(), false); $builder->select('*')->from('foo')->where('bar', '=', 'baz')->lock()->get(); $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with(m::any(), m::any(), false, []); + ->with(m::any(), m::any(), false); $builder->select('*')->from('foo')->where('bar', '=', 'baz')->lock(false)->get(); } diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 4e964149659a..c323ff0e1513 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -11,7 +11,6 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Testing\Assert as PHPUnit; use Orchestra\Testbench\Attributes\DefineEnvironment; -use PDO; use PDOException; class QueryBuilderTest extends DatabaseTestCase @@ -601,12 +600,6 @@ public function testChunkMap() public function testPluck() { - // Test empty result set. - $this->assertSame( - [], - DB::table('posts')->whereRaw('0=1')->pluck('title')->toArray() - ); - // Test SELECT override, since pluck will take the first column. $this->assertSame([ 'Foo Post', @@ -643,47 +636,6 @@ public function testPluck() ], DB::table('posts')->pluck('title', 'content')->toArray()); } - public function testFetchUsing() - { - // Fetch column as a list. - $this->assertSame([ - 'Foo Post', - 'Bar Post', - ], DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_COLUMN)->get()->toArray()); - - // Fetch the second column as a list (zero-indexed). - $this->assertSame([ - 'Lorem Ipsum.', - 'Lorem Ipsum.', - ], DB::table('posts')->select(['title', 'content'])->fetchUsing(PDO::FETCH_COLUMN, 1)->get()->toArray()); - - // Fetch two columns as key value pairs. - $this->assertSame([ - 1 => 'Foo Post', - 2 => 'Bar Post', - ], DB::table('posts')->select(['id', 'title'])->fetchUsing(PDO::FETCH_KEY_PAIR)->get()->toArray()); - - // Fetch data as associative array with custom key. - $result = DB::table('posts')->select(['id', 'title'])->fetchUsing(PDO::FETCH_UNIQUE)->get()->toArray(); - // Note: results are keyed by their post id here. - $this->assertSame('Foo Post', $result[1]->title); - $this->assertSame('Bar Post', $result[2]->title); - - // Use a cursor. - $this->assertSame([ - 'Foo Post', - 'Bar Post', - ], DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_COLUMN)->cursor()->collect()->toArray()); - - // Test the default 'object' fetch mode. - $result = DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_OBJ)->get()->toArray(); - $result2 = DB::table('posts')->select(['title'])->fetchUsing()->get()->toArray(); - $this->assertSame('Foo Post', $result[0]->title); - $this->assertSame('Bar Post', $result[1]->title); - $this->assertSame('Foo Post', $result2[0]->title); - $this->assertSame('Bar Post', $result2[1]->title); - } - protected function defineEnvironmentWouldThrowsPDOException($app) { $this->afterApplicationCreated(function () { From 19aac07772c2155eaadaf08f412952d90a29da99 Mon Sep 17 00:00:00 2001 From: crynobone <172966+crynobone@users.noreply.github.com> Date: Wed, 19 Feb 2025 22:49:01 +0000 Subject: [PATCH 093/455] Update facade docblocks --- src/Illuminate/Support/Facades/DB.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 233816bf5767..3ddeae76298a 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -40,9 +40,9 @@ * @method static mixed selectOne(string $query, array $bindings = [], bool $useReadPdo = true) * @method static mixed scalar(string $query, array $bindings = [], bool $useReadPdo = true) * @method static array selectFromWriteConnection(string $query, array $bindings = []) - * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true, array $fetchUsing = []) - * @method static array selectResultSets(string $query, array $bindings = [], bool $useReadPdo = true, array $fetchUsing = []) - * @method static \Generator cursor(string $query, array $bindings = [], bool $useReadPdo = true, array $fetchUsing = []) + * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true) + * @method static array selectResultSets(string $query, array $bindings = [], bool $useReadPdo = true) + * @method static \Generator cursor(string $query, array $bindings = [], bool $useReadPdo = true) * @method static bool insert(string $query, array $bindings = []) * @method static int update(string $query, array $bindings = []) * @method static int delete(string $query, array $bindings = []) From 17b8f6dada215d5fedcd25b3141a01a007566cab Mon Sep 17 00:00:00 2001 From: askdkc Date: Sun, 23 Feb 2025 23:17:51 +0900 Subject: [PATCH 094/455] Update `config/app.php` to reflect laravel/laravel change for compatibility (#54752) * Update app.php to reflect laravel/laravel change * Update app.php --- config-stubs/app.php | 2 +- config/app.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config-stubs/app.php b/config-stubs/app.php index f46726731e4a..324b513a2733 100644 --- a/config-stubs/app.php +++ b/config-stubs/app.php @@ -65,7 +65,7 @@ | */ - 'timezone' => env('APP_TIMEZONE', 'UTC'), + 'timezone' => 'UTC', /* |-------------------------------------------------------------------------- diff --git a/config/app.php b/config/app.php index d4e3180fa6fc..16073173f8f8 100644 --- a/config/app.php +++ b/config/app.php @@ -72,7 +72,7 @@ | */ - 'timezone' => env('APP_TIMEZONE', 'UTC'), + 'timezone' => 'UTC', /* |-------------------------------------------------------------------------- From 703e7fb3227ebcdf6301a9bf15970c454780fde8 Mon Sep 17 00:00:00 2001 From: Androshchuk Andrii Date: Sun, 23 Feb 2025 17:47:58 +0200 Subject: [PATCH 095/455] Add Env::addExtraAdapter to support extra adapters when loading environment variables --- src/Illuminate/Support/Env.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Illuminate/Support/Env.php b/src/Illuminate/Support/Env.php index 51ea918e0a4e..c9da01e5c6da 100644 --- a/src/Illuminate/Support/Env.php +++ b/src/Illuminate/Support/Env.php @@ -2,6 +2,7 @@ namespace Illuminate\Support; +use Closure; use Dotenv\Repository\Adapter\PutenvAdapter; use Dotenv\Repository\RepositoryBuilder; use PhpOption\Option; @@ -23,6 +24,13 @@ class Env */ protected static $repository; + /** + * The list of custom adapters for environment variables loading. + * + * @var array + */ + protected static $customAdapters = []; + /** * Enable the putenv adapter. * @@ -45,6 +53,16 @@ public static function disablePutenv() static::$repository = null; } + /** + * Register a custom adapter creator Closure. + * + * @return void + */ + public static function extend($name, Closure $callback) + { + static::$customAdapters[$name] = $callback; + } + /** * Get the environment repository instance. * @@ -59,6 +77,10 @@ public static function getRepository() $builder = $builder->addAdapter(PutenvAdapter::class); } + foreach (static::$customAdapters as $adapter) { + $builder = $builder->addAdapter($adapter()); + } + static::$repository = $builder->immutable()->make(); } From e2627a5802b1c93170c64cdf5431107e6c481201 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 23 Feb 2025 10:18:06 -0600 Subject: [PATCH 096/455] formatting --- src/Illuminate/Support/Env.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Support/Env.php b/src/Illuminate/Support/Env.php index c9da01e5c6da..702f61d44f4c 100644 --- a/src/Illuminate/Support/Env.php +++ b/src/Illuminate/Support/Env.php @@ -25,7 +25,7 @@ class Env protected static $repository; /** - * The list of custom adapters for environment variables loading. + * The list of custom adapters for loading environment variables. * * @var array */ @@ -55,12 +55,14 @@ public static function disablePutenv() /** * Register a custom adapter creator Closure. - * - * @return void */ - public static function extend($name, Closure $callback) + public static function extend(Closure $callback, ?string $name = null): void { - static::$customAdapters[$name] = $callback; + if (! is_null($name)) { + static::$customAdapters[$name] = $callback; + } else { + static::$customAdapters[] = $callback; + } } /** From 2d0d986223509d011183fd9bf5663b820ace2bbd Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 24 Feb 2025 20:53:52 +0800 Subject: [PATCH 097/455] [12.x] Sync `filesystem.disk.local` configurations (#54764) * https://github.com/laravel/laravel/pull/6450 Signed-off-by: Mior Muhammad Zaki --- config/filesystems.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/filesystems.php b/config/filesystems.php index c9bd1d09468f..3d671bd9105e 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -32,7 +32,8 @@ 'local' => [ 'driver' => 'local', - 'root' => storage_path('app'), + 'root' => storage_path('app/private'), + 'serve' => true, 'throw' => false, 'report' => false, ], From 376e9f19da9cc37858a55572a9d2ef0be9830c35 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 24 Feb 2025 13:17:43 +0000 Subject: [PATCH 098/455] Update CHANGELOG --- CHANGELOG.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e15585ce85..5491984024fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,89 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.44.0..v12.0.0) +## [Unreleased](https://github.com/laravel/framework/compare/v12.0.0...12.x) + +## [v12.0.0](https://github.com/laravel/framework/compare/v11.44.0..v12.0.0...v12.0.0) - 2025-02-24 + +* [12.x] Prep Laravel v12 by [@driesvints](https://github.com/driesvints) in https://github.com/laravel/framework/pull/50406 +* [12.x] Make `Str::is()` match multiline strings by [@SjorsO](https://github.com/SjorsO) in https://github.com/laravel/framework/pull/51196 +* [12.x] Use native MariaDB CLI commands by [@staudenmeir](https://github.com/staudenmeir) in https://github.com/laravel/framework/pull/51505 +* [12.x] Adds missing streamJson() to ResponseFactory contract by [@wilsenhc](https://github.com/wilsenhc) in https://github.com/laravel/framework/pull/51544 +* [12.x] Preserve numeric keys on the first level of the validator rules by [@Tofandel](https://github.com/Tofandel) in https://github.com/laravel/framework/pull/51516 +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/52248 +* [12.x] mergeIfMissing allows merging with nested arrays by [@KIKOmanasijev](https://github.com/KIKOmanasijev) in https://github.com/laravel/framework/pull/52242 +* [12.x] Fix chunked queries not honoring user-defined limits and offsets by [@tonysm](https://github.com/tonysm) in https://github.com/laravel/framework/pull/52093 +* [12.x] Replace md5 with much faster xxhash by [@GrahamCampbell](https://github.com/GrahamCampbell) in https://github.com/laravel/framework/pull/52301 +* [12.x] Switch models to UUID v7 by [@staudenmeir](https://github.com/staudenmeir) in https://github.com/laravel/framework/pull/52433 +* [12.x] Improved algorithm for Number::pairs() by [@hotmeteor](https://github.com/hotmeteor) in https://github.com/laravel/framework/pull/52641 +* Removed Duplicated Prefix on DynamoDbStore.php by [@felipehertzer](https://github.com/felipehertzer) in https://github.com/laravel/framework/pull/52986 +* [12.x] feat: configure default datetime precision on per-grammar basis by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/51821 +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/53150 +* [12.x] Fix laravel/prompt dependency version constraint for illuminate/console by [@wouterj](https://github.com/wouterj) in https://github.com/laravel/framework/pull/53146 +* [12.x] Add generic return type to Container::instance() by [@axlon](https://github.com/axlon) in https://github.com/laravel/framework/pull/53161 +* Map output of concurrecy calls to the index of the input by [@ovp87](https://github.com/ovp87) in https://github.com/laravel/framework/pull/53135 +* Change Composer hasPackage to public by [@buihanh2304](https://github.com/buihanh2304) in https://github.com/laravel/framework/pull/53282 +* [12.x] force `Eloquent\Collection::partition` to return a base `Collection` by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53304 +* [12.x] Better support for multi-dbs in the `RefreshDatabase` trait by [@tonysm](https://github.com/tonysm) in https://github.com/laravel/framework/pull/53231 +* [12.x] Validate UUID's version optionally by [@shaedrich](https://github.com/shaedrich) in https://github.com/laravel/framework/pull/53341 +* [12.x] Validate UUID version 2 and max by [@shaedrich](https://github.com/shaedrich) in https://github.com/laravel/framework/pull/53368 +* [12.x] Add step parameter to LazyCollection range method by [@Ashot1995](https://github.com/Ashot1995) in https://github.com/laravel/framework/pull/53473 +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/53524 +* [12.x] Avoid breaking change `RefreshDatabase::usingInMemoryDatabase()` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/53587 +* [12.x] fix: container resolution order when resolving class dependencies by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/53522 +* [12.x] Change the default for scheduled command `emailOutput()` to only send email if output exists by [@onlime](https://github.com/onlime) in https://github.com/laravel/framework/pull/53774 +* [12.x] Add `hasMorePages()` to `CursorPaginator` contract by [@KennedyTedesco](https://github.com/KennedyTedesco) in https://github.com/laravel/framework/pull/53762 +* [12.x] modernize `DatabaseTokenRepository` and make consistent with `CacheTokenRepository` by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53746 +* [12.x] chore: remove support for Carbon v2 by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/53825 +* [12.x] use promoted properties for Auth events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53847 +* [12.x] use promoted properties for Database events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53848 +* [12.x] use promoted properties for Console events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53851 +* [12.x] use promoted properties for Mail events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53852 +* [12.x] use promoted properties for Notification events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53853 +* [12.x] use promoted properties for Routing events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53854 +* [12.x] use promoted properties for Queue events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53855 +* [12.x] Restore database token repository property documentation by [@shaedrich](https://github.com/shaedrich) in https://github.com/laravel/framework/pull/53908 +* [12.x] Use reject() instead of a negated filter() by [@shaedrich](https://github.com/shaedrich) in https://github.com/laravel/framework/pull/53925 +* [12.x] Use first-class callable syntax to improve static analysis by [@shaedrich](https://github.com/shaedrich) in https://github.com/laravel/framework/pull/53924 +* [12.x] add type declarations for Console Events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53947 +* [12.x] use type declaration on property by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/53970 +* [12.x] Update Symfony and PHPUnit dependencies by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54019 +* [12.x] Allow `when()` helper to accept Closure condition parameter by [@ziadoz](https://github.com/ziadoz) in https://github.com/laravel/framework/pull/54005 +* [12.x] Add test for collapse in collections by [@amirmohammadnajmi](https://github.com/amirmohammadnajmi) in https://github.com/laravel/framework/pull/54032 +* [12.x] Add test for benchmark utilities by [@amirmohammadnajmi](https://github.com/amirmohammadnajmi) in https://github.com/laravel/framework/pull/54055 +* [12.x] Fix once() cache when used in extended static class by [@FrittenKeeZ](https://github.com/FrittenKeeZ) in https://github.com/laravel/framework/pull/54094 +* [12.x] Ignore querystring parameters using closure when validating signed url by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/54104 +* Make `dropForeignIdFor` method complementary to `foreignIdFor` by [@willrowe](https://github.com/willrowe) in https://github.com/laravel/framework/pull/54102 +* Allow scoped disks to be scoped from other scoped disks by [@willrowe](https://github.com/willrowe) in https://github.com/laravel/framework/pull/54124 +* [12.x] Add test for Util::getParameterClassName() by [@amirmohammadnajmi](https://github.com/amirmohammadnajmi) in https://github.com/laravel/framework/pull/54209 +* Improve eloquent attach parameter consistency by [@fabpl](https://github.com/fabpl) in https://github.com/laravel/framework/pull/54225 +* [12.x] Enhance multi-database support by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/54274 +* [12.x] Fix Session's `getCookieExpirationDate` incompatibility with Carbon 3 by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54313 +* [12.x] Update minimum PHPUnit versions by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54323 +* [12.x] Prevent XSS vulnerabilities by excluding SVGs by default in image validation by [@SanderMuller](https://github.com/SanderMuller) in https://github.com/laravel/framework/pull/54331 +* [12.x] Convert interfaces from docblock to method by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54348 +* [12.x] Validate paths for UTF-8 characters by [@Jubeki](https://github.com/Jubeki) in https://github.com/laravel/framework/pull/54370 +* [12.x] Fix aggregate alias when using expression by [@iamgergo](https://github.com/iamgergo) in https://github.com/laravel/framework/pull/54418 +* Added flash method to Session interface to fix IDE issues by [@eldair](https://github.com/eldair) in https://github.com/laravel/framework/pull/54421 +* Adding the withQueryString method to the paginator interface. by [@dvlpr91](https://github.com/dvlpr91) in https://github.com/laravel/framework/pull/54462 +* [12.x] feat: --memory=0 should mean skip memory exceeded verification (Breaking Change) by [@mathiasgrimm](https://github.com/mathiasgrimm) in https://github.com/laravel/framework/pull/54393 +* Auto-discover nested policies following conventional, parallel hierarchy by [@jasonmccreary](https://github.com/jasonmccreary) in https://github.com/laravel/framework/pull/54493 +* [12.x] Reintroduce PHPUnit 10.5 supports by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54490 +* [12.x] Allow limiting bcrypt hashing to 72 bytes to prevent insecure hashes. by [@waxim](https://github.com/waxim) in https://github.com/laravel/framework/pull/54509 +* [12.x] Fix accessing `Connection` property in `Grammar` classes by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/54487 +* [12.x] Configure connection on SQLite connector by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/54588 +* [12.x] Introduce Job@resolveQueuedJobClass() by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54613 +* [12.x] Bind abstract from concrete's return type by [@peterfox](https://github.com/peterfox) in https://github.com/laravel/framework/pull/54628 +* [12.x] Query builder PDO fetch modes by [@bert-w](https://github.com/bert-w) in https://github.com/laravel/framework/pull/54443 +* [12.x] Fix Illuminate components `composer.json` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54700 +* [12.x] Bump minimum `brick/math` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54694 +* [11.x] Fix parsing `PHP_CLI_SERVER_WORKERS` as `string` instead of `int` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54724 +* [11.x] Rename Redis parse connection for cluster test method to follow naming conventions by [@jackbayliss](https://github.com/jackbayliss) in https://github.com/laravel/framework/pull/54721 +* [11.x] Allow `readAt` method to use in database channel by [@utsavsomaiya](https://github.com/utsavsomaiya) in https://github.com/laravel/framework/pull/54729 +* [11.x] Fix: Custom Exceptions with Multiple Arguments does not properly rein… by [@pandiselvamm](https://github.com/pandiselvamm) in https://github.com/laravel/framework/pull/54705 +* [11.x] Update ConcurrencyTest exception reference to use namespace by [@jackbayliss](https://github.com/jackbayliss) in https://github.com/laravel/framework/pull/54732 +* [11.x] Deprecate `Factory::$modelNameResolver` by [@samlev](https://github.com/samlev) in https://github.com/laravel/framework/pull/54736 +* Update `config/app.php` to reflect laravel/laravel change for compatibility by [@askdkc](https://github.com/askdkc) in https://github.com/laravel/framework/pull/54752 +* [11x.] Improved typehints for `InteractsWithDatabase` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54748 +* [11.x] Improved typehints for `InteractsWithExceptionHandling` && `ExceptionHandlerFake` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54747 +* Add Env::extend to support custom adapters when loading environment variables by [@andrii-androshchuk](https://github.com/andrii-androshchuk) in https://github.com/laravel/framework/pull/54756 +* [12.x] Sync `filesystem.disk.local` configurations by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54764 From 65bdfa09777727cc05216885390d4aadf11de883 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 24 Feb 2025 07:29:35 -0600 Subject: [PATCH 099/455] fix bug in sqlite connector --- src/Illuminate/Database/Connectors/SQLiteConnector.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Connectors/SQLiteConnector.php b/src/Illuminate/Database/Connectors/SQLiteConnector.php index d68b42718044..2e2ed8758919 100755 --- a/src/Illuminate/Database/Connectors/SQLiteConnector.php +++ b/src/Illuminate/Database/Connectors/SQLiteConnector.php @@ -38,6 +38,8 @@ public function connect(array $config) */ protected function parseDatabasePath(string $path): string { + $database = $path; + // SQLite supports "in-memory" databases that only last as long as the owning // connection does. These are useful for tests or for short lifetime store // querying. In-memory databases shall be anonymous (:memory:) or named. @@ -54,7 +56,7 @@ protected function parseDatabasePath(string $path): string // as the developer probably wants to know if the database exists and this // SQLite driver will not throw any exception if it does not by default. if ($path === false) { - throw new SQLiteDatabaseDoesNotExistException($path); + throw new SQLiteDatabaseDoesNotExistException($database); } return $path; From d99e2385a6d4324782d52f4423891966425641be Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 24 Feb 2025 13:31:23 +0000 Subject: [PATCH 100/455] Update version to v12.0.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 31abef05a053..17ae78df14be 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.0.0'; + const VERSION = '12.0.1'; /** * The base path for the Laravel installation. From abf823f36b5cb31b910cbbb14225dccfeeb52263 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 24 Feb 2025 13:33:05 +0000 Subject: [PATCH 101/455] Update CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5491984024fd..ba1d08ead792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.0.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.0.1...12.x) + +## [v12.0.1](https://github.com/laravel/framework/compare/v12.0.0...v12.0.1) - 2025-02-24 ## [v12.0.0](https://github.com/laravel/framework/compare/v11.44.0..v12.0.0...v12.0.0) - 2025-02-24 From 3ea6180a99ed2d1a4c1e75cc46887682ef4e9359 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 25 Feb 2025 17:26:23 +0800 Subject: [PATCH 102/455] [12.x] Test Improvements (#54782) * [12.x] Test Improvements Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- composer.json | 2 +- tests/Integration/Cache/Psr6RedisTest.php | 4 ++-- tests/Integration/Cache/RedisStoreTest.php | 5 ++--- .../Console/CallbackSchedulingTest.php | 7 ------- .../Scheduling/ScheduleListCommandTest.php | 4 +--- .../Database/EloquentBelongsToManyTest.php | 7 ------- .../Database/EloquentMassPrunableTest.php | 16 ++-------------- tests/Integration/Events/ListenerTest.php | 2 -- .../Foundation/Console/OptimizeCommandTest.php | 1 + .../Providers/RouteServiceProviderHealthTest.php | 2 ++ .../Providers/RouteServiceProviderTest.php | 2 ++ tests/Integration/Migration/MigratorTest.php | 3 ++- .../Queue/DeleteModelWhenMissingTest.php | 4 ++-- tests/Integration/Queue/WorkCommandTest.php | 8 -------- .../Routing/ImplicitModelRouteBindingTest.php | 14 ++------------ tests/Integration/Routing/UrlSigningTest.php | 7 ------- tests/Testing/Console/RouteListCommandTest.php | 2 ++ 17 files changed, 21 insertions(+), 69 deletions(-) diff --git a/composer.json b/composer.json index 46b926adcf40..6ce6a3254312 100644 --- a/composer.json +++ b/composer.json @@ -111,7 +111,7 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^10.0", + "orchestra/testbench-core": "^10.0.0", "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", diff --git a/tests/Integration/Cache/Psr6RedisTest.php b/tests/Integration/Cache/Psr6RedisTest.php index 062d5ec4dbfb..9328077fe6e0 100644 --- a/tests/Integration/Cache/Psr6RedisTest.php +++ b/tests/Integration/Cache/Psr6RedisTest.php @@ -21,9 +21,9 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); - $this->tearDownRedis(); + + parent::tearDown(); } #[DataProvider('redisClientDataProvider')] diff --git a/tests/Integration/Cache/RedisStoreTest.php b/tests/Integration/Cache/RedisStoreTest.php index af731995b7de..491461950824 100644 --- a/tests/Integration/Cache/RedisStoreTest.php +++ b/tests/Integration/Cache/RedisStoreTest.php @@ -25,10 +25,9 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); - $this->tearDownRedis(); - m::close(); + + parent::tearDown(); } public function testCacheTtl(): void diff --git a/tests/Integration/Console/CallbackSchedulingTest.php b/tests/Integration/Console/CallbackSchedulingTest.php index 13349238ca70..7fef2668b29d 100644 --- a/tests/Integration/Console/CallbackSchedulingTest.php +++ b/tests/Integration/Console/CallbackSchedulingTest.php @@ -45,13 +45,6 @@ public function store($name = null) $container->instance(SchedulingMutex::class, new CacheSchedulingMutex($cache)); } - protected function tearDown(): void - { - Container::setInstance(null); - - parent::tearDown(); - } - public function testExecutionOrder() { $event = $this->app->make(Schedule::class) diff --git a/tests/Integration/Console/Scheduling/ScheduleListCommandTest.php b/tests/Integration/Console/Scheduling/ScheduleListCommandTest.php index 806b0a7e929e..b65ab28d218e 100644 --- a/tests/Integration/Console/Scheduling/ScheduleListCommandTest.php +++ b/tests/Integration/Console/Scheduling/ScheduleListCommandTest.php @@ -156,11 +156,9 @@ public function testClosureCommandsMayBeScheduled() protected function tearDown(): void { - parent::tearDown(); - putenv('SHELL_VERBOSITY'); - ScheduleListCommand::resolveTerminalWidthUsing(null); + parent::tearDown(); } } diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 8cb8acba0187..608e9ce1318c 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -15,13 +15,6 @@ class EloquentBelongsToManyTest extends DatabaseTestCase { - protected function tearDown(): void - { - parent::tearDown(); - - Carbon::setTestNow(null); - } - protected function afterRefreshingDatabase() { Schema::create('users', function (Blueprint $table) { diff --git a/tests/Integration/Database/EloquentMassPrunableTest.php b/tests/Integration/Database/EloquentMassPrunableTest.php index e3e1c0c36f34..62401e880db3 100644 --- a/tests/Integration/Database/EloquentMassPrunableTest.php +++ b/tests/Integration/Database/EloquentMassPrunableTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Integration\Database; -use Illuminate\Container\Container; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Eloquent\MassPrunable; use Illuminate\Database\Eloquent\Model; @@ -19,13 +18,11 @@ protected function setUp(): void { parent::setUp(); - Container::setInstance($container = new Container); - - $container->singleton(Dispatcher::class, function () { + $this->app->singleton(Dispatcher::class, function () { return m::mock(Dispatcher::class); }); - $container->alias(Dispatcher::class, 'events'); + $this->app->alias(Dispatcher::class, 'events'); } protected function afterRefreshingDatabase() @@ -93,15 +90,6 @@ public function testPrunesSoftDeletedRecords() $this->assertEquals(0, MassPrunableSoftDeleteTestModel::count()); $this->assertEquals(2000, MassPrunableSoftDeleteTestModel::withTrashed()->count()); } - - protected function tearDown(): void - { - parent::tearDown(); - - Container::setInstance(null); - - m::close(); - } } class MassPrunableTestModel extends Model diff --git a/tests/Integration/Events/ListenerTest.php b/tests/Integration/Events/ListenerTest.php index fbd34776406c..490117eef174 100644 --- a/tests/Integration/Events/ListenerTest.php +++ b/tests/Integration/Events/ListenerTest.php @@ -11,8 +11,6 @@ class ListenerTest extends TestCase { protected function tearDown(): void { - parent::tearDown(); - ListenerTestListener::$ran = false; ListenerTestListenerAfterCommit::$ran = false; diff --git a/tests/Integration/Foundation/Console/OptimizeCommandTest.php b/tests/Integration/Foundation/Console/OptimizeCommandTest.php index 2ea8d7a3f8bc..194670aaf4b5 100644 --- a/tests/Integration/Foundation/Console/OptimizeCommandTest.php +++ b/tests/Integration/Foundation/Console/OptimizeCommandTest.php @@ -14,6 +14,7 @@ class OptimizeCommandTest extends TestCase protected $files = [ 'bootstrap/cache/config.php', 'bootstrap/cache/events.php', + 'bootstrap/cache/routes-v7.php', ]; protected function getPackageProviders($app): array diff --git a/tests/Integration/Foundation/Support/Providers/RouteServiceProviderHealthTest.php b/tests/Integration/Foundation/Support/Providers/RouteServiceProviderHealthTest.php index 1a341eb33a10..6a331999d88f 100644 --- a/tests/Integration/Foundation/Support/Providers/RouteServiceProviderHealthTest.php +++ b/tests/Integration/Foundation/Support/Providers/RouteServiceProviderHealthTest.php @@ -4,8 +4,10 @@ use Illuminate\Foundation\Application; use Illuminate\Support\Str; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\TestCase; +#[WithConfig('filesystems.disks.local.serve', false)] class RouteServiceProviderHealthTest extends TestCase { /** diff --git a/tests/Integration/Foundation/Support/Providers/RouteServiceProviderTest.php b/tests/Integration/Foundation/Support/Providers/RouteServiceProviderTest.php index 20005e6270dc..fe106bb275df 100644 --- a/tests/Integration/Foundation/Support/Providers/RouteServiceProviderTest.php +++ b/tests/Integration/Foundation/Support/Providers/RouteServiceProviderTest.php @@ -8,8 +8,10 @@ use Illuminate\Foundation\Support\Providers\RouteServiceProvider; use Illuminate\Support\Facades\Route; use Illuminate\Testing\Assert; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\TestCase; +#[WithConfig('filesystems.disks.local.serve', false)] class RouteServiceProviderTest extends TestCase { /** diff --git a/tests/Integration/Migration/MigratorTest.php b/tests/Integration/Migration/MigratorTest.php index 0b32efc7aa0c..15f79993dfd6 100644 --- a/tests/Integration/Migration/MigratorTest.php +++ b/tests/Integration/Migration/MigratorTest.php @@ -32,8 +32,9 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); Migrator::withoutMigrations([]); + + parent::tearDown(); } public function testMigrate() diff --git a/tests/Integration/Queue/DeleteModelWhenMissingTest.php b/tests/Integration/Queue/DeleteModelWhenMissingTest.php index f05564db59b9..9c9f98a83f9c 100644 --- a/tests/Integration/Queue/DeleteModelWhenMissingTest.php +++ b/tests/Integration/Queue/DeleteModelWhenMissingTest.php @@ -38,9 +38,9 @@ protected function destroyDatabaseMigrations() #[\Override] protected function tearDown(): void { - parent::tearDown(); - DeleteMissingModelJob::$handled = false; + + parent::tearDown(); } public function test_deleteModelWhenMissing_and_display_name(): void diff --git a/tests/Integration/Queue/WorkCommandTest.php b/tests/Integration/Queue/WorkCommandTest.php index 6d3796e01491..f1eb6b83134a 100644 --- a/tests/Integration/Queue/WorkCommandTest.php +++ b/tests/Integration/Queue/WorkCommandTest.php @@ -7,7 +7,6 @@ use Illuminate\Database\UniqueConstraintViolationException; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Testing\DatabaseMigrations; -use Illuminate\Queue\Console\WorkCommand; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Exceptions; @@ -34,13 +33,6 @@ protected function setUp(): void $this->markTestSkippedWhenUsingSyncQueueDriver(); } - protected function tearDown(): void - { - WorkCommand::flushState(); - - parent::tearDown(); - } - public function testRunningOneJob() { Queue::push(new FirstJob); diff --git a/tests/Integration/Routing/ImplicitModelRouteBindingTest.php b/tests/Integration/Routing/ImplicitModelRouteBindingTest.php index d2cf32096222..96dcadcae555 100644 --- a/tests/Integration/Routing/ImplicitModelRouteBindingTest.php +++ b/tests/Integration/Routing/ImplicitModelRouteBindingTest.php @@ -9,9 +9,11 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Schema; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\Concerns\InteractsWithPublishedFiles; use Orchestra\Testbench\TestCase; +#[WithConfig('app.key', 'AckfSECXIvnK5r28GVIWUAxmbBSjTsmF')] class ImplicitModelRouteBindingTest extends TestCase { use InteractsWithPublishedFiles; @@ -20,18 +22,6 @@ class ImplicitModelRouteBindingTest extends TestCase 'routes/testbench.php', ]; - protected function tearDown(): void - { - $this->tearDownInteractsWithPublishedFiles(); - - parent::tearDown(); - } - - protected function defineEnvironment($app): void - { - $app['config']->set(['app.key' => 'AckfSECXIvnK5r28GVIWUAxmbBSjTsmF']); - } - protected function defineDatabaseMigrations(): void { Schema::create('users', function (Blueprint $table) { diff --git a/tests/Integration/Routing/UrlSigningTest.php b/tests/Integration/Routing/UrlSigningTest.php index f836066d26f9..66b30417673f 100644 --- a/tests/Integration/Routing/UrlSigningTest.php +++ b/tests/Integration/Routing/UrlSigningTest.php @@ -14,13 +14,6 @@ class UrlSigningTest extends TestCase { - protected function tearDown(): void - { - parent::tearDown(); - - Carbon::setTestNow(null); - } - protected function defineEnvironment($app): void { $app['config']->set(['app.key' => 'AckfSECXIvnK5r28GVIWUAxmbBSjTsmF']); diff --git a/tests/Testing/Console/RouteListCommandTest.php b/tests/Testing/Console/RouteListCommandTest.php index 61723bb9bce1..c6deeeb8df21 100644 --- a/tests/Testing/Console/RouteListCommandTest.php +++ b/tests/Testing/Console/RouteListCommandTest.php @@ -9,8 +9,10 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Facade; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\TestCase; +#[WithConfig('filesystems.disks.local.serve', false)] class RouteListCommandTest extends TestCase { use InteractsWithDeprecationHandling; From 6782c1b65e673c079679dda4c1b68e6322f86748 Mon Sep 17 00:00:00 2001 From: mohprilaksono <56257564+mohprilaksono@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:56:57 +0700 Subject: [PATCH 103/455] [12.x] Fix incorrect typehints in `BuildsWhereDateClauses` traits (#54784) * fix incorrect typehints * make sure tests are pass * . --- src/Illuminate/Database/Concerns/BuildsWhereDateClauses.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Concerns/BuildsWhereDateClauses.php b/src/Illuminate/Database/Concerns/BuildsWhereDateClauses.php index ea6048975525..06da84427365 100644 --- a/src/Illuminate/Database/Concerns/BuildsWhereDateClauses.php +++ b/src/Illuminate/Database/Concerns/BuildsWhereDateClauses.php @@ -99,6 +99,8 @@ public function orWhereNowOrFuture($columns) * Add an "where" clause to determine if a "date" column is in the past or future. * * @param array|string $columns + * @param string $operator + * @param string $boolean * @return $this */ protected function wherePastOrFuture($columns, $operator, $boolean) @@ -197,7 +199,6 @@ public function orWhereBeforeToday($columns) * Add an "or where date" clause to determine if a "date" column is today or before to the query. * * @param array|string $columns - * @param string $boolean * @return $this */ public function orWhereTodayOrBefore($columns) @@ -209,7 +210,6 @@ public function orWhereTodayOrBefore($columns) * Add an "or where date" clause to determine if a "date" column is after today. * * @param array|string $columns - * @param string $boolean * @return $this */ public function orWhereAfterToday($columns) @@ -221,7 +221,6 @@ public function orWhereAfterToday($columns) * Add an "or where date" clause to determine if a "date" column is today or after to the query. * * @param array|string $columns - * @param string $boolean * @return $this */ public function orWhereTodayOrAfter($columns) From 3a8a839b5e182679382c2c1df173ce49bd951e25 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 25 Feb 2025 17:38:31 +0330 Subject: [PATCH 104/455] [12.x] Improve queries readablility (#54791) * improve queries readability * fix tests --- src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php | 4 ++-- .../Database/Schema/Grammars/PostgresGrammar.php | 8 ++++---- .../Database/Schema/Grammars/SqlServerGrammar.php | 2 +- tests/Database/DatabaseMariaDbSchemaGrammarTest.php | 4 ++-- tests/Database/DatabaseMySqlSchemaGrammarTest.php | 4 ++-- tests/Database/DatabasePostgresSchemaGrammarTest.php | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 938a18856e32..38fd418141b2 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -653,7 +653,7 @@ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) */ public function compileDropAllTables($tables) { - return 'drop table '.implode(',', $this->wrapArray($tables)); + return 'drop table '.implode(', ', $this->wrapArray($tables)); } /** @@ -664,7 +664,7 @@ public function compileDropAllTables($tables) */ public function compileDropAllViews($views) { - return 'drop view '.implode(',', $this->wrapArray($views)); + return 'drop view '.implode(', ', $this->wrapArray($views)); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 21a5863f305e..2a49cd1d1c23 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -463,7 +463,7 @@ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) */ public function compileDropAllTables($tables) { - return 'drop table '.implode(',', $this->escapeNames($tables)).' cascade'; + return 'drop table '.implode(', ', $this->escapeNames($tables)).' cascade'; } /** @@ -474,7 +474,7 @@ public function compileDropAllTables($tables) */ public function compileDropAllViews($views) { - return 'drop view '.implode(',', $this->escapeNames($views)).' cascade'; + return 'drop view '.implode(', ', $this->escapeNames($views)).' cascade'; } /** @@ -485,7 +485,7 @@ public function compileDropAllViews($views) */ public function compileDropAllTypes($types) { - return 'drop type '.implode(',', $this->escapeNames($types)).' cascade'; + return 'drop type '.implode(', ', $this->escapeNames($types)).' cascade'; } /** @@ -496,7 +496,7 @@ public function compileDropAllTypes($types) */ public function compileDropAllDomains($domains) { - return 'drop domain '.implode(',', $this->escapeNames($domains)).' cascade'; + return 'drop domain '.implode(', ', $this->escapeNames($domains)).' cascade'; } /** diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index b387b3a4d42d..6aff6696d507 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -405,7 +405,7 @@ public function compileDropDefaultConstraint(Blueprint $blueprint, Fluent $comma { $columns = $command->name === 'change' ? "'".$command->column->name."'" - : "'".implode("','", $command->columns)."'"; + : "'".implode("', '", $command->columns)."'"; $table = $this->wrapTable($blueprint); $tableName = $this->quoteString($this->wrapTable($blueprint)); diff --git a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php index e30063710c9e..1152b2c1adcb 100755 --- a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php +++ b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php @@ -1471,14 +1471,14 @@ public function testDropAllTables() $connection = $this->getConnection(); $statement = $this->getGrammar($connection)->compileDropAllTables(['alpha', 'beta', 'gamma']); - $this->assertSame('drop table `alpha`,`beta`,`gamma`', $statement); + $this->assertSame('drop table `alpha`, `beta`, `gamma`', $statement); } public function testDropAllViews() { $statement = $this->getGrammar()->compileDropAllViews(['alpha', 'beta', 'gamma']); - $this->assertSame('drop view `alpha`,`beta`,`gamma`', $statement); + $this->assertSame('drop view `alpha`, `beta`, `gamma`', $statement); } public function testGrammarsAreMacroable() diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 64002304ba10..a00aff0472b9 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1480,14 +1480,14 @@ public function testDropAllTables() { $statement = $this->getGrammar()->compileDropAllTables(['alpha', 'beta', 'gamma']); - $this->assertSame('drop table `alpha`,`beta`,`gamma`', $statement); + $this->assertSame('drop table `alpha`, `beta`, `gamma`', $statement); } public function testDropAllViews() { $statement = $this->getGrammar()->compileDropAllViews(['alpha', 'beta', 'gamma']); - $this->assertSame('drop view `alpha`,`beta`,`gamma`', $statement); + $this->assertSame('drop view `alpha`, `beta`, `gamma`', $statement); } public function testGrammarsAreMacroable() diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 3b7b0cb4e9c7..36e26f9885b8 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -1093,21 +1093,21 @@ public function testDropAllTablesEscapesTableNames() { $statement = $this->getGrammar()->compileDropAllTables(['alpha', 'beta', 'gamma']); - $this->assertSame('drop table "alpha","beta","gamma" cascade', $statement); + $this->assertSame('drop table "alpha", "beta", "gamma" cascade', $statement); } public function testDropAllViewsEscapesTableNames() { $statement = $this->getGrammar()->compileDropAllViews(['alpha', 'beta', 'gamma']); - $this->assertSame('drop view "alpha","beta","gamma" cascade', $statement); + $this->assertSame('drop view "alpha", "beta", "gamma" cascade', $statement); } public function testDropAllTypesEscapesTableNames() { $statement = $this->getGrammar()->compileDropAllTypes(['alpha', 'beta', 'gamma']); - $this->assertSame('drop type "alpha","beta","gamma" cascade', $statement); + $this->assertSame('drop type "alpha", "beta", "gamma" cascade', $statement); } public function testCompileColumns() From 006a6276eb3cc879245c08ba2fab5a48100f8f22 Mon Sep 17 00:00:00 2001 From: Hammed Oyedele Date: Tue, 25 Feb 2025 21:07:40 +0100 Subject: [PATCH 105/455] [12.x] Enhance eventStream to Support Custom Events and Start Messages (#54776) * feat: enhance event stream response * feat: create EventStream.php * feat: update ResponseFactory.php * fix: update EventStream.php * fix: update EventStream.php * fix: update EventStream.php * fix: update ResponseFactory.php * formatting * Update ResponseFactory.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Http/StreamedEvent.php | 27 ++++++++++++++++++ src/Illuminate/Routing/ResponseFactory.php | 33 ++++++++++++++++------ 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/Illuminate/Http/StreamedEvent.php diff --git a/src/Illuminate/Http/StreamedEvent.php b/src/Illuminate/Http/StreamedEvent.php new file mode 100644 index 000000000000..e6defe52f8ee --- /dev/null +++ b/src/Illuminate/Http/StreamedEvent.php @@ -0,0 +1,27 @@ +event = $event; + $this->data = $data; + } +} diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index 200ed11a075c..7886a0a43243 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -7,6 +7,7 @@ use Illuminate\Contracts\View\Factory as ViewFactory; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; +use Illuminate\Http\StreamedEvent; use Illuminate\Routing\Exceptions\StreamedResponseException; use Illuminate\Support\Js; use Illuminate\Support\Str; @@ -124,10 +125,10 @@ public function jsonp($callback, $data = [], $status = 200, array $headers = [], * * @param \Closure $callback * @param array $headers - * @param string $endStreamWith + * @param \Illuminate\Http\StreamedEvent|string $endStreamWith * @return \Symfony\Component\HttpFoundation\StreamedResponse */ - public function eventStream(Closure $callback, array $headers = [], string $endStreamWith = '') + public function eventStream(Closure $callback, array $headers = [], StreamedEvent|string|null $endStreamWith = '') { return $this->stream(function () use ($callback, $endStreamWith) { foreach ($callback() as $message) { @@ -135,11 +136,18 @@ public function eventStream(Closure $callback, array $headers = [], string $endS break; } + $event = 'update'; + + if ($message instanceof StreamedEvent) { + $event = $message->event; + $message = $message->data; + } + if (! is_string($message) && ! is_numeric($message)) { $message = Js::encode($message); } - echo "event: update\n"; + echo "event: $event\n"; echo 'data: '.$message; echo "\n\n"; @@ -147,12 +155,21 @@ public function eventStream(Closure $callback, array $headers = [], string $endS flush(); } - echo "event: update\n"; - echo 'data: '.$endStreamWith; - echo "\n\n"; + if (filled($endStreamWith)) { + $endEvent = 'update'; + + if ($endStreamWith instanceof StreamedEvent) { + $endEvent = $endStreamWith->event; + $endStreamWith = $endStreamWith->data; + } + + echo "event: $endEvent\n"; + echo 'data: '.$endStreamWith; + echo "\n\n"; - ob_flush(); - flush(); + ob_flush(); + flush(); + } }, 200, array_merge($headers, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', From 50828e208a4698abc032154ff3534d4dc004e584 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:08:21 +0000 Subject: [PATCH 106/455] Update facade docblocks --- src/Illuminate/Support/Facades/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Response.php b/src/Illuminate/Support/Facades/Response.php index 1c5bfac0d137..cf7563ee635c 100755 --- a/src/Illuminate/Support/Facades/Response.php +++ b/src/Illuminate/Support/Facades/Response.php @@ -10,7 +10,7 @@ * @method static \Illuminate\Http\Response view(string|array $view, array $data = [], int $status = 200, array $headers = []) * @method static \Illuminate\Http\JsonResponse json(mixed $data = [], int $status = 200, array $headers = [], int $options = 0) * @method static \Illuminate\Http\JsonResponse jsonp(string $callback, mixed $data = [], int $status = 200, array $headers = [], int $options = 0) - * @method static \Symfony\Component\HttpFoundation\StreamedResponse eventStream(\Closure $callback, array $headers = [], string $endStreamWith = '') + * @method static \Symfony\Component\HttpFoundation\StreamedResponse eventStream(\Closure $callback, array $headers = [], \Illuminate\Http\StreamedEvent|string $endStreamWith = '') * @method static \Symfony\Component\HttpFoundation\StreamedResponse stream(callable $callback, int $status = 200, array $headers = []) * @method static \Symfony\Component\HttpFoundation\StreamedJsonResponse streamJson(array $data, int $status = 200, array $headers = [], int $encodingOptions = 15) * @method static \Symfony\Component\HttpFoundation\StreamedResponse streamDownload(callable $callback, string|null $name = null, array $headers = [], string|null $disposition = 'attachment') From 2fbac93fa1f420a5d504a5b49c9e633066d5907b Mon Sep 17 00:00:00 2001 From: Kevin Bui Date: Thu, 27 Feb 2025 00:23:07 +1100 Subject: [PATCH 107/455] Make the PendingCommand class tappable. (#54801) --- src/Illuminate/Testing/PendingCommand.php | 4 +-- .../Testing/ArtisanCommandTest.php | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index 0946161d4caf..e6d9b4be17e5 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -10,6 +10,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Traits\Conditionable; use Illuminate\Support\Traits\Macroable; +use Illuminate\Support\Traits\Tappable; use Mockery; use Mockery\Exception\NoMatchingExpectationException; use PHPUnit\Framework\TestCase as PHPUnitTestCase; @@ -21,8 +22,7 @@ class PendingCommand { - use Conditionable; - use Macroable; + use Conditionable, Macroable, Tappable; /** * The test being run. diff --git a/tests/Integration/Testing/ArtisanCommandTest.php b/tests/Integration/Testing/ArtisanCommandTest.php index fc26269e227f..d86467c396ce 100644 --- a/tests/Integration/Testing/ArtisanCommandTest.php +++ b/tests/Integration/Testing/ArtisanCommandTest.php @@ -55,6 +55,16 @@ protected function setUp(): void Artisan::command('contains', function () { $this->line('My name is Taylor Otwell'); }); + + Artisan::command('new-england', function () { + $this->line('The region of New England consists of the following states:'); + $this->info('Connecticut'); + $this->info('Maine'); + $this->info('Massachusetts'); + $this->info('New Hampshire'); + $this->info('Rhode Island'); + $this->info('Vermont'); + }); } public function test_console_command_that_passes() @@ -275,6 +285,27 @@ public function test_console_command_that_fails_if_the_output_does_not_contain() }); } + public function test_pending_command_can_be_tapped() + { + $newEngland = [ + 'Connecticut', + 'Maine', + 'Massachusetts', + 'New Hampshire', + 'Rhode Island', + 'Vermont', + ]; + + $this->artisan('new-england') + ->expectsOutput('The region of New England consists of the following states:') + ->tap(function ($command) use ($newEngland) { + foreach ($newEngland as $state) { + $command->expectsOutput($state); + } + }) + ->assertExitCode(0); + } + /** * Don't allow Mockery's InvalidCountException to be reported. Mocks setup * in PendingCommand cause PHPUnit tearDown() to later throw the exception. From ec46a0f64eab5052258bb461339403f2efa5eb0f Mon Sep 17 00:00:00 2001 From: Hammed Oyedele Date: Wed, 26 Feb 2025 14:24:43 +0100 Subject: [PATCH 108/455] fix: add missing union type in event stream docblock (#54800) --- src/Illuminate/Routing/ResponseFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index 7886a0a43243..2a71ad57c9a3 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -125,7 +125,7 @@ public function jsonp($callback, $data = [], $status = 200, array $headers = [], * * @param \Closure $callback * @param array $headers - * @param \Illuminate\Http\StreamedEvent|string $endStreamWith + * @param \Illuminate\Http\StreamedEvent|string|null $endStreamWith * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function eventStream(Closure $callback, array $headers = [], StreamedEvent|string|null $endStreamWith = '') From 45f0347e4baaab341fbab27031026b60ff3e9ffb Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 26 Feb 2025 13:25:17 +0000 Subject: [PATCH 109/455] Update facade docblocks --- src/Illuminate/Support/Facades/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Response.php b/src/Illuminate/Support/Facades/Response.php index cf7563ee635c..f2dc641b77c5 100755 --- a/src/Illuminate/Support/Facades/Response.php +++ b/src/Illuminate/Support/Facades/Response.php @@ -10,7 +10,7 @@ * @method static \Illuminate\Http\Response view(string|array $view, array $data = [], int $status = 200, array $headers = []) * @method static \Illuminate\Http\JsonResponse json(mixed $data = [], int $status = 200, array $headers = [], int $options = 0) * @method static \Illuminate\Http\JsonResponse jsonp(string $callback, mixed $data = [], int $status = 200, array $headers = [], int $options = 0) - * @method static \Symfony\Component\HttpFoundation\StreamedResponse eventStream(\Closure $callback, array $headers = [], \Illuminate\Http\StreamedEvent|string $endStreamWith = '') + * @method static \Symfony\Component\HttpFoundation\StreamedResponse eventStream(\Closure $callback, array $headers = [], \Illuminate\Http\StreamedEvent|string|null $endStreamWith = '') * @method static \Symfony\Component\HttpFoundation\StreamedResponse stream(callable $callback, int $status = 200, array $headers = []) * @method static \Symfony\Component\HttpFoundation\StreamedJsonResponse streamJson(array $data, int $status = 200, array $headers = [], int $encodingOptions = 15) * @method static \Symfony\Component\HttpFoundation\StreamedResponse streamDownload(callable $callback, string|null $name = null, array $headers = [], string|null $disposition = 'attachment') From f5e57f042c81ed37b2611ad0af0f7a88023a63d2 Mon Sep 17 00:00:00 2001 From: Alexander Karlstad Date: Thu, 27 Feb 2025 16:03:28 +0100 Subject: [PATCH 110/455] Change `paginage()` method return types to `\Illuminate\Pagination\LengthAwarePaginator` (#54826) Return types of all the subsequent calls are returning this, which in turn implements `\Illuminate\Contracts\Pagination\LengthAwarePaginator` Related to https://github.com/bmewburn/vscode-intelephense/issues/2912. Which I in turn had issues with locally where calling methods to the returned data from `->paginage()` did not auto complete. Hope this is possible to backport to 11.x too if this is a change that is okay. --- src/Illuminate/Database/Eloquent/Builder.php | 2 +- src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php | 2 +- .../Database/Eloquent/Relations/HasOneOrManyThrough.php | 2 +- src/Illuminate/Database/Query/Builder.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 9cb9c2e22b91..a2f4554c61cc 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1018,7 +1018,7 @@ public function pluck($column, $key = null) * @param string $pageName * @param int|null $page * @param \Closure|int|null $total - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 7019cf49c069..5618f0190f51 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -938,7 +938,7 @@ protected function aliasedPivotColumns() * @param array $columns * @param string $pageName * @param int|null $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index 6e74acf74651..72a65b0c1f5b 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -468,7 +468,7 @@ public function get($columns = ['*']) * @param array $columns * @param string $pageName * @param int $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index c5db6b31060e..1bb26adf622e 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3142,7 +3142,7 @@ protected function withoutGroupLimitKeys($items) * @param string $pageName * @param int|null $page * @param \Closure|int|null $total - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null, $total = null) { From 84565cc3bc6aed8676817a7f996f451b123d5709 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Thu, 27 Feb 2025 15:25:59 -0300 Subject: [PATCH 111/455] check if method exists before forwarding call (#54833) --- src/Illuminate/Hashing/HashManager.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Hashing/HashManager.php b/src/Illuminate/Hashing/HashManager.php index f4c5b9f38e40..f1d46998a1ac 100644 --- a/src/Illuminate/Hashing/HashManager.php +++ b/src/Illuminate/Hashing/HashManager.php @@ -119,6 +119,10 @@ public function getDefaultDriver() */ public function verifyConfiguration($value) { - return $this->driver()->verifyConfiguration($value); + if (method_exists($driver = $this->driver(), 'verifyConfiguration')) { + return $driver->verifyConfiguration($value); + } + + return true; } } From 6051f411a3f9193b43a76a6a3abdcca322780c78 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 28 Feb 2025 02:28:12 +0800 Subject: [PATCH 112/455] [11.x] Fix using `AsStringable` cast on Notifiable's key (#54818) * [11.x] Fix using `AsStringable` cast on Notifiable's key fixes #54785 Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- .../Testing/Fakes/NotificationFake.php | 4 +- .../DatabaseNotificationTest.php | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/Integration/Notifications/DatabaseNotificationTest.php diff --git a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php index bc3f16ce59e0..ecc4d63b1090 100644 --- a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php +++ b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php @@ -279,7 +279,7 @@ public function hasSent($notifiable, $notification) */ protected function notificationsFor($notifiable, $notification) { - return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification] ?? []; + return $this->notifications[get_class($notifiable)][(string) $notifiable->getKey()][$notification] ?? []; } /** @@ -326,7 +326,7 @@ public function sendNow($notifiables, $notification, ?array $channels = null) continue; } - $this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [ + $this->notifications[get_class($notifiable)][(string) $notifiable->getKey()][get_class($notification)][] = [ 'notification' => $this->serializeAndRestore && $notification instanceof ShouldQueue ? $this->serializeAndRestoreNotification($notification) : $notification, diff --git a/tests/Integration/Notifications/DatabaseNotificationTest.php b/tests/Integration/Notifications/DatabaseNotificationTest.php new file mode 100644 index 000000000000..e26908d4ed44 --- /dev/null +++ b/tests/Integration/Notifications/DatabaseNotificationTest.php @@ -0,0 +1,73 @@ +create(); + + $user->notify(new NotificationStub); + + Notification::assertSentTo($user, NotificationStub::class, function ($notification, $channels, $notifiable) use ($user) { + return $notifiable === $user; + }); + } + + /** + * Define database and convert User's ID to UUID. + * + * @param \Illuminate\Foundation\Application $app + * @return void + */ + protected function defineDatabaseAndConvertUserIdToUuid($app): void + { + Schema::table('users', function (Blueprint $table) { + $table->uuid('id')->change(); + }); + } +} + +class UuidUserFactoryStub extends \Orchestra\Testbench\Factories\UserFactory +{ + protected $model = UuidUserStub::class; +} + +class UuidUserStub extends \Illuminate\Foundation\Auth\User +{ + use HasUuids, Notifiable; + + protected $table = 'users'; + + #[\Override] + public function casts() + { + return array_merge(parent::casts(), ['id' => AsStringable::class]); + } +} + +class NotificationStub extends \Illuminate\Notifications\Notification +{ + public function via($notifiable) + { + return ['mail']; + } +} From a71794b46f52e37bae3b5b5c1207acdaa6bcbab4 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Thu, 27 Feb 2025 21:58:27 +0330 Subject: [PATCH 113/455] Add Tests for Handling Null Primary Keys and Special Values in Unique Validation Rule (#54823) * Add test for handling ignoreModel with NULL primary key values * Add test case for handling special values in 'where' conditions (NULL, 0, etc.) --- tests/Validation/ValidationUniqueRuleTest.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/Validation/ValidationUniqueRuleTest.php b/tests/Validation/ValidationUniqueRuleTest.php index 8b4c85054ca5..8e7ae62c5582 100644 --- a/tests/Validation/ValidationUniqueRuleTest.php +++ b/tests/Validation/ValidationUniqueRuleTest.php @@ -103,6 +103,40 @@ public function testItOnlyTrashedSoftDeletes() $rule->onlyTrashed('softdeleted_at'); $this->assertSame('unique:table,NULL,NULL,id,softdeleted_at,"NOT_NULL"', (string) $rule); } + + public function testItHandlesNullPrimaryKeyInIgnoreModel() + { + $model = new EloquentModelStub(['id_column' => null]); + + $rule = new Unique('table', 'column'); + $rule->ignore($model); + $rule->where('foo', 'bar'); + $this->assertSame('unique:table,column,NULL,id_column,foo,"bar"', (string) $rule); + + $rule = new Unique('table', 'column'); + $rule->ignore($model, 'id_column'); + $rule->where('foo', 'bar'); + $this->assertSame('unique:table,column,NULL,id_column,foo,"bar"', (string) $rule); + } + + public function testItHandlesWhereWithSpecialValues() + { + $rule = new Unique('table', 'column'); + $rule->where('foo', null); + $this->assertSame('unique:table,column,NULL,id,foo,"NULL"', (string) $rule); + + $rule = new Unique('table', 'column'); + $rule->whereNull('foo'); + $this->assertSame('unique:table,column,NULL,id,foo,"NULL"', (string) $rule); + + $rule = new Unique('table', 'column'); + $rule->whereNotNull('foo'); + $this->assertSame('unique:table,column,NULL,id,foo,"NOT_NULL"', (string) $rule); + + $rule = new Unique('table', 'column'); + $rule->where('foo', 0); + $this->assertSame('unique:table,column,NULL,id,foo,"0"', (string) $rule); + } } class EloquentModelStub extends Model From b7254f9366386f942e33ec42aa7be1c5e0f58b4e Mon Sep 17 00:00:00 2001 From: igorlealantunes Date: Thu, 27 Feb 2025 19:19:17 -0300 Subject: [PATCH 114/455] =?UTF-8?q?Improve=20docblock=20for=20with()=20met?= =?UTF-8?q?hod=20to=20clarify=20it=20adds=20to=20existing=20eag=E2=80=A6?= =?UTF-8?q?=20(#54838)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve docblock for with() method to clarify it adds to existing eager loads The previous docblock for the with() method wasn't entirely clear on whether it set and replaced the existing eager loading list or appended to it. I had to read the source code instead of just the docblock. This update clarifies that calling with() adds to the existing list rather than overwriting it. * Update Builder.php * Update Builder.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Eloquent/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index a2f4554c61cc..34c31d8e73a1 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1595,7 +1595,7 @@ protected function createNestedWhere($whereSlice, $boolean = 'and') } /** - * Set the relationships that should be eager loaded. + * Specify relationships that should be eager loaded. * * @param array): mixed)|string>|string $relations * @param (\Closure(\Illuminate\Database\Eloquent\Relations\Relation<*,*,*>): mixed)|string|null $callback From 260855c6a92b65523aa0ca8df9629cb4895b53d5 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 28 Feb 2025 01:50:28 +0330 Subject: [PATCH 115/455] [12.x] Fix dropping schema-qualified prefixed tables (#54834) * fix dropping prefixed tables * add tests * fix tests --- .../Database/Schema/Grammars/MySqlGrammar.php | 18 ++++++++- .../Schema/Grammars/PostgresGrammar.php | 9 ++--- .../DatabaseMySqlSchemaGrammarTest.php | 16 ++++++++ .../DatabasePostgresSchemaGrammarTest.php | 37 ++++++++++++++++++- 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 38fd418141b2..693fc78a3659 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -653,7 +653,7 @@ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) */ public function compileDropAllTables($tables) { - return 'drop table '.implode(', ', $this->wrapArray($tables)); + return 'drop table '.implode(', ', $this->escapeNames($tables)); } /** @@ -664,7 +664,7 @@ public function compileDropAllTables($tables) */ public function compileDropAllViews($views) { - return 'drop view '.implode(', ', $this->wrapArray($views)); + return 'drop view '.implode(', ', $this->escapeNames($views)); } /** @@ -702,6 +702,20 @@ public function compileTableComment(Blueprint $blueprint, Fluent $command) ); } + /** + * Quote-escape the given tables, views, or types. + * + * @param array $names + * @return array + */ + public function escapeNames($names) + { + return array_map( + fn ($name) => (new Collection(explode('.', $name)))->map($this->wrapValue(...))->implode('.'), + $names + ); + } + /** * Create the column definition for a char type. * diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 2a49cd1d1c23..1eae481a8df9 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -682,11 +682,10 @@ public function compileTableComment(Blueprint $blueprint, Fluent $command) */ public function escapeNames($names) { - return array_map(static function ($name) { - return '"'.(new Collection(explode('.', $name))) - ->map(fn ($segment) => trim($segment, '\'"')) - ->implode('"."').'"'; - }, $names); + return array_map( + fn ($name) => (new Collection(explode('.', $name)))->map($this->wrapValue(...))->implode('.'), + $names + ); } /** diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index a00aff0472b9..09082dab62df 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1490,6 +1490,22 @@ public function testDropAllViews() $this->assertSame('drop view `alpha`, `beta`, `gamma`', $statement); } + public function testDropAllTablesWithPrefixAndSchema() + { + $connection = $this->getConnection(prefix: 'prefix_'); + $statement = $this->getGrammar($connection)->compileDropAllTables(['schema.alpha', 'schema.beta', 'schema.gamma']); + + $this->assertSame('drop table `schema`.`alpha`, `schema`.`beta`, `schema`.`gamma`', $statement); + } + + public function testDropAllViewsWithPrefixAndSchema() + { + $connection = $this->getConnection(prefix: 'prefix_'); + $statement = $this->getGrammar($connection)->compileDropAllViews(['schema.alpha', 'schema.beta', 'schema.gamma']); + + $this->assertSame('drop view `schema`.`alpha`, `schema`.`beta`, `schema`.`gamma`', $statement); + } + public function testGrammarsAreMacroable() { // compileReplace macro. diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 36e26f9885b8..220cdf9c5fc9 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -1110,6 +1110,38 @@ public function testDropAllTypesEscapesTableNames() $this->assertSame('drop type "alpha", "beta", "gamma" cascade', $statement); } + public function testDropAllTablesWithPrefixAndSchema() + { + $connection = $this->getConnection(prefix: 'prefix_'); + $statement = $this->getGrammar($connection)->compileDropAllTables(['schema.alpha', 'schema.beta', 'schema.gamma']); + + $this->assertSame('drop table "schema"."alpha", "schema"."beta", "schema"."gamma" cascade', $statement); + } + + public function testDropAllViewsWithPrefixAndSchema() + { + $connection = $this->getConnection(prefix: 'prefix_'); + $statement = $this->getGrammar($connection)->compileDropAllViews(['schema.alpha', 'schema.beta', 'schema.gamma']); + + $this->assertSame('drop view "schema"."alpha", "schema"."beta", "schema"."gamma" cascade', $statement); + } + + public function testDropAllTypesWithPrefixAndSchema() + { + $connection = $this->getConnection(prefix: 'prefix_'); + $statement = $this->getGrammar($connection)->compileDropAllTypes(['schema.alpha', 'schema.beta', 'schema.gamma']); + + $this->assertSame('drop type "schema"."alpha", "schema"."beta", "schema"."gamma" cascade', $statement); + } + + public function testDropAllDomainsWithPrefixAndSchema() + { + $connection = $this->getConnection(prefix: 'prefix_'); + $statement = $this->getGrammar($connection)->compileDropAllDomains(['schema.alpha', 'schema.beta', 'schema.gamma']); + + $this->assertSame('drop domain "schema"."alpha", "schema"."beta", "schema"."gamma" cascade', $statement); + } + public function testCompileColumns() { $connection = $this->getConnection(); @@ -1122,10 +1154,11 @@ public function testCompileColumns() protected function getConnection( ?PostgresGrammar $grammar = null, - ?PostgresBuilder $builder = null + ?PostgresBuilder $builder = null, + string $prefix = '' ) { $connection = m::mock(Connection::class) - ->shouldReceive('getTablePrefix')->andReturn('') + ->shouldReceive('getTablePrefix')->andReturn($prefix) ->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(null) ->getMock(); From fad4e71d79c9de28f6b557b01076c330b5125b30 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Thu, 27 Feb 2025 17:28:41 -0500 Subject: [PATCH 116/455] [12.x] Add `Context::scope()` (#54799) * add Context::with() * style * fix comment * remove return type * swap param order * change name to scope * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Log/Context/Repository.php | 29 +++++++++++++ tests/Log/ContextTest.php | 50 +++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/Illuminate/Log/Context/Repository.php b/src/Illuminate/Log/Context/Repository.php index c46224d14594..1582d375e681 100644 --- a/src/Illuminate/Log/Context/Repository.php +++ b/src/Illuminate/Log/Context/Repository.php @@ -447,6 +447,35 @@ protected function isHiddenStackable($key) (is_array($this->hidden[$key]) && array_is_list($this->hidden[$key])); } + /** + * Run the callback function with the given context values and restore the original context state when complete. + * + * @param callable $callback + * @param array $data + * @param array $hidden + * @return mixed + */ + public function scope(callable $callback, array $data = [], array $hidden = []) + { + $dataBefore = $this->data; + $hiddenBefore = $this->hidden; + + if ($data !== []) { + $this->add($data); + } + + if ($hidden !== []) { + $this->addHidden($hidden); + } + + try { + return $callback(); + } finally { + $this->data = $dataBefore; + $this->hidden = $hiddenBefore; + } + } + /** * Determine if the repository is empty. * diff --git a/tests/Log/ContextTest.php b/tests/Log/ContextTest.php index ba2594342d3c..98917b440c1e 100644 --- a/tests/Log/ContextTest.php +++ b/tests/Log/ContextTest.php @@ -494,6 +494,56 @@ public function test_it_adds_context_to_logged_exceptions() file_put_contents($path, ''); Str::createUuidsNormally(); } + + public function test_scope_sets_keys_and_restores() + { + $contextInClosure = []; + $callback = function () use (&$contextInClosure) { + $contextInClosure = ['data' => Context::all(), 'hidden' => Context::allHidden()]; + + throw new Exception('test_with_sets_keys_and_restores'); + }; + + Context::add('key1', 'value1'); + Context::add('key2', 123); + Context::addHidden([ + 'hiddenKey1' => 'hello', + 'hiddenKey2' => 'world', + ]); + + try { + Context::scope( + $callback, + ['key1' => 'with', 'key3' => 'also-with'], + ['hiddenKey3' => 'foobar'], + ); + + $this->fail('No exception was thrown.'); + } catch (Exception) { + } + + $this->assertEqualsCanonicalizing([ + 'data' => [ + 'key1' => 'with', + 'key2' => 123, + 'key3' => 'also-with', + ], + 'hidden' => [ + 'hiddenKey1' => 'hello', + 'hiddenKey2' => 'world', + 'hiddenKey3' => 'foobar', + ], + ], $contextInClosure); + + $this->assertEqualsCanonicalizing([ + 'key1' => 'value1', + 'key2' => 123, + ], Context::all()); + $this->assertEqualsCanonicalizing([ + 'hiddenKey1' => 'hello', + 'hiddenKey2' => 'world', + ], Context::allHidden()); + } } enum Suit From 5d477f9a4080c1cdd43edd05ec4df61c738e0f8d Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 27 Feb 2025 22:29:20 +0000 Subject: [PATCH 117/455] Update facade docblocks --- src/Illuminate/Support/Facades/Context.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Context.php b/src/Illuminate/Support/Facades/Context.php index a08bf9b4a834..e1bc10a1bb2e 100644 --- a/src/Illuminate/Support/Facades/Context.php +++ b/src/Illuminate/Support/Facades/Context.php @@ -27,6 +27,7 @@ * @method static mixed popHidden(string $key) * @method static bool stackContains(string $key, mixed $value, bool $strict = false) * @method static bool hiddenStackContains(string $key, mixed $value, bool $strict = false) + * @method static mixed scope(callable $callback, array $data = [], array $hidden = []) * @method static bool isEmpty() * @method static \Illuminate\Log\Context\Repository dehydrating(callable $callback) * @method static \Illuminate\Log\Context\Repository hydrated(callable $callback) From 908e33c70270d752ccf30ef197a30820c9093947 Mon Sep 17 00:00:00 2001 From: Steven Kemp Date: Fri, 28 Feb 2025 11:47:19 -0500 Subject: [PATCH 118/455] Allow Http requests to be recorded without requests being faked (#54850) * Allow Http requests to be recorded without requests being faked * Add `record` to docblock --- src/Illuminate/Http/Client/Factory.php | 2 +- src/Illuminate/Support/Facades/Http.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 84b8fc61a15d..61376e556904 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -322,7 +322,7 @@ public function allowStrayRequests() * * @return $this */ - protected function record() + public function record() { $this->recording = true; diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index 60489694d3c6..3ba95e38f9f1 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -14,6 +14,7 @@ * @method static \Illuminate\Http\Client\ResponseSequence sequence(array $responses = []) * @method static bool preventingStrayRequests() * @method static \Illuminate\Http\Client\Factory allowStrayRequests() + * @method static \Illuminate\Http\Client\Factory record() * @method static void recordRequestResponsePair(\Illuminate\Http\Client\Request $request, \Illuminate\Http\Client\Response|null $response) * @method static void assertSent(callable $callback) * @method static void assertSentInOrder(array $callbacks) From d1b79d7c8c3a571b384b3b47c26b6aaaf7366dd6 Mon Sep 17 00:00:00 2001 From: Erick de Azevedo Lima <12174550+erickcomp@users.noreply.github.com> Date: Fri, 28 Feb 2025 13:48:36 -0300 Subject: [PATCH 119/455] [12.x] Adds a new method "getRawSql" (with embedded bindings) to the QueryException class (#54849) * [12.x] Get Raw SQL (with embedded bindings) from QueryException (new method) * Reordering the imports * Reverting string concatenation format on untouched method * Reverting string concatenation format on untouched method * Resolving StyleCI complaint about extra line between namespace declaration and imports * Update QueryException.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/QueryException.php | 11 ++++ tests/Database/DatabaseQueryExceptionTest.php | 64 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100755 tests/Database/DatabaseQueryExceptionTest.php diff --git a/src/Illuminate/Database/QueryException.php b/src/Illuminate/Database/QueryException.php index 84aebb1a670b..143910029956 100644 --- a/src/Illuminate/Database/QueryException.php +++ b/src/Illuminate/Database/QueryException.php @@ -2,6 +2,7 @@ namespace Illuminate\Database; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; use PDOException; use Throwable; @@ -87,6 +88,16 @@ public function getSql() return $this->sql; } + /** + * Get the raw SQL representation of the query with embedded bindings. + */ + public function getRawSql(): string + { + return DB::connection($this->getConnectionName()) + ->getQueryGrammar() + ->substituteBindingsIntoRawSql($this->getSql(), $this->getBindings()); + } + /** * Get the bindings for the query. * diff --git a/tests/Database/DatabaseQueryExceptionTest.php b/tests/Database/DatabaseQueryExceptionTest.php new file mode 100755 index 000000000000..0a0c719718cc --- /dev/null +++ b/tests/Database/DatabaseQueryExceptionTest.php @@ -0,0 +1,64 @@ +getConnection(); + + $sql = 'SELECT * FROM huehue WHERE a = ? and hue = ?'; + $bindings = [1, 'br']; + + $expectedSql = "SELECT * FROM huehue WHERE a = 1 and hue = 'br'"; + + $pdoException = new PDOException('Mock SQL error'); + $exception = new QueryException($connection->getName(), $sql, $bindings, $pdoException); + + DB::shouldReceive('connection')->andReturn($connection); + $result = $exception->getRawSql(); + + $this->assertSame($expectedSql, $result); + } + + public function testIfItReturnsSameSqlWhenThereAreNoBindings() + { + $connection = $this->getConnection(); + + $sql = "SELECT * FROM huehue WHERE a = 1 and hue = 'br'"; + $bindings = []; + + $expectedSql = $sql; + + $pdoException = new PDOException('Mock SQL error'); + $exception = new QueryException($connection->getName(), $sql, $bindings, $pdoException); + + DB::shouldReceive('connection')->andReturn($connection); + $result = $exception->getRawSql(); + + $this->assertSame($expectedSql, $result); + } + + protected function getConnection() + { + $connection = m::mock(Connection::class); + + $grammar = new Grammar($connection); + + $connection->shouldReceive('getName')->andReturn('default'); + $connection->shouldReceive('getQueryGrammar')->andReturn($grammar); + $connection->shouldReceive('escape')->with(1, false)->andReturn(1); + $connection->shouldReceive('escape')->with('br', false)->andReturn("'br'"); + + return $connection; + } +} From 68e695b613e7c6356732c2cf3b07fa8edf3e981c Mon Sep 17 00:00:00 2001 From: Ju-gow Date: Fri, 28 Feb 2025 17:49:31 +0100 Subject: [PATCH 120/455] Update Inspiring.php (#54846) * Update Inspiring.php Only the selected quotes needs to be formatted, not all. * Update Inspiring.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Foundation/Inspiring.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Inspiring.php b/src/Illuminate/Foundation/Inspiring.php index 6b44751e74f3..59891493d9b5 100644 --- a/src/Illuminate/Foundation/Inspiring.php +++ b/src/Illuminate/Foundation/Inspiring.php @@ -56,9 +56,7 @@ class Inspiring */ public static function quote() { - return static::quotes() - ->map(fn ($quote) => static::formatForConsole($quote)) - ->random(); + return static::formatForConsole(static::quotes()->random()); } /** From 66d56c33b1a892179b95bf4d3ebbee58ee106d78 Mon Sep 17 00:00:00 2001 From: "Md. Mottasin Lemon" <68915904+lmottasin@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:50:08 +0600 Subject: [PATCH 121/455] Update docblock: Change 'tz' argument to 'timezone' and update 'TranslatorInterface' to 'Symfony\Contracts\Translation\TranslatorInterface' (#54847) --- src/Illuminate/Support/DateFactory.php | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Support/DateFactory.php b/src/Illuminate/Support/DateFactory.php index 3d0cd04dfc5b..fbf918396d05 100644 --- a/src/Illuminate/Support/DateFactory.php +++ b/src/Illuminate/Support/DateFactory.php @@ -9,16 +9,16 @@ * @see https://carbon.nesbot.com/docs/ * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php * - * @method \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) - * @method \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $tz = null) - * @method \Illuminate\Support\Carbon|false createFromFormat($format, $time, $tz = null) - * @method \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) - * @method \Illuminate\Support\Carbon createFromTimeString($time, $tz = null) - * @method \Illuminate\Support\Carbon createFromTimestamp($timestamp, $tz = null) - * @method \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $tz = null) + * @method \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) + * @method \Illuminate\Support\Carbon|false createFromFormat($format, $time, $timezone = null) + * @method \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimeString($time, $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestamp($timestamp, $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $timezone = null) * @method \Illuminate\Support\Carbon createFromTimestampUTC($timestamp) - * @method \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null) - * @method \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) + * @method \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) + * @method \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) * @method void disableHumanDiffOption($humanDiffOption) * @method void enableHumanDiffOption($humanDiffOption) * @method mixed executeWithLocale($locale, $func) @@ -31,7 +31,7 @@ * @method string getLocale() * @method int getMidDayAt() * @method \Illuminate\Support\Carbon|null getTestNow() - * @method \Symfony\Component\Translation\TranslatorInterface getTranslator() + * @method \Symfony\Contracts\Translation\TranslatorInterface getTranslator() * @method int getWeekEndsAt() * @method int getWeekStartsAt() * @method array getWeekendDays() @@ -54,8 +54,8 @@ * @method \Illuminate\Support\Carbon maxValue() * @method \Illuminate\Support\Carbon minValue() * @method void mixin($mixin) - * @method \Illuminate\Support\Carbon now($tz = null) - * @method \Illuminate\Support\Carbon parse($time = null, $tz = null) + * @method \Illuminate\Support\Carbon now($timezone = null) + * @method \Illuminate\Support\Carbon parse($time = null, $timezone = null) * @method string pluralUnit(string $unit) * @method void resetMonthsOverflow() * @method void resetToStringFormat() @@ -66,7 +66,7 @@ * @method void setMidDayAt($hour) * @method void setTestNow($testNow = null) * @method void setToStringFormat($format) - * @method void setTranslator(\Symfony\Component\Translation\TranslatorInterface $translator) + * @method void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) * @method void setUtf8($utf8) * @method void setWeekEndsAt($day) * @method void setWeekStartsAt($day) @@ -74,12 +74,12 @@ * @method bool shouldOverflowMonths() * @method bool shouldOverflowYears() * @method string singularUnit(string $unit) - * @method \Illuminate\Support\Carbon today($tz = null) - * @method \Illuminate\Support\Carbon tomorrow($tz = null) + * @method \Illuminate\Support\Carbon today($timezone = null) + * @method \Illuminate\Support\Carbon tomorrow($timezone = null) * @method void useMonthsOverflow($monthsOverflow = true) * @method void useStrictMode($strictModeEnabled = true) * @method void useYearsOverflow($yearsOverflow = true) - * @method \Illuminate\Support\Carbon yesterday($tz = null) + * @method \Illuminate\Support\Carbon yesterday($timezone = null) */ class DateFactory { From df80a44f291af8bd7b22f2b64a078059fd7bae4f Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Fri, 28 Feb 2025 16:50:42 +0000 Subject: [PATCH 122/455] Update facade docblocks --- src/Illuminate/Support/Facades/Date.php | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index 7d4607f99d67..462025508629 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -13,16 +13,16 @@ * @method static void useCallable(callable $callable) * @method static void useClass(string $dateClass) * @method static void useFactory(object $factory) - * @method static \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) - * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $tz = null) - * @method static \Illuminate\Support\Carbon|false createFromFormat($format, $time, $tz = null) - * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) - * @method static \Illuminate\Support\Carbon createFromTimeString($time, $tz = null) - * @method static \Illuminate\Support\Carbon createFromTimestamp($timestamp, $tz = null) - * @method static \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $tz = null) + * @method static \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|false createFromFormat($format, $time, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimeString($time, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp($timestamp, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $timezone = null) * @method static \Illuminate\Support\Carbon createFromTimestampUTC($timestamp) - * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null) - * @method static \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) + * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) * @method static void disableHumanDiffOption($humanDiffOption) * @method static void enableHumanDiffOption($humanDiffOption) * @method static mixed executeWithLocale($locale, $func) @@ -35,7 +35,7 @@ * @method static string getLocale() * @method static int getMidDayAt() * @method static \Illuminate\Support\Carbon|null getTestNow() - * @method static \Symfony\Component\Translation\TranslatorInterface getTranslator() + * @method static \Symfony\Contracts\Translation\TranslatorInterface getTranslator() * @method static int getWeekEndsAt() * @method static int getWeekStartsAt() * @method static array getWeekendDays() @@ -58,8 +58,8 @@ * @method static \Illuminate\Support\Carbon maxValue() * @method static \Illuminate\Support\Carbon minValue() * @method static void mixin($mixin) - * @method static \Illuminate\Support\Carbon now($tz = null) - * @method static \Illuminate\Support\Carbon parse($time = null, $tz = null) + * @method static \Illuminate\Support\Carbon now($timezone = null) + * @method static \Illuminate\Support\Carbon parse($time = null, $timezone = null) * @method static string pluralUnit(string $unit) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() @@ -70,7 +70,7 @@ * @method static void setMidDayAt($hour) * @method static void setTestNow($testNow = null) * @method static void setToStringFormat($format) - * @method static void setTranslator(\Symfony\Component\Translation\TranslatorInterface $translator) + * @method static void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) * @method static void setUtf8($utf8) * @method static void setWeekEndsAt($day) * @method static void setWeekStartsAt($day) @@ -78,12 +78,12 @@ * @method static bool shouldOverflowMonths() * @method static bool shouldOverflowYears() * @method static string singularUnit(string $unit) - * @method static \Illuminate\Support\Carbon today($tz = null) - * @method static \Illuminate\Support\Carbon tomorrow($tz = null) + * @method static \Illuminate\Support\Carbon today($timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow($timezone = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) - * @method static \Illuminate\Support\Carbon yesterday($tz = null) + * @method static \Illuminate\Support\Carbon yesterday($timezone = null) * * @see \Illuminate\Support\DateFactory */ From ab0b9b00ef1513d1eb562009462e17e5e7cfe9e5 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Fri, 28 Feb 2025 20:21:10 +0330 Subject: [PATCH 123/455] Add additional tests for Rule::array validation scenarios (#54844) * Added tests for Rule::array with empty arrays, duplicate keys, and numeric values. * Added tests for array validation with objects, nullable values, and empty arrays * Add test for getCount with valid excludeId condition --- tests/Validation/ValidationArrayRuleTest.php | 21 +++++++++++++++++++ ...ValidationDatabasePresenceVerifierTest.php | 14 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/Validation/ValidationArrayRuleTest.php b/tests/Validation/ValidationArrayRuleTest.php index 9df05e81430a..1057faa7adf1 100644 --- a/tests/Validation/ValidationArrayRuleTest.php +++ b/tests/Validation/ValidationArrayRuleTest.php @@ -18,6 +18,9 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $this->assertSame('array', (string) $rule); + $rule = Rule::array([]); + $this->assertSame('array', (string) $rule); + $rule = Rule::array('key_1', 'key_2', 'key_3'); $this->assertSame('array:key_1,key_2,key_3', (string) $rule); @@ -37,6 +40,12 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $rule = Rule::array([ArrayKeysBacked::key_1, ArrayKeysBacked::key_2, ArrayKeysBacked::key_3]); $this->assertSame('array:key_1,key_2,key_3', (string) $rule); + + $rule = Rule::array(['key_1', 'key_1']); + $this->assertSame('array:key_1,key_1', (string) $rule); + + $rule = Rule::array([1, 2, 3]); + $this->assertSame('array:1,2,3', (string) $rule); } public function testArrayValidation() @@ -46,6 +55,18 @@ public function testArrayValidation() $v = new Validator($trans, ['foo' => 'not an array'], ['foo' => Rule::array()]); $this->assertTrue($v->fails()); + $v = new Validator($trans, ['foo' => (object) ['key_1' => 'bar']], ['foo' => Rule::array()]); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['foo' => null], ['foo' => ['nullable', Rule::array()]]); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['foo' => []], ['foo' => Rule::array()]); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['foo' => ['key_1' => []]], ['foo' => Rule::array(['key_1'])]); + $this->assertTrue($v->passes()); + $v = new Validator($trans, ['foo' => ['bar']], ['foo' => (string) Rule::array()]); $this->assertTrue($v->passes()); diff --git a/tests/Validation/ValidationDatabasePresenceVerifierTest.php b/tests/Validation/ValidationDatabasePresenceVerifierTest.php index 96f484499059..cae7acd00bc8 100644 --- a/tests/Validation/ValidationDatabasePresenceVerifierTest.php +++ b/tests/Validation/ValidationDatabasePresenceVerifierTest.php @@ -60,4 +60,18 @@ public function testBasicCountWithClosures() $this->assertEquals(100, $verifier->getCount('table', 'column', 'value', null, null, $extra)); } + + public function testGetCountWithValidExcludeId() + { + $verifier = new DatabasePresenceVerifier($db = m::mock(ConnectionResolverInterface::class)); + $verifier->setConnection('connection'); + $db->shouldReceive('connection')->once()->with('connection')->andReturn($conn = m::mock(stdClass::class)); + $conn->shouldReceive('table')->once()->with('table')->andReturn($builder = m::mock(stdClass::class)); + $builder->shouldReceive('useWritePdo')->once()->andReturn($builder); + $builder->shouldReceive('where')->with('column', '=', 'value')->andReturn($builder); + $builder->shouldReceive('where')->with('id', '<>', 123)->andReturn($builder); + $builder->shouldReceive('count')->once()->andReturn(100); + + $this->assertEquals(100, $verifier->getCount('table', 'column', 'value', 123, 'id', [])); + } } From 928be7bcd3a895ad970082c7e88e9802081ac5d4 Mon Sep 17 00:00:00 2001 From: mohprilaksono <56257564+mohprilaksono@users.noreply.github.com> Date: Fri, 28 Feb 2025 23:52:00 +0700 Subject: [PATCH 124/455] remove return statement (#54842) --- src/Illuminate/Bus/Batch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Bus/Batch.php b/src/Illuminate/Bus/Batch.php index bcfb898cb940..6b11dd1ff60d 100644 --- a/src/Illuminate/Bus/Batch.php +++ b/src/Illuminate/Bus/Batch.php @@ -454,7 +454,7 @@ public function delete() protected function invokeHandlerCallback($handler, Batch $batch, ?Throwable $e = null) { try { - return $handler($batch, $e); + $handler($batch, $e); } catch (Throwable $e) { if (function_exists('report')) { report($e); From cfc65ac7ca9c9255e17d7c95a7e2884e16590063 Mon Sep 17 00:00:00 2001 From: co63oc Date: Sat, 1 Mar 2025 00:52:27 +0800 Subject: [PATCH 125/455] Fix (#54839) --- src/Illuminate/Filesystem/LocalFilesystemAdapter.php | 2 +- tests/Integration/Cache/RepositoryTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Filesystem/LocalFilesystemAdapter.php b/src/Illuminate/Filesystem/LocalFilesystemAdapter.php index 37d0e6934872..bca0ea42ea24 100644 --- a/src/Illuminate/Filesystem/LocalFilesystemAdapter.php +++ b/src/Illuminate/Filesystem/LocalFilesystemAdapter.php @@ -87,7 +87,7 @@ public function diskName(string $disk) } /** - * Indiate that signed URLs should serve the corresponding files. + * Indicate that signed URLs should serve the corresponding files. * * @param bool $serve * @param \Closure|null $urlGeneratorResolver diff --git a/tests/Integration/Cache/RepositoryTest.php b/tests/Integration/Cache/RepositoryTest.php index b0d48e2024fe..8b13595cd5c5 100644 --- a/tests/Integration/Cache/RepositoryTest.php +++ b/tests/Integration/Cache/RepositoryTest.php @@ -103,7 +103,7 @@ public function testStaleWhileRevalidate(): void $this->assertSame(3, $cache->get('foo')); $this->assertSame(946684832, $cache->get('illuminate:cache:flexible:created:foo')); - // Now we will execute the deferred callback but we will first aquire + // Now we will execute the deferred callback but we will first acquire // our own lock. This means that the value should not be refreshed by // deferred callback. /** @var Lock */ @@ -118,7 +118,7 @@ public function testStaleWhileRevalidate(): void $this->assertTrue($lock->release()); // Now we have cleared the lock we will, one last time, confirm that - // the deferred callack does refresh the value when the lock is not active. + // the deferred callback does refresh the value when the lock is not active. defer()->invoke(); $this->assertCount(0, defer()); $this->assertSame(4, $cache->get('foo')); From 7b8e12d8f4218615370d329a258f0b7c4afc6237 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Fri, 28 Feb 2025 11:59:47 -0500 Subject: [PATCH 126/455] [12.x] Do not loop through middleware when excluded is empty (#54837) * simplify resolving middleware * style * avoid loop above --- src/Illuminate/Routing/Router.php | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 8aaf0f36b643..4ea9480961eb 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -829,35 +829,35 @@ public function gatherRouteMiddleware(Route $route) */ public function resolveMiddleware(array $middleware, array $excluded = []) { - $excluded = (new Collection($excluded))->map(function ($name) { + $excluded = $excluded === [] ? $excluded : (new Collection($excluded))->map(function ($name) { return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups); })->flatten()->values()->all(); $middleware = (new Collection($middleware))->map(function ($name) { return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups); - })->flatten()->reject(function ($name) use ($excluded) { - if (empty($excluded)) { - return false; - } - - if ($name instanceof Closure) { - return false; - } - - if (in_array($name, $excluded, true)) { - return true; - } - - if (! class_exists($name)) { - return false; - } - - $reflection = new ReflectionClass($name); - - return (new Collection($excluded))->contains( - fn ($exclude) => class_exists($exclude) && $reflection->isSubclassOf($exclude) - ); - })->values(); + })->flatten() + ->when( + ! empty($excluded), + fn ($collection) => $collection->reject(function ($name) use ($excluded) { + if ($name instanceof Closure) { + return false; + } + + if (in_array($name, $excluded, true)) { + return true; + } + + if (! class_exists($name)) { + return false; + } + + $reflection = new ReflectionClass($name); + + return (new Collection($excluded))->contains( + fn ($exclude) => class_exists($exclude) && $reflection->isSubclassOf($exclude) + ); + }) + )->values(); return $this->sortMiddleware($middleware); } From 56458795c1e68aa88bee5b415f5e40b67d482ed3 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Mon, 3 Mar 2025 18:13:44 +0330 Subject: [PATCH 127/455] Add test for Arr::reject method (#54863) This commit adds test coverage for the Arr::reject method which filters an array using the negation of a given callback. The test verifies: - Basic rejection behavior with sequential arrays - Key preservation with associative arrays --- tests/Support/SupportArrTest.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 73676e981acf..4acef7238572 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -1533,4 +1533,32 @@ public function testSelect() [], ], Arr::select($array, null)); } + + public function testReject() + { + $array = [1, 2, 3, 4, 5, 6]; + + // Test rejection behavior (removing even numbers) + $result = Arr::reject($array, function ($value) { + return $value % 2 === 0; + }); + + $this->assertEquals([ + 0 => 1, + 2 => 3, + 4 => 5, + ], $result); + + // Test key preservation with associative array + $assocArray = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]; + + $result = Arr::reject($assocArray, function ($value) { + return $value > 2; + }); + + $this->assertEquals([ + 'a' => 1, + 'b' => 2, + ], $result); + } } From 64688352a46f280840e2a4a68d3793ede14a0252 Mon Sep 17 00:00:00 2001 From: Liam Duckett Date: Tue, 4 Mar 2025 15:01:53 +0000 Subject: [PATCH 128/455] [12.x] Feature: Array partition (#54859) * add array partition method * allow traversable in array partition * use array partition in collection partition * remove unneccesary import * use iterable instead of array|Traversable --- src/Illuminate/Collections/Arr.php | 26 +++++++++++++++++++ .../Collections/Traits/EnumeratesValues.php | 11 +------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 70fbb36924f5..8a1e9c575f98 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -942,6 +942,32 @@ public static function reject($array, callable $callback) return static::where($array, fn ($value, $key) => ! $callback($value, $key)); } + /** + * Partition the array into two arrays using the given callback. + * + * @template TKey of array-key + * @template TValue of mixed + * + * @param iterable $array + * @param callable $callback + * @return array, array> + */ + public static function partition($array, callable $callback) + { + $passed = []; + $failed = []; + + foreach ($array as $key => $item) { + if ($callback($item, $key)) { + $passed[$key] = $item; + } else { + $failed[$key] = $item; + } + } + + return [$passed, $failed]; + } + /** * Filter items where the value is not null. * diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 925ca760a884..13e799d99440 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -504,20 +504,11 @@ public function forPage($page, $perPage) */ public function partition($key, $operator = null, $value = null) { - $passed = []; - $failed = []; - $callback = func_num_args() === 1 ? $this->valueRetriever($key) : $this->operatorForWhere(...func_get_args()); - foreach ($this as $key => $item) { - if ($callback($item, $key)) { - $passed[$key] = $item; - } else { - $failed[$key] = $item; - } - } + [$passed, $failed] = Arr::partition($this->getIterator(), $callback); return new static([new static($passed), new static($failed)]); } From 78d85fbb8a30015e4e841a10118f8685b0e5a7dd Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:55:02 -0500 Subject: [PATCH 129/455] [12.x] Introduce `ContextLogProcessor` (#54851) * introduce setContextToLogProcessor * rename * tests * tests * tests * add context log processor * use processor * return type * removes unnecessary import * Update ContextTest.php * add interface to contracts * formatting * Update ContextServiceProvider.php --------- Co-authored-by: Taylor Otwell --- .../Contracts/Log/ContextLogProcessor.php | 9 +++ .../Log/Context/ContextLogProcessor.php | 39 ++++++++++ .../Log/Context/ContextServiceProvider.php | 3 + src/Illuminate/Log/LogManager.php | 13 +--- tests/Log/ContextTest.php | 74 +++++++++++++++++++ 5 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 src/Illuminate/Contracts/Log/ContextLogProcessor.php create mode 100644 src/Illuminate/Log/Context/ContextLogProcessor.php diff --git a/src/Illuminate/Contracts/Log/ContextLogProcessor.php b/src/Illuminate/Contracts/Log/ContextLogProcessor.php new file mode 100644 index 000000000000..ca6900cfbc27 --- /dev/null +++ b/src/Illuminate/Contracts/Log/ContextLogProcessor.php @@ -0,0 +1,9 @@ +app->bound(ContextRepository::class)) { + return $record; + } + + return $record->with(extra: [ + ...$record->extra, + ...$this->app[ContextRepository::class]->all(), + ]); + } +} diff --git a/src/Illuminate/Log/Context/ContextServiceProvider.php b/src/Illuminate/Log/Context/ContextServiceProvider.php index 7c00e256ae26..59f4c6c63fda 100644 --- a/src/Illuminate/Log/Context/ContextServiceProvider.php +++ b/src/Illuminate/Log/Context/ContextServiceProvider.php @@ -2,6 +2,7 @@ namespace Illuminate\Log\Context; +use Illuminate\Contracts\Log\ContextLogProcessor as ContextLogProcessorContract; use Illuminate\Queue\Events\JobProcessing; use Illuminate\Queue\Queue; use Illuminate\Support\Facades\Context; @@ -17,6 +18,8 @@ class ContextServiceProvider extends ServiceProvider public function register() { $this->app->scoped(Repository::class); + + $this->app->bind(ContextLogProcessorContract::class, fn ($app) => new ContextLogProcessor($app)); } /** diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 7563e35cb837..840cdd65dd5e 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -3,7 +3,7 @@ namespace Illuminate\Log; use Closure; -use Illuminate\Log\Context\Repository as ContextRepository; +use Illuminate\Contracts\Log\ContextLogProcessor; use Illuminate\Support\Collection; use Illuminate\Support\Str; use InvalidArgumentException; @@ -143,16 +143,7 @@ protected function get($name, ?array $config = null) )->withContext($this->sharedContext); if (method_exists($loggerWithContext->getLogger(), 'pushProcessor')) { - $loggerWithContext->pushProcessor(function ($record) { - if (! $this->app->bound(ContextRepository::class)) { - return $record; - } - - return $record->with(extra: [ - ...$record->extra, - ...$this->app[ContextRepository::class]->all(), - ]); - }); + $loggerWithContext->pushProcessor($this->app->make(ContextLogProcessor::class)); } return $this->channels[$name] = $loggerWithContext; diff --git a/tests/Log/ContextTest.php b/tests/Log/ContextTest.php index 98917b440c1e..657b2fa16fa1 100644 --- a/tests/Log/ContextTest.php +++ b/tests/Log/ContextTest.php @@ -4,6 +4,7 @@ use Exception; use Illuminate\Contracts\Debug\ExceptionHandler; +use Illuminate\Contracts\Log\ContextLogProcessor; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Testing\LazilyRefreshDatabase; use Illuminate\Log\Context\Events\ContextDehydrating as Dehydrating; @@ -13,6 +14,7 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; +use Monolog\LogRecord; use Orchestra\Testbench\TestCase; use RuntimeException; @@ -20,6 +22,13 @@ class ContextTest extends TestCase { use LazilyRefreshDatabase; + #[\Override] + protected function tearDown(): void + { + parent::tearDown(); + MyAddContextProcessor::$wasConstructed = false; + } + public function test_it_can_set_values() { $values = [ @@ -544,6 +553,55 @@ public function test_scope_sets_keys_and_restores() 'hiddenKey2' => 'world', ], Context::allHidden()); } + + public function test_uses_closure_for_context_processor() + { + $path = storage_path('logs/laravel.log'); + file_put_contents($path, ''); + + $this->app->bind( + ContextLogProcessor::class, + fn () => function (LogRecord $record): LogRecord { + $logChannel = Context::getHidden('log_channel_name'); + + return $record->with( + // allow overriding the context from what's been set on the log + context: array_merge(Context::all(), $record->context), + // use the log channel we've set in context, or fallback to the current channel + channel: $logChannel ?? $record->channel, + ); + } + ); + + Context::addHidden('log_channel_name', 'closure-test'); + Context::add(['value_from_context' => 'hello']); + + Log::info('This is an info log.', ['value_from_log_info_context' => 'foo']); + + $log = Str::after(file_get_contents($path), '] '); + $this->assertSame('closure-test.INFO: This is an info log. {"value_from_context":"hello","value_from_log_info_context":"foo"}', Str::trim($log)); + file_put_contents($path, ''); + } + + public function test_can_rebind_to_separate_class() + { + $path = storage_path('logs/laravel.log'); + file_put_contents($path, ''); + + $this->app->bind(ContextLogProcessor::class, MyAddContextProcessor::class); + + Context::add(['this-will-be-included' => false]); + + Log::info('This is an info log.', ['value_from_log_info_context' => 'foo']); + $log = Str::after(file_get_contents($path), '] '); + $this->assertSame( + 'testing.INFO: This is an info log. {"value_from_log_info_context":"foo","inside of MyAddContextProcessor":true}', + Str::trim($log) + ); + $this->assertTrue(MyAddContextProcessor::$wasConstructed); + + file_put_contents($path, ''); + } } enum Suit @@ -566,3 +624,19 @@ class ContextModel extends Model { // } + +class MyAddContextProcessor implements ContextLogProcessor +{ + public static bool $wasConstructed = false; + + public function __construct() + { + self::$wasConstructed = true; + } + + #[\Override] + public function __invoke(LogRecord $record): LogRecord + { + return $record->with(context: array_merge($record->context, ['inside of MyAddContextProcessor' => true])); + } +} From 09f4a014c3fea7726c6824f5e04fca6ee165e328 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 4 Mar 2025 10:10:40 -0600 Subject: [PATCH 130/455] minor release --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 17ae78df14be..85d83606cdbc 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.0.1'; + const VERSION = '12.1.0'; /** * The base path for the Laravel installation. From 761b42613af571e175255b03aedbc2cd7e0b7e65 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 4 Mar 2025 16:13:00 +0000 Subject: [PATCH 131/455] Update CHANGELOG --- CHANGELOG.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba1d08ead792..2ef195848f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.0.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.1.0...12.x) + +## [v12.1.0](https://github.com/laravel/framework/compare/v12.0.1...v12.1.0) - 2025-03-04 + +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54782 +* [12.x] Fix incorrect typehints in `BuildsWhereDateClauses` traits by [@mohprilaksono](https://github.com/mohprilaksono) in https://github.com/laravel/framework/pull/54784 +* [12.x] Improve queries readablility by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/54791 +* [12.x] Enhance eventStream to Support Custom Events and Start Messages by [@devhammed](https://github.com/devhammed) in https://github.com/laravel/framework/pull/54776 +* [12.x] Make the PendingCommand class tappable. by [@kevinb1989](https://github.com/kevinb1989) in https://github.com/laravel/framework/pull/54801 +* [12.x] Add missing union type in event stream docblock by [@devhammed](https://github.com/devhammed) in https://github.com/laravel/framework/pull/54800 +* Change return types of `paginage()` methods to `\Illuminate\Pagination\LengthAwarePaginator` by [@carestad](https://github.com/carestad) in https://github.com/laravel/framework/pull/54826 +* [12.x] Check if internal `Hasher::verifyConfiguration()` method exists on driver before forwarding call by [@rodrigopedra](https://github.com/rodrigopedra) in https://github.com/laravel/framework/pull/54833 +* [11.x] Fix using `AsStringable` cast on Notifiable's key by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54818 +* Add Tests for Handling Null Primary Keys and Special Values in Unique Validation Rule by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54823 +* Improve docblock for with() method to clarify it adds to existing eag… by [@igorlealantunes](https://github.com/igorlealantunes) in https://github.com/laravel/framework/pull/54838 +* [12.x] Fix dropping schema-qualified prefixed tables by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/54834 +* [12.x] Add `Context::scope()` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54799 +* Allow Http requests to be recorded without requests being faked by [@kemp](https://github.com/kemp) in https://github.com/laravel/framework/pull/54850 +* [12.x] Adds a new method "getRawSql" (with embedded bindings) to the QueryException class by [@erickcomp](https://github.com/erickcomp) in https://github.com/laravel/framework/pull/54849 +* Update Inspiring.php by [@ju-gow](https://github.com/ju-gow) in https://github.com/laravel/framework/pull/54846 +* [12.x] Correct use of named argument in `Date` facade and fix a return type. by [@lmottasin](https://github.com/lmottasin) in https://github.com/laravel/framework/pull/54847 +* Add additional tests for Rule::array validation scenarios by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54844 +* [12.x] Remove return statement by [@mohprilaksono](https://github.com/mohprilaksono) in https://github.com/laravel/framework/pull/54842 +* Fix typos by [@co63oc](https://github.com/co63oc) in https://github.com/laravel/framework/pull/54839 +* [12.x] Do not loop through middleware when excluded is empty by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54837 +* Add test for Arr::reject method in Illuminate Support by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54863 +* [12.x] Feature: Array partition by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/54859 +* [12.x] Introduce `ContextLogProcessor` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54851 ## [v12.0.1](https://github.com/laravel/framework/compare/v12.0.0...v12.0.1) - 2025-02-24 From 18a3622fcb21703715a117425b83e547c96a6baf Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Tue, 4 Mar 2025 15:55:59 -0600 Subject: [PATCH 132/455] Fixed typehint for callable in Arr::partition (#54896) --- src/Illuminate/Collections/Arr.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 8a1e9c575f98..63bb3111b66c 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -949,7 +949,7 @@ public static function reject($array, callable $callback) * @template TValue of mixed * * @param iterable $array - * @param callable $callback + * @param callable(TValue, TKey): bool $callback * @return array, array> */ public static function partition($array, callable $callback) From 88b71607d47e36b8c6e2050430a4bfa39568acf6 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Wed, 5 Mar 2025 01:39:49 +0330 Subject: [PATCH 133/455] Enhance Email and Image Dimensions Validation Tests (#54897) * Added new test cases for special values, constraint order, value overriding in `ValidationDimensionsRuleTest`. * Add more email validation cases to the testBasic method. --- .../ValidationDimensionsRuleTest.php | 36 +++++++++++++++++++ tests/Validation/ValidationEmailRuleTest.php | 22 ++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tests/Validation/ValidationDimensionsRuleTest.php b/tests/Validation/ValidationDimensionsRuleTest.php index 6bd2d0326e06..92ff39ca2b20 100644 --- a/tests/Validation/ValidationDimensionsRuleTest.php +++ b/tests/Validation/ValidationDimensionsRuleTest.php @@ -53,6 +53,42 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $this->assertSame('dimensions:min_ratio=0.5,max_ratio=0.33333333333333', (string) $rule); } + public function testItCorrectlyFormatsWithSpecialValues() + { + $rule = new Dimensions(); + + $this->assertSame('dimensions:', (string) $rule); + + $rule = Rule::dimensions()->width(-100)->height(-200); + + $this->assertSame('dimensions:width=-100,height=-200', (string) $rule); + + $rule = Rule::dimensions()->width('300')->height('400'); + + $this->assertSame('dimensions:width=300,height=400', (string) $rule); + } + + public function testDimensionsRuleMaintainsCorrectOrder() + { + $rule = Rule::dimensions()->minWidth(100)->width(200)->maxWidth(300); + + $this->assertSame('dimensions:min_width=100,width=200,max_width=300', (string) $rule); + } + + public function testOverridingValues() + { + $rule = Rule::dimensions()->width(100)->width(500); + + $this->assertSame('dimensions:width=500', (string) $rule); + } + + public function testRatioBetweenOverridesMinAndMaxRatio() + { + $rule = Rule::dimensions()->minRatio(0.5)->maxRatio(2.0)->ratioBetween(1, 1.5); + + $this->assertSame('dimensions:min_ratio=1,max_ratio=1.5', (string) $rule); + } + public function testGeneratesTheCorrectValidationMessages() { $rule = Rule::dimensions() diff --git a/tests/Validation/ValidationEmailRuleTest.php b/tests/Validation/ValidationEmailRuleTest.php index b6382f508bc4..aaae6c48f707 100644 --- a/tests/Validation/ValidationEmailRuleTest.php +++ b/tests/Validation/ValidationEmailRuleTest.php @@ -33,6 +33,18 @@ public function testBasic() ['The '.self::ATTRIBUTE_REPLACED.' must be a valid email address.'] ); + $this->fails( + Email::default(), + 12345, + [Email::class] + ); + + $this->fails( + Rule::email(), + 12345, + [Email::class] + ); + $this->passes( Email::default(), 'taylor@laravel.com' @@ -43,6 +55,16 @@ public function testBasic() 'taylor@laravel.com' ); + $this->passes( + Rule::email(), + ['taylor@laravel.com'], + ); + + $this->passes( + Email::default(), + ['taylor@laravel.com'], + ); + $this->passes(Email::default(), null); $this->passes(Rule::email(), null); From 93e3a68b26506a370a6146f538fbff76e960e885 Mon Sep 17 00:00:00 2001 From: Andy Hinkle Date: Tue, 4 Mar 2025 16:10:13 -0600 Subject: [PATCH 134/455] Apply default pint styling rules to the notification stub (#54895) --- src/Illuminate/Foundation/Console/stubs/notification.stub | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/notification.stub b/src/Illuminate/Foundation/Console/stubs/notification.stub index e573dcd271e9..ee32826b70a5 100644 --- a/src/Illuminate/Foundation/Console/stubs/notification.stub +++ b/src/Illuminate/Foundation/Console/stubs/notification.stub @@ -35,9 +35,9 @@ class {{ class }} extends Notification public function toMail(object $notifiable): MailMessage { return (new MailMessage) - ->line('The introduction to the notification.') - ->action('Notification Action', url('/')) - ->line('Thank you for using our application!'); + ->line('The introduction to the notification.') + ->action('Notification Action', url('/')) + ->line('Thank you for using our application!'); } /** From 9be5738f1ca1530055bb9d6db81f909a7ed34842 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:31:19 +0000 Subject: [PATCH 135/455] Update version to v12.1.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index b50ced9d0905..4a067367c0ce 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.1.0'; + const VERSION = '12.1.1'; /** * The base path for the Laravel installation. From 3dd1872b48873a84d58e395e3aff984da6442127 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:33:02 +0000 Subject: [PATCH 136/455] Update CHANGELOG --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ef195848f75..a949f3d37af3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.1.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.1.1...12.x) + +## [v12.1.1](https://github.com/laravel/framework/compare/v12.1.0...v12.1.1) - 2025-03-05 + +* [11.x] Add valid values to ensure method by [@lancepioch](https://github.com/lancepioch) in https://github.com/laravel/framework/pull/54840 +* Fix attribute name used on `Validator` instance within certain rule classes by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54845 +* [11.x] Fix `Application::interBasePath()` fails to resolve application when project name is "vendor" by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54871 +* [11.x] Test improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54879 +* [12.x] DocBlock: Changed typehint for `Arr::partition` method by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/54896 +* Enhance Email and Image Dimensions Validation Tests by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54897 +* [12.x] Apply default styling rules to the notification stub by [@ahinkle](https://github.com/ahinkle) in https://github.com/laravel/framework/pull/54895 ## [v12.1.0](https://github.com/laravel/framework/compare/v12.0.1...v12.1.0) - 2025-03-04 From 2a2050214ded9ff176e1f1e7e8a254baa2f539a6 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:36:19 +0000 Subject: [PATCH 137/455] Update CHANGELOG --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 901a0c1ec378..8a4c7a4c7be4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.44.0...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.44.1...11.x) + +## [v11.44.1](https://github.com/laravel/framework/compare/v11.44.0...v11.44.1) - 2025-03-05 + +* [11.x] Add valid values to ensure method by [@lancepioch](https://github.com/lancepioch) in https://github.com/laravel/framework/pull/54840 +* Fix attribute name used on `Validator` instance within certain rule classes by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54845 +* [11.x] Fix `Application::interBasePath()` fails to resolve application when project name is "vendor" by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54871 +* [11.x] Test improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54879 ## [v11.44.0](https://github.com/laravel/framework/compare/v11.43.2...v11.44.0) - 2025-02-24 From 154a0f17bb9cfe22b5b6b9daa4c6adacb41e0c3d Mon Sep 17 00:00:00 2001 From: Michael Newton Date: Wed, 5 Mar 2025 08:46:01 -0700 Subject: [PATCH 138/455] dates can be passed to having() (#54899) --- src/Illuminate/Database/Query/Builder.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 1bb26adf622e..b9ccfa6ead1a 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2400,8 +2400,8 @@ public function groupByRaw($sql, array $bindings = []) * Add a "having" clause to the query. * * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column - * @param string|int|float|null $operator - * @param string|int|float|null $value + * @param \DateTimeInterface|string|int|float|null $operator + * @param \DateTimeInterface|string|int|float|null $value * @param string $boolean * @return $this */ @@ -2452,8 +2452,8 @@ public function having($column, $operator = null, $value = null, $boolean = 'and * Add an "or having" clause to the query. * * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column - * @param string|int|float|null $operator - * @param string|int|float|null $value + * @param \DateTimeInterface|string|int|float|null $operator + * @param \DateTimeInterface|string|int|float|null $value * @return $this */ public function orHaving($column, $operator = null, $value = null) From 3bc68057f6f695acd9b74959caba4e862df3b99c Mon Sep 17 00:00:00 2001 From: Owen Voke Date: Wed, 5 Mar 2025 15:47:13 +0000 Subject: [PATCH 139/455] fix: resolve `whereNotMorphedTo` query (#54902) This resolves an issue with the `whereNotMorphedTo()` method where the query results in a double negative. This changes to a format that resembles the previous logic. --- .../Eloquent/Concerns/QueriesRelationships.php | 2 +- tests/Database/DatabaseEloquentBuilderTest.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index c6162d7656a8..a9acf90fb68f 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -674,7 +674,7 @@ public function whereNotMorphedTo($relation, $model, $boolean = 'and') $models->groupBy(fn ($model) => $model->getMorphClass())->each(function ($models) use ($query, $relation) { $query->orWhere(function ($query) use ($relation, $models) { $query->where($relation->qualifyColumn($relation->getMorphType()), '<=>', $models->first()->getMorphClass()) - ->whereNotIn($relation->qualifyColumn($relation->getForeignKeyName()), $models->map->getKey()); + ->whereIn($relation->qualifyColumn($relation->getForeignKeyName()), $models->map->getKey()); }); }); }, null, null, $boolean); diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 60daa61f0bcc..ad0c86122a9f 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -1837,7 +1837,7 @@ public function testWhereNotMorphedTo() $builder = $model->whereNotMorphedTo('morph', $relatedModel); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals([$relatedModel->getMorphClass(), $relatedModel->getKey()], $builder->getBindings()); } @@ -1854,7 +1854,7 @@ public function testWhereNotMorphedToCollection() $builder = $model->whereNotMorphedTo('morph', new Collection([$firstRelatedModel, $secondRelatedModel])); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)))', $builder->toSql()); $this->assertEquals([$firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $secondRelatedModel->getKey()], $builder->getBindings()); } @@ -1874,7 +1874,7 @@ public function testWhereNotMorphedToCollectionWithDifferentModels() $builder = $model->whereNotMorphedTo('morph', [$firstRelatedModel, $secondRelatedModel, $thirdRelatedModel]); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals([$firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $thirdRelatedModel->getKey(), $secondRelatedModel->getMorphClass(), $secondRelatedModel->id], $builder->getBindings()); } @@ -1950,7 +1950,7 @@ public function testOrWhereNotMorphedTo() $builder = $model->where('bar', 'baz')->orWhereNotMorphedTo('morph', $relatedModel); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals(['baz', $relatedModel->getMorphClass(), $relatedModel->getKey()], $builder->getBindings()); } @@ -1967,7 +1967,7 @@ public function testOrWhereNotMorphedToCollection() $builder = $model->where('bar', 'baz')->orWhereNotMorphedTo('morph', new Collection([$firstRelatedModel, $secondRelatedModel])); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)))', $builder->toSql()); $this->assertEquals(['baz', $firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $secondRelatedModel->getKey()], $builder->getBindings()); } @@ -1987,7 +1987,7 @@ public function testOrWhereNotMorphedToCollectionWithDifferentModels() $builder = $model->where('bar', 'baz')->orWhereNotMorphedTo('morph', [$firstRelatedModel, $secondRelatedModel, $thirdRelatedModel]); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals(['baz', $firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $thirdRelatedModel->getKey(), $secondRelatedModel->getMorphClass(), $secondRelatedModel->id], $builder->getBindings()); } From b9b9e3d7457bca6aa8ccbfcde6266643f8e56259 Mon Sep 17 00:00:00 2001 From: Liam Duckett Date: Wed, 5 Mar 2025 18:54:31 +0000 Subject: [PATCH 140/455] add test for array partition (#54913) --- tests/Support/SupportArrTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 4acef7238572..b7805c6127a3 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -1561,4 +1561,13 @@ public function testReject() 'b' => 2, ], $result); } + + public function testPartition() + { + $array = ['John', 'Jane', 'Greg']; + + $result = Arr::partition($array, fn (string $value) => str_contains($value, 'J')); + + $this->assertEquals([[0 => 'John', 1 => 'Jane'], [2 => 'Greg']], $result); + } } From fd8cf8b9afc2eb7104330ee39e2c0d3124c593fc Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 5 Mar 2025 20:11:55 +0100 Subject: [PATCH 141/455] [11.x] Expose process checkTimeout method (#54912) * Expose checkTimeout method * rename method --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Process/InvokedProcess.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Illuminate/Process/InvokedProcess.php b/src/Illuminate/Process/InvokedProcess.php index d19230ce8a44..c93f6bfba0c5 100644 --- a/src/Illuminate/Process/InvokedProcess.php +++ b/src/Illuminate/Process/InvokedProcess.php @@ -112,6 +112,22 @@ public function latestErrorOutput() return $this->process->getIncrementalErrorOutput(); } + /** + * Ensure that the process has not timed out. + * + * @return void + * + * @throws \Illuminate\Process\Exceptions\ProcessTimedOutException + */ + public function ensureNotTimedOut() + { + try { + $this->process->checkTimeout(); + } catch (SymfonyTimeoutException $e) { + throw new ProcessTimedOutException($e, new ProcessResult($this->process)); + } + } + /** * Wait for the process to finish. * From 4284e61c659fc4117e53d65db9043e0e4549c9bd Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Wed, 5 Mar 2025 19:37:08 +0000 Subject: [PATCH 142/455] [12.x] Compilable for Validation Contract (#54882) * Adds the compiled rules contract * Transforms NestedRules to use a Contract * style fix --- .../Contracts/Validation/CompilableRules.php | 17 +++++++++++ src/Illuminate/Validation/NestedRules.php | 22 ++------------ src/Illuminate/Validation/Rule.php | 30 +++++++++++++++++++ .../Validation/ValidationRuleParser.php | 7 +++-- 4 files changed, 54 insertions(+), 22 deletions(-) create mode 100644 src/Illuminate/Contracts/Validation/CompilableRules.php diff --git a/src/Illuminate/Contracts/Validation/CompilableRules.php b/src/Illuminate/Contracts/Validation/CompilableRules.php new file mode 100644 index 000000000000..2907824026ae --- /dev/null +++ b/src/Illuminate/Contracts/Validation/CompilableRules.php @@ -0,0 +1,17 @@ +callback, $value, $attribute, $data, $context); - $parser = new ValidationRuleParser( - Arr::undot(Arr::wrap($data)) - ); - - if (is_array($rules) && ! array_is_list($rules)) { - $nested = []; - - foreach ($rules as $key => $rule) { - $nested[$attribute.'.'.$key] = $rule; - } - - $rules = $nested; - } else { - $rules = [$attribute => $rules]; - } - - return $parser->explode(ValidationRuleParser::filterConditionalRules($rules, $data)); + return Rule::compile($attribute, $rules, $data); } } diff --git a/src/Illuminate/Validation/Rule.php b/src/Illuminate/Validation/Rule.php index 18da0c9c3921..44bb2b4347b5 100644 --- a/src/Illuminate/Validation/Rule.php +++ b/src/Illuminate/Validation/Rule.php @@ -3,6 +3,7 @@ namespace Illuminate\Validation; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Support\Arr; use Illuminate\Support\Traits\Macroable; use Illuminate\Validation\Rules\ArrayRule; use Illuminate\Validation\Rules\Can; @@ -244,4 +245,33 @@ public static function numeric() { return new Numeric; } + + /** + * Compile a set of rules for an attribute. + * + * @param string $attribute + * @param array $rules + * @param array|null $data + * @return object|\stdClass + */ + public static function compile($attribute, $rules, $data = null) + { + $parser = new ValidationRuleParser( + Arr::undot(Arr::wrap($data)) + ); + + if (is_array($rules) && ! array_is_list($rules)) { + $nested = []; + + foreach ($rules as $key => $rule) { + $nested[$attribute.'.'.$key] = $rule; + } + + $rules = $nested; + } else { + $rules = [$attribute => $rules]; + } + + return $parser->explode(ValidationRuleParser::filterConditionalRules($rules, $data)); + } } diff --git a/src/Illuminate/Validation/ValidationRuleParser.php b/src/Illuminate/Validation/ValidationRuleParser.php index c7fafbfa2149..c54fa2ce4370 100644 --- a/src/Illuminate/Validation/ValidationRuleParser.php +++ b/src/Illuminate/Validation/ValidationRuleParser.php @@ -3,6 +3,7 @@ namespace Illuminate\Validation; use Closure; +use Illuminate\Contracts\Validation\CompilableRules; use Illuminate\Contracts\Validation\InvokableRule; use Illuminate\Contracts\Validation\Rule as RuleContract; use Illuminate\Contracts\Validation\ValidationRule; @@ -138,7 +139,7 @@ protected function prepareRule($rule, $attribute) return $rule; } - if ($rule instanceof NestedRules) { + if ($rule instanceof CompilableRules) { return $rule->compile( $attribute, $this->data[$attribute] ?? null, Arr::dot($this->data), $this->data )->rules[$attribute]; @@ -164,7 +165,7 @@ protected function explodeWildcardRules($results, $attribute, $rules) foreach ($data as $key => $value) { if (Str::startsWith($key, $attribute) || (bool) preg_match('/^'.$pattern.'\z/', $key)) { foreach ((array) $rules as $rule) { - if ($rule instanceof NestedRules) { + if ($rule instanceof CompilableRules) { $context = Arr::get($this->data, Str::beforeLast($key, '.')); $compiled = $rule->compile($key, $value, $data, $context); @@ -238,7 +239,7 @@ protected function mergeRulesForAttribute($results, $attribute, $rules) */ public static function parse($rule) { - if ($rule instanceof RuleContract || $rule instanceof NestedRules) { + if ($rule instanceof RuleContract || $rule instanceof CompilableRules) { return [$rule, []]; } From f5679ceaeba6b7871656b3824985b50da01e715d Mon Sep 17 00:00:00 2001 From: Alexander Karlstad Date: Wed, 5 Mar 2025 23:03:36 +0100 Subject: [PATCH 143/455] Change `paginage()` method return types to `\Illuminate\Pagination\LengthAwarePaginator` (#54826) (#54917) Return types of all the subsequent calls are returning this, which in turn implements `\Illuminate\Contracts\Pagination\LengthAwarePaginator` Related to https://github.com/bmewburn/vscode-intelephense/issues/2912. Which I in turn had issues with locally where calling methods to the returned data from `->paginage()` did not auto complete. Hope this is possible to backport to 11.x too if this is a change that is okay. --- src/Illuminate/Database/Eloquent/Builder.php | 2 +- src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php | 2 +- .../Database/Eloquent/Relations/HasOneOrManyThrough.php | 2 +- src/Illuminate/Database/Query/Builder.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 1c27bb2ff773..57baa3a6801f 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1018,7 +1018,7 @@ public function pluck($column, $key = null) * @param string $pageName * @param int|null $page * @param \Closure|int|null $total - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 7019cf49c069..5618f0190f51 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -938,7 +938,7 @@ protected function aliasedPivotColumns() * @param array $columns * @param string $pageName * @param int|null $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index 6e74acf74651..72a65b0c1f5b 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -468,7 +468,7 @@ public function get($columns = ['*']) * @param array $columns * @param string $pageName * @param int $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 538994fe4b25..d6d9fd07b445 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3142,7 +3142,7 @@ protected function withoutGroupLimitKeys($items) * @param string $pageName * @param int|null $page * @param \Closure|int|null $total - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null, $total = null) { From 69a7dbd76e2ddc689a0de4e8d0e46d5682c55a18 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:02:47 +0100 Subject: [PATCH 144/455] Revert faulty change to `EnumeratesValues::ensure()` doc block (#54919) --- 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 7d47b1f1d02a..55c7110942da 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -342,7 +342,7 @@ public function value($key, $default = null) * * @template TEnsureOfType * - * @param class-string|array>|scalar|'array'|'null' $type + * @param class-string|array>|'string'|'int'|'float'|'bool'|'array'|'null' $type * @return static * * @throws \UnexpectedValueException From 3ac6ae196b1d0814e409064b4d7e6dc0ec405866 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Thu, 6 Mar 2025 18:09:15 +0330 Subject: [PATCH 145/455] Add `#[RequiresPhpExtension('intl')]` attribute to `testValidateMxRecord` and `testCombiningRules` due to intl extension dependency. (#54918) --- tests/Validation/ValidationEmailRuleTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Validation/ValidationEmailRuleTest.php b/tests/Validation/ValidationEmailRuleTest.php index b6382f508bc4..c48451db9bef 100644 --- a/tests/Validation/ValidationEmailRuleTest.php +++ b/tests/Validation/ValidationEmailRuleTest.php @@ -11,6 +11,7 @@ use Illuminate\Validation\Rules\Email; use Illuminate\Validation\ValidationServiceProvider; use Illuminate\Validation\Validator; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; @@ -143,6 +144,7 @@ public function testRfcCompliantStrict() ); } + #[RequiresPhpExtension('intl')] public function testValidateMxRecord() { $this->fails( @@ -674,6 +676,7 @@ public function testEmailsThatFailBothNativeValidationAndRfcCompliantStrict($ema ); } + #[RequiresPhpExtension('intl')] public function testCombiningRules() { $this->passes( From 7b420473aac5a66167cc7858d38d1628ed7e9af4 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Thu, 6 Mar 2025 18:12:27 +0330 Subject: [PATCH 146/455] Added test case to validate case sensitivity in Enum rule. (#54922) --- tests/Validation/ValidationEnumRuleTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Validation/ValidationEnumRuleTest.php b/tests/Validation/ValidationEnumRuleTest.php index 68200d3390cb..bf9ec319dc66 100644 --- a/tests/Validation/ValidationEnumRuleTest.php +++ b/tests/Validation/ValidationEnumRuleTest.php @@ -249,6 +249,22 @@ public function testValidationFailsWhenProvidingStringToIntegerType() $this->assertEquals(['The selected status is invalid.'], $v->messages()->get('status')); } + public function testValidationFailsWhenUsingDifferentCase() + { + $v = new Validator( + resolve('translator'), + [ + 'status' => 'DONE', + ], + [ + 'status' => new Enum(StringStatus::class), + ] + ); + + $this->assertTrue($v->fails()); + $this->assertEquals(['The selected status is invalid.'], $v->messages()->get('status')); + } + public static function conditionalCasesDataProvider(): array { return [ From 77672fd9597629695c5d6f0741894c05e490e06b Mon Sep 17 00:00:00 2001 From: Liam Duckett Date: Thu, 6 Mar 2025 14:44:23 +0000 Subject: [PATCH 147/455] [12.x] Feature: Collection chunk without preserving keys (#54916) * add test * implement chunking without preserving keys for support collection * implement chunking without preserving keys for lazy collection --- src/Illuminate/Collections/Collection.php | 5 +++-- src/Illuminate/Collections/LazyCollection.php | 12 +++++++++--- tests/Support/SupportCollectionTest.php | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index b157d8d3d67e..5da9963ed399 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1441,9 +1441,10 @@ public function firstOrFail($key = null, $operator = null, $value = null) * Chunk the collection into chunks of the given size. * * @param int $size + * @param bool $preserveKeys * @return static */ - public function chunk($size) + public function chunk($size, $preserveKeys = true) { if ($size <= 0) { return new static; @@ -1451,7 +1452,7 @@ public function chunk($size) $chunks = []; - foreach (array_chunk($this->items, $size, true) as $chunk) { + foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) { $chunks[] = new static($chunk); } diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 1673dd42a77f..ade500e2a565 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1376,22 +1376,28 @@ public function firstOrFail($key = null, $operator = null, $value = null) * Chunk the collection into chunks of the given size. * * @param int $size + * @param bool $preserveKeys * @return static */ - public function chunk($size) + public function chunk($size, $preserveKeys = true) { if ($size <= 0) { return static::empty(); } - return new static(function () use ($size) { + $add = match ($preserveKeys) { + true => fn (array &$chunk, Traversable $iterator) => $chunk[$iterator->key()] = $iterator->current(), + false => fn (array &$chunk, Traversable $iterator) => $chunk[] = $iterator->current(), + }; + + return new static(function () use ($size, $add) { $iterator = $this->getIterator(); while ($iterator->valid()) { $chunk = []; while (true) { - $chunk[$iterator->key()] = $iterator->current(); + $add($chunk, $iterator); if (count($chunk) < $size) { $iterator->next(); diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 58fd13751ebf..d0cdcfcd0923 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2145,6 +2145,24 @@ public function testChunkWhenGivenLessThanZero($collection) ); } + #[DataProvider('collectionClassProvider')] + public function testChunkPreservingKeys($collection) + { + $data = new $collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + $this->assertEquals( + [[0 => 1, 1 => 2, 2 => 3], [3 => 4, 4 => 5, 5 => 6], [6 => 7, 7 => 8, 8 => 9], [9 => 10]], + $data->chunk(3)->toArray() + ); + + $data = new $collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + $this->assertEquals( + [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], + $data->chunk(3, false)->toArray() + ); + } + #[DataProvider('collectionClassProvider')] public function testSplitIn($collection) { From 8bed88d2810c8835f66eeac678ce5f8218c825fd Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Thu, 6 Mar 2025 22:24:14 +0330 Subject: [PATCH 148/455] [12.x] Add test coverage for Uri::withQueryIfMissing method (#54923) * Add initial test for Uri::withQueryIfMissing method This test verifies that the withQueryIfMissing method adds parameters only when they don't exist while preserving the values of existing parameters. * Expand withQueryIfMissing tests to cover nested arrays This commit adds cases for complex nested arrays and indexed arrays to ensure the method correctly handles multi-dimensional data structures in query parameters. * Complete withQueryIfMissing tests for advanced array handling This commit finalizes tests for the withQueryIfMissing method, covering: - Partial merging of associative arrays - Preservation of indexed arrays - Verification of both encoded query strings and parsed arrays * docs: add PHPDoc annotation for withQueryIfMissing method * Update Uri.php --------- Co-authored-by: Taylor Otwell --- tests/Support/SupportUriTest.php | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/Support/SupportUriTest.php b/tests/Support/SupportUriTest.php index 95e05ea8791e..bd567817da45 100644 --- a/tests/Support/SupportUriTest.php +++ b/tests/Support/SupportUriTest.php @@ -126,4 +126,66 @@ public function test_decoding_the_entire_uri() $this->assertEquals('https://laravel.com/docs/11.x/installation?tags[0]=first&tags[1]=second', $uri->decode()); } + + public function test_with_query_if_missing() + { + // Test adding new parameters while preserving existing ones + $uri = Uri::of('https://laravel.com?existing=value'); + + $uri = $uri->withQueryIfMissing([ + 'new' => 'parameter', + 'existing' => 'new_value', + ]); + + $this->assertEquals('existing=value&new=parameter', $uri->query()->decode()); + + // Test adding complex nested arrays to empty query string + $uri = Uri::of('https://laravel.com'); + + $uri = $uri->withQueryIfMissing([ + 'name' => 'Taylor', + 'role' => [ + 'title' => 'Developer', + 'focus' => 'PHP', + ], + 'tags' => [ + 'person', + 'employee', + ], + ]); + + $this->assertEquals('name=Taylor&role[title]=Developer&role[focus]=PHP&tags[0]=person&tags[1]=employee', $uri->query()->decode()); + + // Test partial array merging and preserving indexed arrays + $uri = Uri::of('https://laravel.com?name=Taylor&tags[0]=person'); + + $uri = $uri->withQueryIfMissing([ + 'name' => 'Changed', + 'age' => 38, + 'tags' => ['should', 'not', 'change'], + ]); + + $this->assertEquals('name=Taylor&tags[0]=person&age=38', $uri->query()->decode()); + $this->assertEquals(['name' => 'Taylor', 'tags' => ['person'], 'age' => 38], $uri->query()->all()); + + $uri = Uri::of('https://laravel.com?user[name]=Taylor'); + + $uri = $uri->withQueryIfMissing([ + 'user' => [ + 'name' => 'Should Not Change', + 'age' => 38, + ], + 'settings' => [ + 'theme' => 'dark', + ], + ]); + $this->assertEquals([ + 'user' => [ + 'name' => 'Taylor', + ], + 'settings' => [ + 'theme' => 'dark', + ], + ], $uri->query()->all()); + } } From 8fd1ef12dcfd526dfe4c8ff6ad261b14baef06ca Mon Sep 17 00:00:00 2001 From: Razvan Aurariu <38325118+rzv-me@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:12:58 +0200 Subject: [PATCH 149/455] Fix issue with using RedisCluster with compression or serialization (#54934) --- .../Redis/Connections/PacksPhpRedisValues.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php index 81a6ebc74ec8..a64c4f4ce3dc 100644 --- a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php +++ b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php @@ -95,26 +95,26 @@ public function withoutSerializationOrCompression(callable $callback) $oldSerializer = null; if ($this->serialized()) { - $oldSerializer = $client->getOption($client::OPT_SERIALIZER); - $client->setOption($client::OPT_SERIALIZER, $client::SERIALIZER_NONE); + $oldSerializer = $client->getOption(Redis::OPT_SERIALIZER); + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); } $oldCompressor = null; if ($this->compressed()) { - $oldCompressor = $client->getOption($client::OPT_COMPRESSION); - $client->setOption($client::OPT_COMPRESSION, $client::COMPRESSION_NONE); + $oldCompressor = $client->getOption(Redis::OPT_COMPRESSION); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE); } try { return $callback(); } finally { if ($oldSerializer !== null) { - $client->setOption($client::OPT_SERIALIZER, $oldSerializer); + $client->setOption(Redis::OPT_SERIALIZER, $oldSerializer); } if ($oldCompressor !== null) { - $client->setOption($client::OPT_COMPRESSION, $oldCompressor); + $client->setOption(Redis::OPT_COMPRESSION, $oldCompressor); } } } From 189a0bb7cf6d145309ba1ae73a881c525c8024d7 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Fri, 7 Mar 2025 18:44:05 +0330 Subject: [PATCH 150/455] [12.x] Add test coverage for Str::replaceMatches method (#54930) * Add tests for Str::replaceMatches with string replacements This commit adds tests for the basic functionality of the replaceMatches method using string replacements and array of patterns. * Complete Str::replaceMatches tests with limit parameter tests This commit finalizes the test coverage for the replaceMatches method by adding tests for the limit parameter, which controls the maximum number of replacements to be performed. --- tests/Support/SupportStrTest.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index ff4ddfbbb173..0c46efa5f828 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -1758,6 +1758,38 @@ public function testChopEnd() $this->assertSame($expected, Str::chopEnd($subject, $needle)); } } + + public function testReplaceMatches() + { + // Test basic string replacement + $this->assertSame('foo bar bar', Str::replaceMatches('/baz/', 'bar', 'foo baz bar')); + $this->assertSame('foo baz baz', Str::replaceMatches('/404/', 'found', 'foo baz baz')); + + // Test with array of patterns + $this->assertSame('foo XXX YYY', Str::replaceMatches(['/bar/', '/baz/'], ['XXX', 'YYY'], 'foo bar baz')); + + // Test with callback + $result = Str::replaceMatches('/ba(.)/', function ($match) { + return 'ba'.strtoupper($match[1]); + }, 'foo baz bar'); + + $this->assertSame('foo baZ baR', $result); + + $result = Str::replaceMatches('/(\d+)/', function ($match) { + return $match[1] * 2; + }, 'foo 123 bar 456'); + + $this->assertSame('foo 246 bar 912', $result); + + // Test with limit parameter + $this->assertSame('foo baz baz', Str::replaceMatches('/ba(.)/', 'ba$1', 'foo baz baz', 1)); + + $result = Str::replaceMatches('/ba(.)/', function ($match) { + return 'ba'.strtoupper($match[1]); + }, 'foo baz baz bar', 1); + + $this->assertSame('foo baZ baz bar', $result); + } } class StringableObjectStub From db6ee21288b4409b0bdccf0fa45bdfd7b3722e8d Mon Sep 17 00:00:00 2001 From: Liam Duckett Date: Fri, 7 Mar 2025 15:21:05 +0000 Subject: [PATCH 151/455] [12.x] Types: Collection chunk without preserving keys (#54924) * add failing type assertions * simplify tests * fix typehint for collection, lazy collection chunk when not preserving keys --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/LazyCollection.php | 2 +- tests/Support/SupportCollectionTest.php | 12 ++++++------ types/Support/Collection.php | 8 ++++++-- types/Support/LazyCollection.php | 10 +++++++--- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 5da9963ed399..14c2f067efe9 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1442,7 +1442,7 @@ public function firstOrFail($key = null, $operator = null, $value = null) * * @param int $size * @param bool $preserveKeys - * @return static + * @return ($preserveKeys is true ? static : static>) */ public function chunk($size, $preserveKeys = true) { diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index ade500e2a565..47fbb665c7c5 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1377,7 +1377,7 @@ public function firstOrFail($key = null, $operator = null, $value = null) * * @param int $size * @param bool $preserveKeys - * @return static + * @return ($preserveKeys is true ? static : static>) */ public function chunk($size, $preserveKeys = true) { diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index d0cdcfcd0923..41b5f06f629f 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2148,18 +2148,18 @@ public function testChunkWhenGivenLessThanZero($collection) #[DataProvider('collectionClassProvider')] public function testChunkPreservingKeys($collection) { - $data = new $collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + $data = new $collection(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5]); $this->assertEquals( - [[0 => 1, 1 => 2, 2 => 3], [3 => 4, 4 => 5, 5 => 6], [6 => 7, 7 => 8, 8 => 9], [9 => 10]], - $data->chunk(3)->toArray() + [['a' => 1, 'b' => 2], ['c' => 3, 'd' => 4], ['e' => 5]], + $data->chunk(2)->toArray() ); - $data = new $collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + $data = new $collection([1, 2, 3, 4, 5]); $this->assertEquals( - [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], - $data->chunk(3, false)->toArray() + [[0 => 1, 1 => 2], [0 => 3, 1 => 4], [0 => 5]], + $data->chunk(2, false)->toArray() ); } diff --git a/types/Support/Collection.php b/types/Support/Collection.php index 701735e732f2..05a5b79fcd46 100644 --- a/types/Support/Collection.php +++ b/types/Support/Collection.php @@ -10,7 +10,7 @@ class Users implements Arrayable { public function toArray(): array { - return [new User()]; + return [new User]; } } @@ -21,6 +21,8 @@ public function toArray(): array /** @var Traversable $traversable */ $traversable = new ArrayIterator(['string']); +$associativeCollection = collect(['John' => new User]); + class Invokable { public function __invoke(): string @@ -28,7 +30,7 @@ public function __invoke(): string return 'Taylor'; } } -$invokable = new Invokable(); +$invokable = new Invokable; assertType('Illuminate\Support\Collection', $collection); @@ -806,6 +808,8 @@ function ($collection, $count) { assertType('Illuminate\Support\Collection>', $collection::make(['string'])->chunk(1)); assertType('Illuminate\Support\Collection>', $collection->chunk(2)); +assertType('Illuminate\Support\Collection>', $associativeCollection->chunk(2)); +assertType('Illuminate\Support\Collection>', $associativeCollection->chunk(2, false)); assertType('Illuminate\Support\Collection>', $collection->chunkWhile(function ($user, $int, $collection) { assertType('User', $user); diff --git a/types/Support/LazyCollection.php b/types/Support/LazyCollection.php index 287eb69a2127..7c1359f58a40 100644 --- a/types/Support/LazyCollection.php +++ b/types/Support/LazyCollection.php @@ -11,20 +11,22 @@ class Users implements Arrayable { public function toArray(): array { - return [new User()]; + return [new User]; } } $collection = new LazyCollection([new User]); -$arrayable = new Users(); +$arrayable = new Users; /** @var iterable $iterable */ $iterable = [1]; /** @var Traversable $traversable */ $traversable = new ArrayIterator(['string']); $generator = function () { - yield new User(); + yield new User; }; +$associativeCollection = new LazyCollection(['Sam' => new User]); + assertType('Illuminate\Support\LazyCollection', $collection); assertType("Illuminate\Support\LazyCollection", new LazyCollection(['string'])); @@ -665,6 +667,8 @@ public function toArray(): array assertType('Illuminate\Support\LazyCollection>', $collection::make(['string'])->chunk(1)); assertType('Illuminate\Support\LazyCollection>', $collection->chunk(2)); +assertType('Illuminate\Support\LazyCollection>', $associativeCollection->chunk(2)); +assertType('Illuminate\Support\LazyCollection>', $associativeCollection->chunk(2, false)); assertType('Illuminate\Support\LazyCollection>', $collection->chunkWhile(function ($user, $int, $collection) { assertType('User', $user); From fe8c50c6ddf490a4c58aa5b779a4dbd4aa3cef30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sam=20Carr=C3=A9?= <29132017+Sammyjo20@users.noreply.github.com> Date: Fri, 7 Mar 2025 15:27:29 +0000 Subject: [PATCH 152/455] [12.x] Add `ddBody` method to TestResponse for dumping various response payloads (#54933) * [12.x] Add method to TestResponse for dumping various response payloads * Update TestResponse.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Testing/TestResponse.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index e930d3bb7d21..94d2239e0aed 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -1645,6 +1645,23 @@ public function ddHeaders() exit(1); } + /** + * Dump the body of the response and end the script. + * + * @param string|null $key + * @return never + */ + public function ddBody($key = null) + { + $content = $this->content(); + + if (json_validate($content)) { + $this->ddJson($key); + } + + dd($content); + } + /** * Dump the JSON payload from the response and end the script. * From 006eada75f5d17bb71be26f2169540390e417508 Mon Sep 17 00:00:00 2001 From: Razvan Aurariu <38325118+rzv-me@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:42:48 +0200 Subject: [PATCH 153/455] Fix issue with using RedisCluster with compression or serialization for Laravel 11.x (#54935) --- .../Redis/Connections/PacksPhpRedisValues.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php index 526a764ede89..1a81720b0752 100644 --- a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php +++ b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php @@ -95,26 +95,26 @@ public function withoutSerializationOrCompression(callable $callback) $oldSerializer = null; if ($this->serialized()) { - $oldSerializer = $client->getOption($client::OPT_SERIALIZER); - $client->setOption($client::OPT_SERIALIZER, $client::SERIALIZER_NONE); + $oldSerializer = $client->getOption(Redis::OPT_SERIALIZER); + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); } $oldCompressor = null; if ($this->compressed()) { - $oldCompressor = $client->getOption($client::OPT_COMPRESSION); - $client->setOption($client::OPT_COMPRESSION, $client::COMPRESSION_NONE); + $oldCompressor = $client->getOption(Redis::OPT_COMPRESSION); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE); } try { return $callback(); } finally { if ($oldSerializer !== null) { - $client->setOption($client::OPT_SERIALIZER, $oldSerializer); + $client->setOption(Redis::OPT_SERIALIZER, $oldSerializer); } if ($oldCompressor !== null) { - $client->setOption($client::OPT_COMPRESSION, $oldCompressor); + $client->setOption(Redis::OPT_COMPRESSION, $oldCompressor); } } } From c5f2a94676b6397647c5751387eda574736a4a2d Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 7 Mar 2025 12:46:52 -0600 Subject: [PATCH 154/455] [12.x] feat: add `CanBeOneOfMany` support to `HasOneThrough` (#54759) * chore: use existing method when filling HasOneThrough * fix: correct query instance not being passed to HasOneOrManyThrough::addEagerConstraints * fix: duplicate constraints on OneOfMany queries * feat: add *OfMany support to HasOneThrough * formatting --------- Co-authored-by: Taylor Otwell --- .../Relations/Concerns/CanBeOneOfMany.php | 2 - .../Eloquent/Relations/HasManyThrough.php | 2 +- .../Relations/HasOneOrManyThrough.php | 3 +- .../Eloquent/Relations/HasOneThrough.php | 55 +- .../DatabaseEloquentHasOneOfManyTest.php | 6 +- ...atabaseEloquentHasOneThroughOfManyTest.php | 756 ++++++++++++++++++ .../DatabaseEloquentMorphOneOfManyTest.php | 2 +- 7 files changed, 816 insertions(+), 10 deletions(-) create mode 100755 tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php index 800999f86c78..0240f7f59529 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php @@ -131,8 +131,6 @@ public function ofMany($column = 'id', $aggregate = 'MAX', $relation = null) ]; } - $this->addConstraints(); - $columns = $this->query->getQuery()->columns; if (is_null($columns) || $columns === ['*']) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 37e8410b58b6..9f9ba0484d29 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -29,7 +29,7 @@ public function one() $this->farParent, $this->throughParent, $this->getFirstKeyName(), - $this->secondKey, + $this->getForeignKeyName(), $this->getLocalKeyName(), $this->getSecondLocalKeyName(), )); diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index 72a65b0c1f5b..c25be24b7016 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -168,7 +168,8 @@ public function addEagerConstraints(array $models) $this->whereInEager( $whereIn, $this->getQualifiedFirstKeyName(), - $this->getKeys($models, $this->localKey) + $this->getKeys($models, $this->localKey), + $this->getRelationQuery(), ); } diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php index 21de2e301213..5567124bde5b 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php @@ -2,10 +2,15 @@ namespace Illuminate\Database\Eloquent\Relations; +use Illuminate\Contracts\Database\Eloquent\SupportsPartialRelations; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Concerns\CanBeOneOfMany; +use Illuminate\Database\Eloquent\Relations\Concerns\ComparesRelatedModels; use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; +use Illuminate\Database\Query\JoinClause; /** * @template TRelatedModel of \Illuminate\Database\Eloquent\Model @@ -14,13 +19,17 @@ * * @extends \Illuminate\Database\Eloquent\Relations\HasOneOrManyThrough */ -class HasOneThrough extends HasOneOrManyThrough +class HasOneThrough extends HasOneOrManyThrough implements SupportsPartialRelations { - use InteractsWithDictionary, SupportsDefaultModels; + use ComparesRelatedModels, CanBeOneOfMany, InteractsWithDictionary, SupportsDefaultModels; /** @inheritDoc */ public function getResults() { + if (is_null($this->getParentKey())) { + return $this->getDefaultFor($this->farParent); + } + return $this->first() ?: $this->getDefaultFor($this->farParent); } @@ -54,6 +63,36 @@ public function match(array $models, EloquentCollection $results, $relation) return $models; } + /** @inheritDoc */ + public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) + { + if ($this->isOneOfMany()) { + $this->mergeOneOfManyJoinsTo($query); + } + + return parent::getRelationExistenceQuery($query, $parentQuery, $columns); + } + + /** @inheritDoc */ + public function addOneOfManySubQueryConstraints(Builder $query, $column = null, $aggregate = null) + { + $query->addSelect([$this->getQualifiedFirstKeyName()]); + + $this->performJoin($query); + } + + /** @inheritDoc */ + public function getOneOfManySubQuerySelectColumns() + { + return [$this->getQualifiedFirstKeyName()]; + } + + /** @inheritDoc */ + public function addOneOfManyJoinSubQueryConstraints(JoinClause $join) + { + $join->on($this->qualifySubSelectColumn($this->firstKey), '=', $this->getQualifiedFirstKeyName()); + } + /** * Make a new related instance for the given model. * @@ -64,4 +103,16 @@ public function newRelatedInstanceFor(Model $parent) { return $this->related->newInstance(); } + + /** @inheritDoc */ + protected function getRelatedKeyFrom(Model $model) + { + return $model->getAttribute($this->getForeignKeyName()); + } + + /** @inheritDoc */ + public function getParentKey() + { + return $this->farParent->getAttribute($this->localKey); + } } diff --git a/tests/Database/DatabaseEloquentHasOneOfManyTest.php b/tests/Database/DatabaseEloquentHasOneOfManyTest.php index c5a47355431e..dff1fdd9e79d 100755 --- a/tests/Database/DatabaseEloquentHasOneOfManyTest.php +++ b/tests/Database/DatabaseEloquentHasOneOfManyTest.php @@ -104,7 +104,7 @@ public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery() $user = HasOneOfManyTestUser::create(); $relation = $user->latest_login(); $relation->addEagerConstraints([$user]); - $this->assertSame('select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id"', $relation->getOneOfManySubQuery()->toSql()); + $this->assertSame('select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" in (1) group by "logins"."user_id"', $relation->getOneOfManySubQuery()->toSql()); } public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalScope() @@ -116,7 +116,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco $user = HasOneOfManyTestUser::create(); $relation = $user->latest_login_without_global_scope(); $relation->addEagerConstraints([$user]); - $this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toSql()); + $this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" in (1) group by "logins"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toSql()); HasOneOfManyTestLogin::addGlobalScope('test', function ($query) { }); @@ -130,7 +130,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco $user = HasOneOfManyTestUser::create(); $relation = $user->price_without_global_scope(); - $this->assertSame('select "prices".* from "prices" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" inner join (select max("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" where "published_at" < ? and "prices"."user_id" = ? and "prices"."user_id" is not null group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "prices"."user_id" = ? and "prices"."user_id" is not null', $relation->getQuery()->toSql()); + $this->assertSame('select "prices".* from "prices" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" inner join (select max("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "prices"."user_id" = ? and "prices"."user_id" is not null', $relation->getQuery()->toSql()); HasOneOfManyTestPrice::addGlobalScope('test', function ($query) { }); diff --git a/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php b/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php new file mode 100755 index 000000000000..0d2e5d671ca5 --- /dev/null +++ b/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php @@ -0,0 +1,756 @@ +addConnection(['driver' => 'sqlite', 'database' => ':memory:']); + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + public function createSchema(): void + { + $this->schema()->create('users', function ($table) { + $table->increments('id'); + }); + + $this->schema()->create('intermediates', function ($table) { + $table->increments('id'); + $table->foreignId('user_id'); + }); + + $this->schema()->create('logins', function ($table) { + $table->increments('id'); + $table->foreignId('intermediate_id'); + $table->dateTime('deleted_at')->nullable(); + }); + + $this->schema()->create('states', function ($table) { + $table->increments('id'); + $table->string('state'); + $table->string('type'); + $table->foreignId('intermediate_id'); + $table->timestamps(); + }); + + $this->schema()->create('prices', function ($table) { + $table->increments('id'); + $table->dateTime('published_at'); + $table->foreignId('intermediate_id'); + }); + } + + protected function tearDown(): void + { + $this->schema()->drop('users'); + $this->schema()->drop('intermediates'); + $this->schema()->drop('logins'); + $this->schema()->drop('states'); + $this->schema()->drop('prices'); + } + + public function testItGuessesRelationName(): void + { + $user = HasOneThroughOfManyTestUser::make(); + $this->assertSame('latest_login', $user->latest_login()->getRelationName()); + } + + public function testItGuessesRelationNameAndAddsOfManyWhenTableNameIsRelationName(): void + { + $model = HasOneThroughOfManyTestModel::make(); + $this->assertSame('logins_of_many', $model->logins()->getRelationName()); + } + + public function testRelationNameCanBeSet(): void + { + $user = HasOneThroughOfManyTestUser::create(); + + $relation = $user->latest_login()->ofMany('id', 'max', 'foo'); + $this->assertSame('foo', $relation->getRelationName()); + + $relation = $user->latest_login()->latestOfMany('id', 'bar'); + $this->assertSame('bar', $relation->getRelationName()); + + $relation = $user->latest_login()->oldestOfMany('id', 'baz'); + $this->assertSame('baz', $relation->getRelationName()); + } + + public function testCorrectLatestOfManyQuery(): void + { + $user = HasOneThroughOfManyTestUser::create(); + $relation = $user->latest_login(); + $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" group by "intermediates"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + } + + public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery(): void + { + $user = HasOneThroughOfManyTestUser::create(); + $relation = $user->latest_login(); + $relation->addEagerConstraints([$user]); + $this->assertSame('select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" in (1) group by "intermediates"."user_id"', $relation->getOneOfManySubQuery()->toSql()); + } + + public function testEagerLoadingAppliesConstraintsToQuery(): void + { + $user = HasOneThroughOfManyTestUser::create(); + $relation = $user->latest_login(); + $relation->addEagerConstraints([$user]); + $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" in (1) group by "intermediates"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + } + + public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalScope(): void + { + HasOneThroughOfManyTestLogin::addGlobalScope('test', function ($query) { + $query->orderBy($query->qualifyColumn('id')); + }); + + $user = HasOneThroughOfManyTestUser::create(); + $relation = $user->latest_login_without_global_scope(); + $relation->addEagerConstraints([$user]); + $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" in (1) group by "intermediates"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + + HasOneThroughOfManyTestLogin::addGlobalScope('test', function ($query) { + }); + } + + public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalScopeWithComplexQuery(): void + { + HasOneThroughOfManyTestPrice::addGlobalScope('test', function ($query) { + $query->orderBy($query->qualifyColumn('id')); + }); + + $user = HasOneThroughOfManyTestUser::create(); + $relation = $user->price_without_global_scope(); + $this->assertSame('select "prices".* from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "intermediates"."user_id" from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" inner join (select max("prices"."published_at") as "published_at_aggregate", "intermediates"."user_id" from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" where "published_at" < ? group by "intermediates"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "intermediates"."user_id" where "published_at" < ? group by "intermediates"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + + HasOneThroughOfManyTestPrice::addGlobalScope('test', function ($query) { + }); + } + + public function testQualifyingSubSelectColumn(): void + { + $user = HasOneThroughOfManyTestUser::make(); + $this->assertSame('latest_login.id', $user->latest_login()->qualifySubSelectColumn('id')); + } + + public function testItFailsWhenUsingInvalidAggregate(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid aggregate [count] used within ofMany relation. Available aggregates: MIN, MAX'); + $user = HasOneThroughOfManyTestUser::make(); + $user->latest_login_with_invalid_aggregate(); + } + + public function testItGetsCorrectResults(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->last()->logins()->create(); + $latestLogin = $user->intermediates->first()->logins()->create(); + + $result = $user->latest_login()->getResults(); + $this->assertNotNull($result); + $this->assertSame($latestLogin->id, $result->id); + } + + public function testResultDoesNotHaveAggregateColumn(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(1)->create(); + $user->intermediates->first()->logins()->create(); + + $result = $user->latest_login()->getResults(); + $this->assertNotNull($result); + $this->assertFalse(isset($result->id_aggregate)); + } + + public function testItGetsCorrectResultsUsingShortcutMethod(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->last()->logins()->create(); + $latestLogin = $user->intermediates->first()->logins()->create(); + + $result = $user->latest_login_with_shortcut()->getResults(); + $this->assertNotNull($result); + $this->assertSame($latestLogin->id, $result->id); + } + + public function testItGetsCorrectResultsUsingShortcutReceivingMultipleColumnsMethod(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + $price = $user->intermediates->first()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + + $result = $user->price_with_shortcut()->getResults(); + $this->assertNotNull($result); + $this->assertSame($price->id, $result->id); + } + + public function testKeyIsAddedToAggregatesWhenMissing(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + $price = $user->intermediates->first()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + + $result = $user->price_without_key_in_aggregates()->getResults(); + $this->assertNotNull($result); + $this->assertSame($price->id, $result->id); + } + + public function testItGetsWithConstraintsCorrectResults(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->last()->logins()->create(); + $user->intermediates->first()->logins()->create(); + + $result = $user->latest_login()->whereKey($previousLogin->getKey())->getResults(); + $this->assertNull($result); + } + + public function testItEagerLoadsCorrectModels(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->logins()->create(); + $latestLogin = $user->intermediates->first()->logins()->create(); + + $user = HasOneThroughOfManyTestUser::with('latest_login')->first(); + + $this->assertTrue($user->relationLoaded('latest_login')); + $this->assertSame($latestLogin->id, $user->latest_login->id); + } + + public function testItJoinsOtherTableInSubQuery(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->first()->logins()->create(); + + $this->assertNull($user->latest_login_with_foo_state); + + $user->unsetRelation('latest_login_with_foo_state'); + $user->intermediates->first()->states()->create([ + 'type' => 'foo', + 'state' => 'draft', + ]); + + $this->assertNotNull($user->latest_login_with_foo_state); + } + + public function testHasNested(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->first()->logins()->create(); + $latestLogin = $user->intermediates->last()->logins()->create(); + + $found = HasOneThroughOfManyTestUser::whereHas('latest_login', function ($query) use ($latestLogin) { + $query->where('logins.id', $latestLogin->id); + })->exists(); + $this->assertTrue($found); + + $found = HasOneThroughOfManyTestUser::whereHas('latest_login', function ($query) use ($previousLogin) { + $query->where('logins.id', $previousLogin->id); + })->exists(); + $this->assertFalse($found); + } + + public function testWithHasNested(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->first()->logins()->create(); + $latestLogin = $user->intermediates->last()->logins()->create(); + + $found = HasOneThroughOfManyTestUser::withWhereHas('latest_login', function ($query) use ($latestLogin) { + $query->where('logins.id', $latestLogin->id); + })->first(); + + $this->assertTrue((bool) $found); + $this->assertTrue($found->relationLoaded('latest_login')); + $this->assertEquals($found->latest_login->id, $latestLogin->id); + + $found = HasOneThroughOfManyTestUser::withWhereHas('latest_login', function ($query) use ($previousLogin) { + $query->where('logins.id', $previousLogin->id); + })->exists(); + + $this->assertFalse($found); + } + + public function testHasCount(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->logins()->create(); + $user->intermediates->first()->logins()->create(); + + $user = HasOneThroughOfManyTestUser::withCount('latest_login')->first(); + $this->assertEquals(1, $user->latest_login_count); + } + + public function testExists(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->last()->logins()->create(); + $latestLogin = $user->intermediates->first()->logins()->create(); + + $this->assertFalse($user->latest_login()->whereKey($previousLogin->getKey())->exists()); + $this->assertTrue($user->latest_login()->whereKey($latestLogin->getKey())->exists()); + } + + public function testIsMethod(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $login1 = $user->intermediates->last()->logins()->create(); + $login2 = $user->intermediates->first()->logins()->create(); + + $this->assertFalse($user->latest_login()->is($login1)); + $this->assertTrue($user->latest_login()->is($login2)); + } + + public function testIsNotMethod(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $login1 = $user->intermediates->last()->logins()->create(); + $login2 = $user->intermediates->first()->logins()->create(); + + $this->assertTrue($user->latest_login()->isNot($login1)); + $this->assertFalse($user->latest_login()->isNot($login2)); + } + + public function testGet(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $previousLogin = $user->intermediates->last()->logins()->create(); + $latestLogin = $user->intermediates->first()->logins()->create(); + + $latestLogins = $user->latest_login()->get(); + $this->assertCount(1, $latestLogins); + $this->assertSame($latestLogin->id, $latestLogins->first()->id); + + $latestLogins = $user->latest_login()->whereKey($previousLogin->getKey())->get(); + $this->assertCount(0, $latestLogins); + } + + public function testCount(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->logins()->create(); + $user->intermediates->first()->logins()->create(); + + $this->assertSame(1, $user->latest_login()->count()); + } + + public function testAggregate(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $firstLogin = $user->intermediates->first()->logins()->create(); + $user->intermediates->last()->logins()->create(); + + $user = HasOneThroughOfManyTestUser::first(); + $this->assertSame($firstLogin->id, $user->first_login->id); + } + + public function testJoinConstraints(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->states()->create([ + 'type' => 'foo', + 'state' => 'draft', + ]); + $currentForState = $user->intermediates->first()->states()->create([ + 'type' => 'foo', + 'state' => 'active', + ]); + $user->intermediates->first()->states()->create([ + 'type' => 'bar', + 'state' => 'baz', + ]); + + $user = HasOneThroughOfManyTestUser::first(); + $this->assertSame($currentForState->id, $user->foo_state->id); + } + + public function testMultipleAggregates(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user->intermediates->last()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + $price = $user->intermediates->first()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + + $user = HasOneThroughOfManyTestUser::first(); + $this->assertSame($price->id, $user->price->id); + } + + public function testEagerLoadingWithMultipleAggregates(): void + { + $user1 = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + $user2 = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + + $user1->intermediates->last()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + $user1Price = $user1->intermediates->first()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + $user1->intermediates->first()->prices()->create([ + 'published_at' => '2021-04-01 00:00:00', + ]); + + $user2Price = $user2->intermediates->last()->prices()->create([ + 'published_at' => '2021-05-01 00:00:00', + ]); + $user2->intermediates->first()->prices()->create([ + 'published_at' => '2021-04-01 00:00:00', + ]); + + $users = HasOneThroughOfManyTestUser::with('price')->get(); + + $this->assertNotNull($users[0]->price); + $this->assertSame($user1Price->id, $users[0]->price->id); + + $this->assertNotNull($users[1]->price); + $this->assertSame($user2Price->id, $users[1]->price->id); + } + + public function testWithExists(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(1)->create(); + + $user = HasOneThroughOfManyTestUser::withExists('latest_login')->first(); + $this->assertFalse($user->latest_login_exists); + + $user->intermediates->first()->logins()->create(); + $user = HasOneThroughOfManyTestUser::withExists('latest_login')->first(); + $this->assertTrue($user->latest_login_exists); + } + + public function testWithExistsWithConstraintsInJoinSubSelect(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(1)->create(); + $user = HasOneThroughOfManyTestUser::withExists('foo_state')->first(); + + $this->assertFalse($user->foo_state_exists); + + $user->intermediates->first()->states()->create([ + 'type' => 'foo', + 'state' => 'bar', + ]); + $user = HasOneThroughOfManyTestUser::withExists('foo_state')->first(); + $this->assertTrue($user->foo_state_exists); + } + + public function testWithSoftDeletes(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(1)->create(); + $user->intermediates->first()->logins()->create(); + $user->latest_login_with_soft_deletes; + $this->assertNotNull($user->latest_login_with_soft_deletes); + } + + public function testWithConstraintNotInAggregate(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + + $previousFoo = $user->intermediates->last()->states()->create([ + 'type' => 'foo', + 'state' => 'bar', + 'updated_at' => '2020-01-01 00:00:00', + ]); + $newFoo = $user->intermediates->first()->states()->create([ + 'type' => 'foo', + 'state' => 'active', + 'updated_at' => '2021-01-01 12:00:00', + ]); + $newBar = $user->intermediates->first()->states()->create([ + 'type' => 'bar', + 'state' => 'active', + 'updated_at' => '2021-01-01 12:00:00', + ]); + + $this->assertSame($newFoo->id, $user->last_updated_foo_state->id); + } + + public function testItGetsCorrectResultUsingAtLeastTwoAggregatesDistinctFromId(): void + { + $user = HasOneThroughOfManyTestUser::factory()->hasIntermediates(2)->create(); + + $expectedState = $user->intermediates->last()->states()->create([ + 'state' => 'state', + 'type' => 'type', + 'created_at' => '2023-01-01', + 'updated_at' => '2023-01-03', + ]); + + $user->intermediates->first()->states()->create([ + 'state' => 'state', + 'type' => 'type', + 'created_at' => '2023-01-01', + 'updated_at' => '2023-01-02', + ]); + + $this->assertSame($user->latest_updated_latest_created_state->id, $expectedState->id); + } + + protected function connection(): Connection + { + return Eloquent::getConnectionResolver()->connection(); + } + + protected function schema(): Builder + { + return $this->connection()->getSchemaBuilder(); + } +} + +class HasOneThroughOfManyTestUser extends Eloquent +{ + use HasFactory; + protected $table = 'users'; + protected $guarded = []; + public $timestamps = false; + protected static string $factory = HasOneThroughOfManyTestUserFactory::class; + + public function intermediates(): HasMany + { + return $this->hasMany(HasOneThroughOfManyTestIntermediate::class, 'user_id'); + } + + public function logins(): HasManyThrough + { + return $this->through('intermediates')->has('logins'); + } + + public function latest_login(): HasOneThrough + { + return $this->hasOneThrough( + HasOneThroughOfManyTestLogin::class, + HasOneThroughOfManyTestIntermediate::class, + 'user_id', + 'intermediate_id' + )->ofMany(); + } + + public function latest_login_with_soft_deletes(): HasOneThrough + { + return $this->hasOneThrough( + HasOneThroughOfManyTestLoginWithSoftDeletes::class, + HasOneThroughOfManyTestIntermediate::class, + 'user_id', + 'intermediate_id', + )->ofMany(); + } + + public function latest_login_with_shortcut(): HasOneThrough + { + return $this->logins()->one()->latestOfMany(); + } + + public function latest_login_with_invalid_aggregate(): HasOneThrough + { + return $this->logins()->one()->ofMany('id', 'count'); + } + + public function latest_login_without_global_scope(): HasOneThrough + { + return $this->logins()->one()->withoutGlobalScopes()->latestOfMany(); + } + + public function first_login(): HasOneThrough + { + return $this->logins()->one()->ofMany('id', 'min'); + } + + public function latest_login_with_foo_state(): HasOneThrough + { + return $this->logins()->one()->ofMany( + ['id' => 'max'], + function ($query) { + $query->join('states', 'states.intermediate_id', 'logins.intermediate_id') + ->where('states.type', 'foo'); + } + ); + } + + public function states(): HasManyThrough + { + return $this->through($this->intermediates()) + ->has(fn ($intermediate) => $intermediate->states()); + } + + public function foo_state(): HasOneThrough + { + return $this->states()->one()->ofMany( + ['id' => 'max'], + function ($q) { + $q->where('type', 'foo'); + } + ); + } + + public function last_updated_foo_state(): HasOneThrough + { + return $this->states()->one()->ofMany([ + 'updated_at' => 'max', + 'id' => 'max', + ], function ($q) { + $q->where('type', 'foo'); + }); + } + + public function prices(): HasManyThrough + { + return $this->throughIntermediates()->hasPrices(); + } + + public function price(): HasOneThrough + { + return $this->prices()->one()->ofMany([ + 'published_at' => 'max', + 'id' => 'max', + ], function ($q) { + $q->where('published_at', '<', now()); + }); + } + + public function price_without_key_in_aggregates(): HasOneThrough + { + return $this->prices()->one()->ofMany(['published_at' => 'MAX']); + } + + public function price_with_shortcut(): HasOneThrough + { + return $this->prices()->one()->latestOfMany(['published_at', 'id']); + } + + public function price_without_global_scope(): HasOneThrough + { + return $this->prices()->one()->withoutGlobalScopes()->ofMany([ + 'published_at' => 'max', + 'id' => 'max', + ], function ($q) { + $q->where('published_at', '<', now()); + }); + } + + public function latest_updated_latest_created_state(): HasOneThrough + { + return $this->states()->one()->ofMany([ + 'updated_at' => 'max', + 'created_at' => 'max', + ]); + } +} + +class HasOneThroughOfManyTestIntermediate extends Eloquent +{ + use HasFactory; + protected $table = 'intermediates'; + protected $guarded = []; + public $timestamps = false; + protected static string $factory = HasOneThroughOfManyTestIntermediateFactory::class; + + public function logins(): HasMany + { + return $this->hasMany(HasOneThroughOfManyTestLogin::class, 'intermediate_id'); + } + + public function states(): HasMany + { + return $this->hasMany(HasOneThroughOfManyTestState::class, 'intermediate_id'); + } + + public function prices(): HasMany + { + return $this->hasMany(HasOneThroughOfManyTestPrice::class, 'intermediate_id'); + } +} + +class HasOneThroughOfManyTestModel extends Eloquent +{ + public function logins(): HasOneThrough + { + return $this->hasOneThrough( + HasOneThroughOfManyTestLogin::class, + HasOneThroughOfManyTestIntermediate::class, + 'user_id', + 'intermediate_id', + )->ofMany(); + } +} + +class HasOneThroughOfManyTestLogin extends Eloquent +{ + protected $table = 'logins'; + protected $guarded = []; + public $timestamps = false; +} + +class HasOneThroughOfManyTestLoginWithSoftDeletes extends Eloquent +{ + use SoftDeletes; + + protected $table = 'logins'; + protected $guarded = []; + public $timestamps = false; +} + +class HasOneThroughOfManyTestState extends Eloquent +{ + protected $table = 'states'; + protected $guarded = []; + public $timestamps = true; + protected $fillable = ['type', 'state', 'updated_at']; +} + +class HasOneThroughOfManyTestPrice extends Eloquent +{ + protected $table = 'prices'; + protected $guarded = []; + public $timestamps = false; + protected $fillable = ['published_at']; + protected $casts = ['published_at' => 'datetime']; +} + +class HasOneThroughOfManyTestUserFactory extends Factory +{ + protected $model = HasOneThroughOfManyTestUser::class; + + public function definition(): array + { + return []; + } +} + +class HasOneThroughOfManyTestIntermediateFactory extends Factory +{ + protected $model = HasOneThroughOfManyTestIntermediate::class; + + public function definition(): array + { + return ['user_id' => HasOneThroughOfManyTestUser::factory()]; + } +} diff --git a/tests/Database/DatabaseEloquentMorphOneOfManyTest.php b/tests/Database/DatabaseEloquentMorphOneOfManyTest.php index f565819dd7cf..9f04afe3ab86 100644 --- a/tests/Database/DatabaseEloquentMorphOneOfManyTest.php +++ b/tests/Database/DatabaseEloquentMorphOneOfManyTest.php @@ -58,7 +58,7 @@ public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery() $product = MorphOneOfManyTestProduct::create(); $relation = $product->current_state(); $relation->addEagerConstraints([$product]); - $this->assertSame('select MAX("states"."id") as "id_aggregate", "states"."stateful_id", "states"."stateful_type" from "states" where "states"."stateful_type" = ? and "states"."stateful_id" = ? and "states"."stateful_id" is not null and "states"."stateful_id" in (1) and "states"."stateful_type" = ? group by "states"."stateful_id", "states"."stateful_type"', $relation->getOneOfManySubQuery()->toSql()); + $this->assertSame('select MAX("states"."id") as "id_aggregate", "states"."stateful_id", "states"."stateful_type" from "states" where "states"."stateful_id" in (1) and "states"."stateful_type" = ? group by "states"."stateful_id", "states"."stateful_type"', $relation->getOneOfManySubQuery()->toSql()); } public function testReceivingModel() From 151982ccf29ababb289ba182b8968144dc5eb370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sam=20Carr=C3=A9?= <29132017+Sammyjo20@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:56:24 +0000 Subject: [PATCH 155/455] [12.x] | Hotfix - Add function_exists check to ddBody in TestResponse (#54937) --- 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 94d2239e0aed..e6d75c13e37f 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -1655,7 +1655,7 @@ public function ddBody($key = null) { $content = $this->content(); - if (json_validate($content)) { + if (function_exists('json_validate') && json_validate($content)) { $this->ddJson($key); } From b5695bace55820dcdf21636aee2b999aed0fc593 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:33:27 +0330 Subject: [PATCH 156/455] [12.x] Refactor: Remove unnecessary variables in Str class methods (#54963) * Replace unnecessary null coalescing assignment operator (??=) with null coalescing operator (??) in Str::wrap method, as the variable is not used afterward. * remove unused exception variable in isUuid method try-catch block --- src/Illuminate/Support/Str.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 622fcba0d018..51e50caa875b 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -454,7 +454,7 @@ public static function finish($value, $cap) */ public static function wrap($value, $before, $after = null) { - return $before.$value.($after ??= $before); + return $before.$value.($after ?? $before); } /** @@ -623,7 +623,7 @@ public static function isUuid($value, $version = null) try { $factoryUuid = $factory->fromString($value); - } catch (InvalidUuidStringException $ex) { + } catch (InvalidUuidStringException) { return false; } From 80af327ec6df8fdb7ebb731144304084200b4959 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:39:53 +0330 Subject: [PATCH 157/455] Add Tests for Str::pluralPascal Method (#54957) * test: Add basic pluralPascal functionality tests Test the method's ability to convert singular Pascal case strings to plural form. * test: Add pluralPascal tests with various count parameters Test pluralPascal behavior with different count values (0, 1, 2), arrays and Countable objects to ensure comprehensive coverage. --- tests/Support/SupportStrTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 0c46efa5f828..b93bb509cf13 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -1790,6 +1790,30 @@ public function testReplaceMatches() $this->assertSame('foo baZ baz bar', $result); } + + public function testPluralPascal(): void + { + // Test basic functionality with default count + $this->assertSame('UserGroups', Str::pluralPascal('UserGroup')); + $this->assertSame('ProductCategories', Str::pluralPascal('ProductCategory')); + + // Test with different count values and array + $this->assertSame('UserGroups', Str::pluralPascal('UserGroup', 0)); // plural + $this->assertSame('UserGroup', Str::pluralPascal('UserGroup', 1)); // singular + $this->assertSame('UserGroups', Str::pluralPascal('UserGroup', 2)); // plural + $this->assertSame('UserGroups', Str::pluralPascal('UserGroup', [])); // plural (empty array count is 0) + + // Test with Countable + $countable = new class implements \Countable + { + public function count(): int + { + return 3; + } + }; + + $this->assertSame('UserGroups', Str::pluralPascal('UserGroup', $countable)); + } } class StringableObjectStub From a0f7faef515e68ccc53f1dc1e5212b3b209edab2 Mon Sep 17 00:00:00 2001 From: Sunao Yada <97194355+naopusyu@users.noreply.github.com> Date: Tue, 11 Mar 2025 02:21:41 +0900 Subject: [PATCH 158/455] [12.x] Fix visibility of setUp and tearDown in tests (#54950) * Change visibility from public to protected * remove tearDown method --- .../DatabaseConcernsPreventsCircularRecursionTest.php | 2 +- .../DatabaseEloquentBelongsToManyCreateOrFirstTest.php | 2 +- tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php | 2 +- tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php | 2 +- .../DatabaseEloquentHasManyThroughCreateOrFirstTest.php | 2 +- tests/Foundation/Configuration/ExceptionsTest.php | 5 ----- tests/Foundation/Configuration/MiddlewareTest.php | 2 +- tests/Integration/Queue/DynamoBatchTest.php | 2 +- tests/Queue/DatabaseFailedJobProviderTest.php | 2 +- 9 files changed, 8 insertions(+), 13 deletions(-) diff --git a/tests/Database/DatabaseConcernsPreventsCircularRecursionTest.php b/tests/Database/DatabaseConcernsPreventsCircularRecursionTest.php index a35a6cd19447..66ca4b0bb4b3 100644 --- a/tests/Database/DatabaseConcernsPreventsCircularRecursionTest.php +++ b/tests/Database/DatabaseConcernsPreventsCircularRecursionTest.php @@ -8,7 +8,7 @@ class DatabaseConcernsPreventsCircularRecursionTest extends TestCase { - public function setUp(): void + protected function setUp(): void { parent::setUp(); diff --git a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php index 8fb7dab36607..fc9597378357 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php @@ -19,7 +19,7 @@ class DatabaseEloquentBelongsToManyCreateOrFirstTest extends TestCase { - public function setUp(): void + protected function setUp(): void { Carbon::setTestNow('2023-01-01 00:00:00'); } diff --git a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php index 63cffe311f53..87fc0c43e24f 100755 --- a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php @@ -15,7 +15,7 @@ class DatabaseEloquentBuilderCreateOrFirstTest extends TestCase { - public function setUp(): void + protected function setUp(): void { Carbon::setTestNow('2023-01-01 00:00:00'); } diff --git a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php index 5a3b9e5c1c06..b7a055a66958 100755 --- a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php @@ -16,7 +16,7 @@ class DatabaseEloquentHasManyCreateOrFirstTest extends TestCase { - public function setUp(): void + protected function setUp(): void { Carbon::setTestNow('2023-01-01 00:00:00'); } diff --git a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php index b499100ef406..63c69a6175bb 100644 --- a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php @@ -18,7 +18,7 @@ class DatabaseEloquentHasManyThroughCreateOrFirstTest extends TestCase { - public function setUp(): void + protected function setUp(): void { Carbon::setTestNow('2023-01-01 00:00:00'); } diff --git a/tests/Foundation/Configuration/ExceptionsTest.php b/tests/Foundation/Configuration/ExceptionsTest.php index 704ca02b8a97..fc868e6c5f4c 100644 --- a/tests/Foundation/Configuration/ExceptionsTest.php +++ b/tests/Foundation/Configuration/ExceptionsTest.php @@ -13,11 +13,6 @@ class ExceptionsTest extends TestCase { - public function tearDown(): void - { - parent::tearDown(); - } - public function testStopIgnoring() { $container = new Container; diff --git a/tests/Foundation/Configuration/MiddlewareTest.php b/tests/Foundation/Configuration/MiddlewareTest.php index 3971b895cac1..d54169a6c9dc 100644 --- a/tests/Foundation/Configuration/MiddlewareTest.php +++ b/tests/Foundation/Configuration/MiddlewareTest.php @@ -21,7 +21,7 @@ class MiddlewareTest extends TestCase { - public function tearDown(): void + protected function tearDown(): void { parent::tearDown(); diff --git a/tests/Integration/Queue/DynamoBatchTest.php b/tests/Integration/Queue/DynamoBatchTest.php index a395fc414af0..5fb67dded164 100644 --- a/tests/Integration/Queue/DynamoBatchTest.php +++ b/tests/Integration/Queue/DynamoBatchTest.php @@ -19,7 +19,7 @@ #[RequiresEnv('DYNAMODB_ENDPOINT')] class DynamoBatchTest extends TestCase { - public function setUp(): void + protected function setUp(): void { $this->afterApplicationCreated(function () { BatchRunRecorder::reset(); diff --git a/tests/Queue/DatabaseFailedJobProviderTest.php b/tests/Queue/DatabaseFailedJobProviderTest.php index 31d1714e2f65..89e38e499c4d 100644 --- a/tests/Queue/DatabaseFailedJobProviderTest.php +++ b/tests/Queue/DatabaseFailedJobProviderTest.php @@ -18,7 +18,7 @@ class DatabaseFailedJobProviderTest extends TestCase protected $provider; - public function setUp(): void + protected function setUp(): void { parent::setUp(); $this->createDatabaseWithFailedJobTable() From 63919de4f9197e2adb2abac9b730f1f1a11afd44 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 11 Mar 2025 01:23:18 +0800 Subject: [PATCH 159/455] [12.x] Test Improvements (#54944) Remove `getEnvironmentSetup()` usage as it has been marked as deprecated. Signed-off-by: Mior Muhammad Zaki --- tests/Integration/Filesystem/ServeFileTest.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/Integration/Filesystem/ServeFileTest.php b/tests/Integration/Filesystem/ServeFileTest.php index c5219761ab10..ccc99350e60f 100644 --- a/tests/Integration/Filesystem/ServeFileTest.php +++ b/tests/Integration/Filesystem/ServeFileTest.php @@ -3,8 +3,10 @@ namespace Illuminate\Tests\Integration\Filesystem; use Illuminate\Support\Facades\Storage; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\TestCase; +#[WithConfig('filesystems.disks.local.serve', true)] class ServeFileTest extends TestCase { protected function setUp(): void @@ -48,11 +50,4 @@ public function testItWill403OnWrongSignature() $response->assertForbidden(); } - - protected function getEnvironmentSetup($app) - { - tap($app['config'], function ($config) { - $config->set('filesystems.disks.local.serve', true); - }); - } } From 7ddf5aeb98922e3a71fb17989477107d791a411f Mon Sep 17 00:00:00 2001 From: parth gohil Date: Mon, 10 Mar 2025 23:00:01 +0530 Subject: [PATCH 160/455] Fix missing return in `assertOnlyInvalid` (#54941) --- src/Illuminate/Testing/TestResponse.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index e6d75c13e37f..a792bdd298cf 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -1405,6 +1405,8 @@ public function assertOnlyInvalid($errors = null, $errorBag = 'default', $respon count($unexpectedErrorKeys) === 0, 'Response has unexpected validation errors: '.collect($unexpectedErrorKeys)->keys()->map(fn ($key) => "'{$key}'")->join(', ') ); + + return $this; } /** From e6753fc3836bb5fdddd1ee95835d8065bd7c5b16 Mon Sep 17 00:00:00 2001 From: Joe Tito Date: Mon, 10 Mar 2025 13:32:22 -0400 Subject: [PATCH 161/455] Handle case when migrate:install command is called and table exists (#54938) * Handle case when migrate:install command is called when migrations table already exists * Fixing tests * Formatting * Delete package-lock.json --------- Co-authored-by: Joe Tito Co-authored-by: Mior Muhammad Zaki --- .../Database/Console/Migrations/InstallCommand.php | 4 +++- .../Database/DatabaseMigrationInstallCommandTest.php | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Console/Migrations/InstallCommand.php b/src/Illuminate/Database/Console/Migrations/InstallCommand.php index 144ff512671b..607553010a61 100755 --- a/src/Illuminate/Database/Console/Migrations/InstallCommand.php +++ b/src/Illuminate/Database/Console/Migrations/InstallCommand.php @@ -53,7 +53,9 @@ public function handle() { $this->repository->setSource($this->input->getOption('database')); - $this->repository->createRepository(); + if (! $this->repository->repositoryExists()) { + $this->repository->createRepository(); + } $this->components->info('Migration table created successfully.'); } diff --git a/tests/Database/DatabaseMigrationInstallCommandTest.php b/tests/Database/DatabaseMigrationInstallCommandTest.php index 165b0c39c545..37e180dc12d5 100755 --- a/tests/Database/DatabaseMigrationInstallCommandTest.php +++ b/tests/Database/DatabaseMigrationInstallCommandTest.php @@ -23,6 +23,17 @@ public function testFireCallsRepositoryToInstall() $command->setLaravel(new Application); $repo->shouldReceive('setSource')->once()->with('foo'); $repo->shouldReceive('createRepository')->once(); + $repo->shouldReceive('repositoryExists')->once()->andReturn(false); + + $this->runCommand($command, ['--database' => 'foo']); + } + + public function testFireCallsRepositoryToInstallExists() + { + $command = new InstallCommand($repo = m::mock(MigrationRepositoryInterface::class)); + $command->setLaravel(new Application); + $repo->shouldReceive('setSource')->once()->with('foo'); + $repo->shouldReceive('repositoryExists')->once()->andReturn(true); $this->runCommand($command, ['--database' => 'foo']); } From c1cc6cc42da1731257d1b56a2a29a949773ee2fd Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 11 Mar 2025 16:51:12 +0800 Subject: [PATCH 162/455] Update docblock --- src/Illuminate/Validation/Validator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index efe08f28cf26..21cb2e727381 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -421,8 +421,8 @@ protected function replacePlaceholderInString(string $value) /** * Replace each field parameter dot placeholder with dot. * - * @param string $value - * @return string + * @param array $parameters + * @return array */ protected function replaceDotPlaceholderInParameters(array $parameters) { From f1778fb099d347f7cfc78d299b97552704f3ac58 Mon Sep 17 00:00:00 2001 From: Lorenzo <7686933+lbovit@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:13:54 +0100 Subject: [PATCH 163/455] Fix callOnce in Seeder so it handles arrays properly (#54985) --- src/Illuminate/Database/Seeder.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Seeder.php b/src/Illuminate/Database/Seeder.php index bfb48aedf3b0..08e57b2d7834 100755 --- a/src/Illuminate/Database/Seeder.php +++ b/src/Illuminate/Database/Seeder.php @@ -110,11 +110,15 @@ public function callSilent($class, array $parameters = []) */ public function callOnce($class, $silent = false, array $parameters = []) { - if (in_array($class, static::$called)) { - return; - } + $classes = Arr::wrap($class); + + foreach ($classes as $class) { + if (in_array($class, static::$called)) { + continue; + } - $this->call($class, $silent, $parameters); + $this->call($class, $silent, $parameters); + } } /** From 036cfc4ea8c000d31982ef56056302d54d890e8e Mon Sep 17 00:00:00 2001 From: Lucas Novoa Date: Wed, 12 Mar 2025 09:15:02 -0500 Subject: [PATCH 164/455] Change "exceptoin" spelling mistake to "exception" (#54979) --- src/Illuminate/Queue/InteractsWithQueue.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/InteractsWithQueue.php b/src/Illuminate/Queue/InteractsWithQueue.php index 4caea95c9c81..850c7c1c54bc 100644 --- a/src/Illuminate/Queue/InteractsWithQueue.php +++ b/src/Illuminate/Queue/InteractsWithQueue.php @@ -185,7 +185,7 @@ public function assertFailedWith($exception) PHPUnit::assertEquals( $exception->getMessage(), $this->job->failedWith->getMessage(), - 'Expected exceptoin message ['.$exception->getMessage().'] but job failed with exception message ['.$this->job->failedWith->getMessage().'].'); + 'Expected exception message ['.$exception->getMessage().'] but job failed with exception message ['.$this->job->failedWith->getMessage().'].'); } return $this; From 67bf0cdd50191a4e9200f5ab4a7edf8db52ec41a Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Wed, 12 Mar 2025 17:45:19 +0330 Subject: [PATCH 165/455] test: Add comprehensive test for LazyCollection::after method (#54978) This commit adds a test for the LazyCollection after() method covering three key scenarios: - Finding the next item with non-strict comparison - Finding the next item with strict comparison - Finding the next item using a callback function --- tests/Support/SupportLazyCollectionTest.php | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index 5865c09e888b..e422a79e9f91 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -286,4 +286,30 @@ public function testUniqueDoubleEnumeration() $this->assertSame([1, 2], $data->all()); } + + public function testAfter() + { + $data = new LazyCollection([1, '2', 3, 4]); + + // Test finding item after value with non-strict comparison + $result = $data->after(1); + $this->assertSame('2', $result); + + // Test with strict comparison + $result = $data->after('2', true); + $this->assertSame(3, $result); + + $users = new LazyCollection([ + ['name' => 'Taylor', 'age' => 35], + ['name' => 'Jeffrey', 'age' => 45], + ['name' => 'Mohamed', 'age' => 35], + ]); + + // Test finding item after the one that matches a condition + $result = $users->after(function ($user) { + return $user['name'] === 'Jeffrey'; + }); + + $this->assertSame(['name' => 'Mohamed', 'age' => 35], $result); + } } From 9b060d83124be62531de663a423c9353a15bd8e1 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 12 Mar 2025 15:17:36 +0100 Subject: [PATCH 166/455] [12.x] Add `increment` and `decrement` methods to `Context` (#54976) --- src/Illuminate/Log/Context/Repository.php | 29 ++++++++++++++++++++ src/Illuminate/Support/Facades/Context.php | 2 ++ tests/Log/ContextTest.php | 32 ++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/Illuminate/Log/Context/Repository.php b/src/Illuminate/Log/Context/Repository.php index 1582d375e681..01e861925020 100644 --- a/src/Illuminate/Log/Context/Repository.php +++ b/src/Illuminate/Log/Context/Repository.php @@ -369,6 +369,35 @@ public function popHidden($key) return array_pop($this->hidden[$key]); } + /** + * Increment a context counter. + * + * @param string $key + * @param int $amount + * @return $this + */ + public function increment(string $key, int $amount = 1) + { + $this->add( + $key, + (int) $this->get($key, 0) + $amount, + ); + + return $this; + } + + /** + * Decrement a context counter. + * + * @param string $key + * @param int $amount + * @return $this + */ + public function decrement(string $key, int $amount = 1) + { + return $this->increment($key, $amount * -1); + } + /** * Determine if the given value is in the given stack. * diff --git a/src/Illuminate/Support/Facades/Context.php b/src/Illuminate/Support/Facades/Context.php index e1bc10a1bb2e..2c9b197f95ac 100644 --- a/src/Illuminate/Support/Facades/Context.php +++ b/src/Illuminate/Support/Facades/Context.php @@ -25,6 +25,8 @@ * @method static mixed pop(string $key) * @method static \Illuminate\Log\Context\Repository pushHidden(string $key, mixed ...$values) * @method static mixed popHidden(string $key) + * @method static mixed increment(string $key, int $amount) + * @method static mixed decrement(string $key, int $amount) * @method static bool stackContains(string $key, mixed $value, bool $strict = false) * @method static bool hiddenStackContains(string $key, mixed $value, bool $strict = false) * @method static mixed scope(callable $callback, array $data = [], array $hidden = []) diff --git a/tests/Log/ContextTest.php b/tests/Log/ContextTest.php index 657b2fa16fa1..dfb76df9194b 100644 --- a/tests/Log/ContextTest.php +++ b/tests/Log/ContextTest.php @@ -602,6 +602,38 @@ public function test_can_rebind_to_separate_class() file_put_contents($path, ''); } + + public function test_it_increments_a_counter() + { + Context::increment('foo'); + $this->assertSame(1, Context::get('foo')); + + Context::increment('foo'); + $this->assertSame(2, Context::get('foo')); + } + + public function test_it_custom_increments_a_counter() + { + Context::increment('foo', 2); + $this->assertSame(2, Context::get('foo')); + + Context::increment('foo', 3); + $this->assertSame(5, Context::get('foo')); + } + + public function test_it_decrements_a_counter() + { + Context::increment('foo'); + Context::decrement('foo'); + $this->assertSame(0, Context::get('foo')); + } + + public function test_it_custom_decrements_a_counter() + { + Context::increment('foo', 2); + Context::decrement('foo', 2); + $this->assertSame(0, Context::get('foo')); + } } enum Suit From 11f92d41d3770caeed241e2e03052a2d4ce5cdb4 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Wed, 12 Mar 2025 17:47:56 +0330 Subject: [PATCH 167/455] Add a null value to ensure that ExcludeIf properly rejects it as an invalid condition (#54973) --- tests/Validation/ValidationExcludeIfTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Validation/ValidationExcludeIfTest.php b/tests/Validation/ValidationExcludeIfTest.php index 5467f66c55d2..a616f642cc13 100644 --- a/tests/Validation/ValidationExcludeIfTest.php +++ b/tests/Validation/ValidationExcludeIfTest.php @@ -42,7 +42,7 @@ public function testItValidatesCallableAndBooleanAreAcceptableArguments() new ExcludeIf(true); new ExcludeIf(fn () => true); - foreach ([1, 1.1, 'phpinfo', new stdClass] as $condition) { + foreach ([1, 1.1, 'phpinfo', new stdClass, null] as $condition) { try { new ExcludeIf($condition); $this->fail('The ExcludeIf constructor must not accept '.gettype($condition)); From da25de486679b503519578551c824ce61298ce61 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:18:24 +0000 Subject: [PATCH 168/455] Update facade docblocks --- src/Illuminate/Support/Facades/Context.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Facades/Context.php b/src/Illuminate/Support/Facades/Context.php index 2c9b197f95ac..6b894fad39b7 100644 --- a/src/Illuminate/Support/Facades/Context.php +++ b/src/Illuminate/Support/Facades/Context.php @@ -25,8 +25,8 @@ * @method static mixed pop(string $key) * @method static \Illuminate\Log\Context\Repository pushHidden(string $key, mixed ...$values) * @method static mixed popHidden(string $key) - * @method static mixed increment(string $key, int $amount) - * @method static mixed decrement(string $key, int $amount) + * @method static \Illuminate\Log\Context\Repository increment(string $key, int $amount = 1) + * @method static \Illuminate\Log\Context\Repository decrement(string $key, int $amount = 1) * @method static bool stackContains(string $key, mixed $value, bool $strict = false) * @method static bool hiddenStackContains(string $key, mixed $value, bool $strict = false) * @method static mixed scope(callable $callback, array $data = [], array $hidden = []) From 33f3dc8677c1236eb0133a88da2da3c878007bf2 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 12 Mar 2025 09:20:46 -0500 Subject: [PATCH 169/455] apply Pint rule "no_spaces_around_offset" (#54970) --- tests/Database/DatabaseQueryBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 1773aff32783..7508d9adaa42 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -6150,7 +6150,7 @@ public function testCursorPaginateWithUnionMultipleWheresMultipleOrders() '(select "id", "start_time" as "created_at", "type" from "videos" where "extra" = ? and ("id" > ? or ("id" = ? and ("start_time" < ? or ("start_time" = ? and ("type" > ?)))))) union (select "id", "created_at", "type" from "news" where "extra" = ? and ("id" > ? or ("id" = ? and ("start_time" < ? or ("start_time" = ? and ("type" > ?)))))) union (select "id", "created_at", "type" from "podcasts" where "extra" = ? and ("id" > ? or ("id" = ? and ("start_time" < ? or ("start_time" = ? and ("type" > ?)))))) order by "id" asc, "created_at" desc, "type" asc limit 17', $builder->toSql()); $this->assertEquals(['first', 1, 1, $ts, $ts, 'news'], $builder->bindings['where']); - $this->assertEquals(['second', 1, 1, $ts, $ts, 'news', 'third', 1, 1, $ts, $ts, 'news'], $builder->bindings ['union']); + $this->assertEquals(['second', 1, 1, $ts, $ts, 'news', 'third', 1, 1, $ts, $ts, 'news'], $builder->bindings['union']); return $results; }); From 0dd71efd2df4b18d1ea456c1e3d7f2da74b34497 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 12 Mar 2025 09:21:02 -0500 Subject: [PATCH 170/455] apply Pint rule "single_line_comment_style" (#54969) `FrequencyTest` is the outlier here, as it retains the `/**` syntax so the docbloc is picked up. This maintains consistency with other similar uses in the framework, such as in https://github.com/laravel/framework/blob/12.x/src/Illuminate/Collections/LazyCollection.php#L233 https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/rules/comment/single_line_comment_style.rst --- tests/Broadcasting/BroadcasterTest.php | 4 +- tests/Cache/CacheRepositoryTest.php | 4 +- tests/Console/Scheduling/FrequencyTest.php | 4 +- tests/Container/ContainerCallTest.php | 4 +- tests/Container/ContextualBindingTest.php | 8 +- ...baseEloquentSoftDeletesIntegrationTest.php | 4 +- tests/Database/DatabaseQueryBuilderTest.php | 72 ++++----------- tests/Pagination/UrlWindowTest.php | 4 +- tests/Routing/RoutingRouteTest.php | 60 +++--------- tests/Routing/RoutingUrlGeneratorTest.php | 92 +++++-------------- 10 files changed, 64 insertions(+), 192 deletions(-) diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 57312935ccdb..0e49c4b9e231 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -61,9 +61,7 @@ public function testExtractingParametersWhileCheckingForUserAccess() $parameters = $this->broadcaster->extractAuthParameters('asd', 'asd', $callback); $this->assertEquals([], $parameters); - /* - * Test Explicit Binding... - */ + // Test Explicit Binding... $container = new Container; Container::setInstance($container); $binder = m::mock(BindingRegistrar::class); diff --git a/tests/Cache/CacheRepositoryTest.php b/tests/Cache/CacheRepositoryTest.php index 5c4b77ce070f..5097a2797795 100755 --- a/tests/Cache/CacheRepositoryTest.php +++ b/tests/Cache/CacheRepositoryTest.php @@ -128,9 +128,7 @@ public function testRememberMethodCallsPutAndReturnsDefault() }); $this->assertSame('qux', $result); - /* - * Use a callable... - */ + // Use a callable... $repo = $this->getRepository(); $repo->getStore()->shouldReceive('get')->once()->andReturn(null); $repo->getStore()->shouldReceive('put')->once()->with('foo', 'bar', 10); diff --git a/tests/Console/Scheduling/FrequencyTest.php b/tests/Console/Scheduling/FrequencyTest.php index 17cc6f398814..87f61d62cd08 100644 --- a/tests/Console/Scheduling/FrequencyTest.php +++ b/tests/Console/Scheduling/FrequencyTest.php @@ -10,9 +10,7 @@ class FrequencyTest extends TestCase { - /* - * @var \Illuminate\Console\Scheduling\Event - */ + /** @var \Illuminate\Console\Scheduling\Event */ protected $event; protected function setUp(): void diff --git a/tests/Container/ContainerCallTest.php b/tests/Container/ContainerCallTest.php index 694ccd511fcb..cd9d207a89c1 100644 --- a/tests/Container/ContainerCallTest.php +++ b/tests/Container/ContainerCallTest.php @@ -146,9 +146,7 @@ public function testCallWithDependencies() $this->assertInstanceOf(stdClass::class, $result[0]); $this->assertSame($stub, $result[1]); - /* - * Wrap a function... - */ + // Wrap a function... $result = $container->wrap(function (stdClass $foo, $bar = []) { return func_get_args(); }, ['bar' => 'taylor']); diff --git a/tests/Container/ContextualBindingTest.php b/tests/Container/ContextualBindingTest.php index 1dae46248d7e..e1db2ee1ac08 100644 --- a/tests/Container/ContextualBindingTest.php +++ b/tests/Container/ContextualBindingTest.php @@ -23,9 +23,7 @@ public function testContainerCanInjectDifferentImplementationsDependingOnContext $this->assertInstanceOf(ContainerContextImplementationStub::class, $one->impl); $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $two->impl); - /* - * Test With Closures - */ + // Test With Closures $container = new Container; $container->bind(IContainerContextContractStub::class, ContainerContextImplementationStub::class); @@ -41,9 +39,7 @@ public function testContainerCanInjectDifferentImplementationsDependingOnContext $this->assertInstanceOf(ContainerContextImplementationStub::class, $one->impl); $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $two->impl); - /* - * Test nesting to make the same 'abstract' in different context - */ + // Test nesting to make the same 'abstract' in different context $container = new Container; $container->bind(IContainerContextContractStub::class, ContainerContextImplementationStub::class); diff --git a/tests/Database/DatabaseEloquentSoftDeletesIntegrationTest.php b/tests/Database/DatabaseEloquentSoftDeletesIntegrationTest.php index c4a59964bce0..195e2dfd7e17 100644 --- a/tests/Database/DatabaseEloquentSoftDeletesIntegrationTest.php +++ b/tests/Database/DatabaseEloquentSoftDeletesIntegrationTest.php @@ -957,9 +957,7 @@ public function testMorphToNonSoftDeletingModel() public function testSelfReferencingRelationshipWithSoftDeletes() { - /* - * https://github.com/laravel/framework/issues/42075 - */ + // https://github.com/laravel/framework/issues/42075 [$taylor, $abigail] = $this->createUsers(); $this->assertCount(1, $abigail->self_referencing); diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 7508d9adaa42..95142e0b698c 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2475,9 +2475,7 @@ public function testOrWheresHaveConsistentResults() public function testWhereWithArrayConditions() { - /* - * where(key, value) - */ + // where(key, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', 2]]); @@ -2509,9 +2507,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - /* - * where(key, <, value) - */ + // where(key, <, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]]); @@ -2528,9 +2524,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - /* - * whereNot(key, value) - */ + // whereNot(key, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', 2]]); @@ -2562,9 +2556,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - /* - * whereNot(key, <, value) - */ + // whereNot(key, <, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', '<', 2]]); @@ -2581,9 +2573,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where not (("foo" = ? and "bar" < ?))', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - /* - * whereColumn(col1, col2) - */ + // whereColumn(col1, col2) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '_bar']]); @@ -2615,9 +2605,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); - /* - * whereColumn(col1, <, col2) - */ + // whereColumn(col1, <, col2) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '<', '_bar']]); @@ -2634,9 +2622,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" < "_bar")', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); - /* - * whereAll([...keys], value) - */ + // whereAll([...keys], value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereAll(['foo', 'bar'], 2); @@ -2648,9 +2634,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); - /* - * whereAny([...keys], value) - */ + // whereAny([...keys], value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereAny(['foo', 'bar'], 2); @@ -2662,9 +2646,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); - /* - * whereNone([...keys], value) - */ + // whereNone([...keys], value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereNone(['foo', 'bar'], 2); @@ -2676,9 +2658,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where not ("foo" = ? or "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); - /* - * where()->orWhere(key, value) - */ + // where()->orWhere(key, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', 2]]); @@ -2690,18 +2670,14 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 1, 2 => 2], $builder->getBindings()); - /* - * where()->orWhere(key, <, value) - */ + // where()->orWhere(key, <, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', '<', 2]]); $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 1, 2 => 2], $builder->getBindings()); - /* - * where()->orWhereColumn(col1, col2) - */ + // where()->orWhereColumn(col1, col2) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereColumn([['foo', '_foo'], ['bar', '_bar']]); @@ -2713,18 +2689,14 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = "_foo" or "bar" = "_bar")', $builder->toSql()); $this->assertEquals([0 => 'xxxx'], $builder->getBindings()); - /* - * where()->orWhere(key, <, value) - */ + // where()->orWhere(key, <, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', '<', 2]]); $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 1, 2 => 2], $builder->getBindings()); - /* - * where()->orWhereNot(key, value) - */ + // where()->orWhereNot(key, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNot([['foo', 1], ['bar', 2]]); @@ -2736,18 +2708,14 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where "xxxx" = ? or not (("foo" = ? or "bar" = ?))', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 1, 2 => 2], $builder->getBindings()); - /* - * where()->orWhereNot(key, <, value) - */ + // where()->orWhereNot(key, <, value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNot([['foo', 1], ['bar', '<', 2]]); $this->assertSame('select * from "users" where "xxxx" = ? or not (("foo" = ? or "bar" < ?))', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 1, 2 => 2], $builder->getBindings()); - /* - * where()->orWhereAll([...keys], value) - */ + // where()->orWhereAll([...keys], value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereAll(['foo', 'bar'], 2); @@ -2759,9 +2727,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); - /* - * where()->orWhereAny([...keys], value) - */ + // where()->orWhereAny([...keys], value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereAny(['foo', 'bar'], 2); @@ -2773,9 +2739,7 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); - /* - * where()->orWhereNone([...keys], value) - */ + // where()->orWhereNone([...keys], value) $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNone(['foo', 'bar'], 2); diff --git a/tests/Pagination/UrlWindowTest.php b/tests/Pagination/UrlWindowTest.php index 420fa7135151..0ed0d43a9657 100644 --- a/tests/Pagination/UrlWindowTest.php +++ b/tests/Pagination/UrlWindowTest.php @@ -37,9 +37,7 @@ public function testPresenterCanGetAUrlRangeForAWindowOfLinks() $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => $slider, 'last' => [19 => '/?page=19', 20 => '/?page=20']], $window->get()); - /* - * Test Being Near The End Of The List - */ + // Test Being Near The End Of The List $array = []; for ($i = 1; $i <= 20; $i++) { $array[$i] = 'item'.$i; diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index 9caddf307069..c44c2fd69a80 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -781,9 +781,7 @@ public function testRouteDomainRegistration() public function testMatchesMethodAgainstRequests() { - /* - * Basic - */ + // Basic $request = Request::create('foo/bar', 'GET'); $route = new Route('GET', 'foo/{bar}', function () { // @@ -796,9 +794,7 @@ public function testMatchesMethodAgainstRequests() }); $this->assertFalse($route->matches($request)); - /* - * Method checks - */ + // Method checks $request = Request::create('foo/bar', 'GET'); $route = new Route('GET', 'foo/{bar}', function () { // @@ -811,9 +807,7 @@ public function testMatchesMethodAgainstRequests() }); $this->assertFalse($route->matches($request)); - /* - * Domain checks - */ + // Domain checks $request = Request::create('http://something.foo.com/foo/bar', 'GET'); $route = new Route('GET', 'foo/{bar}', ['domain' => '{foo}.foo.com', function () { // @@ -826,9 +820,7 @@ public function testMatchesMethodAgainstRequests() }]); $this->assertFalse($route->matches($request)); - /* - * HTTPS checks - */ + // HTTPS checks $request = Request::create('https://foo.com/foo/bar', 'GET'); $route = new Route('GET', 'foo/{bar}', ['https', function () { // @@ -847,9 +839,7 @@ public function testMatchesMethodAgainstRequests() }]); $this->assertFalse($route->matches($request)); - /* - * HTTP checks - */ + // HTTP checks $request = Request::create('https://foo.com/foo/bar', 'GET'); $route = new Route('GET', 'foo/{bar}', ['http', function () { // @@ -906,9 +896,7 @@ public function testWherePatternsProperlyFilter() $route->where('bar', '123|456'); $this->assertFalse($route->matches($request)); - /* - * Optional - */ + // Optional $request = Request::create('foo/123', 'GET'); $route = new Route('GET', 'foo/{bar?}', function () { // @@ -944,9 +932,7 @@ public function testWherePatternsProperlyFilter() $route->where('bar', '[0-9]+'); $this->assertFalse($route->matches($request)); - /* - * Conditional - */ + // Conditional $route = new Route('GET', '{subdomain}.awesome.test', function () { // }); @@ -1196,9 +1182,7 @@ public function testGroupMerging() public function testRouteGrouping() { - /* - * getPrefix() method - */ + // getPrefix() method $router = $this->getRouter(); $router->group(['prefix' => 'foo'], function () use ($router) { $router->get('bar', function () { @@ -1275,9 +1259,7 @@ public function testRouteGroupingWithAs() public function testNestedRouteGroupingWithAs() { - /* - * nested with all layers present - */ + // nested with all layers present $router = $this->getRouter(); $router->group(['prefix' => 'foo', 'as' => 'Foo::'], function () use ($router) { $router->group(['prefix' => 'bar', 'as' => 'Bar::'], function () use ($router) { @@ -1290,9 +1272,7 @@ public function testNestedRouteGroupingWithAs() $route = $routes->getByName('Foo::Bar::baz'); $this->assertSame('foo/bar/baz', $route->uri()); - /* - * nested with layer skipped - */ + // nested with layer skipped $router = $this->getRouter(); $router->group(['prefix' => 'foo', 'as' => 'Foo::'], function () use ($router) { $router->group(['prefix' => 'bar'], function () use ($router) { @@ -1308,9 +1288,7 @@ public function testNestedRouteGroupingWithAs() public function testNestedRouteGroupingPrefixing() { - /* - * nested with layer skipped - */ + // nested with layer skipped $router = $this->getRouter(); $router->group(['prefix' => 'foo', 'as' => 'Foo::'], function () use ($router) { $router->prefix('bar')->get('baz', ['as' => 'baz', function () { @@ -1340,9 +1318,7 @@ public function testRouteMiddlewareMergeWithMiddlewareAttributesAsStrings() public function testRoutePrefixing() { - /* - * Prefix route - */ + // Prefix route $router = $this->getRouter(); $router->get('foo/bar', function () { return 'hello'; @@ -1352,9 +1328,7 @@ public function testRoutePrefixing() $routes[0]->prefix('prefix'); $this->assertSame('prefix/foo/bar', $routes[0]->uri()); - /* - * Use empty prefix - */ + // Use empty prefix $router = $this->getRouter(); $router->get('foo/bar', function () { return 'hello'; @@ -1364,9 +1338,7 @@ public function testRoutePrefixing() $routes[0]->prefix('/'); $this->assertSame('foo/bar', $routes[0]->uri()); - /* - * Prefix homepage - */ + // Prefix homepage $router = $this->getRouter(); $router->get('/', function () { return 'hello'; @@ -1376,9 +1348,7 @@ public function testRoutePrefixing() $routes[0]->prefix('prefix'); $this->assertSame('prefix', $routes[0]->uri()); - /* - * Prefix homepage with empty prefix - */ + // Prefix homepage with empty prefix $router = $this->getRouter(); $router->get('/', function () { return 'hello'; diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index cb7b97ec3f45..cfce4d87962f 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -31,9 +31,7 @@ public function testBasicGeneration() $this->assertSame('https://www.foo.com/foo/bar/baz/boom', $url->to('foo/bar', ['baz', 'boom'], true)); $this->assertSame('https://www.foo.com/foo/bar/baz?foo=bar', $url->to('foo/bar?foo=bar', ['baz'], true)); - /* - * Test HTTPS request URL generation... - */ + // Test HTTPS request URL generation... $url = new UrlGenerator( new RouteCollection, Request::create('https://www.foo.com/') @@ -204,78 +202,54 @@ public function testBasicRouteGeneration() Request::create('http://www.foo.com/') ); - /* - * Empty Named Route - */ + // Empty Named Route $route = new Route(['GET'], '/', ['as' => 'plain']); $routes->add($route); - /* - * Named Routes - */ + // Named Routes $route = new Route(['GET'], 'foo/bar', ['as' => 'foo']); $routes->add($route); - /* - * Parameters... - */ + // Parameters... $route = new Route(['GET'], 'foo/bar/{baz}/breeze/{boom}', ['as' => 'bar']); $routes->add($route); - /* - * Single Parameter... - */ + // Single Parameter... $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'foobar']); $routes->add($route); - /* - * Optional parameter - */ + // Optional parameter $route = new Route(['GET'], 'foo/bar/{baz?}', ['as' => 'optional']); $routes->add($route); - /* - * HTTPS... - */ + // HTTPS... $route = new Route(['GET'], 'foo/baz', ['as' => 'baz', 'https']); $routes->add($route); - /* - * Controller Route Route - */ + // Controller Route Route $route = new Route(['GET'], 'foo/bam', ['controller' => 'foo@bar']); $routes->add($route); - /* - * Non ASCII routes - */ + // Non ASCII routes $route = new Route(['GET'], 'foo/bar/åαф/{baz}', ['as' => 'foobarbaz']); $routes->add($route); - /* - * Fragments - */ + // Fragments $route = new Route(['GET'], 'foo/bar#derp', ['as' => 'fragment']); $routes->add($route); - /* - * Invoke action - */ + // Invoke action $route = new Route(['GET'], 'foo/invoke', ['controller' => 'InvokableActionStub']); $routes->add($route); - /* - * With Default Parameter - */ + // With Default Parameter $url->defaults(['locale' => 'en']); $route = new Route(['GET'], 'foo', ['as' => 'defaults', 'domain' => '{locale}.example.com', function () { // }]); $routes->add($route); - /* - * With backed enum name and domain - */ + // With backed enum name and domain $route = (new Route(['GET'], 'backed-enum', ['as' => 'prefixed.']))->name(RouteNameEnum::UserIndex)->domain(RouteDomainEnum::DashboardDomain); $routes->add($route); @@ -321,9 +295,7 @@ public function testFluentRouteNameDefinitions() Request::create('http://www.foo.com/') ); - /* - * Named Routes - */ + // Named Routes $route = new Route(['GET'], 'foo/bar', []); $route->name('foo'); $routes->add($route); @@ -341,9 +313,7 @@ public function testControllerRoutesWithADefaultNamespace() $url->setRootControllerNamespace('namespace'); - /* - * Controller Route Route - */ + // Controller Route Route $route = new Route(['GET'], 'foo/bar', ['controller' => 'namespace\foo@bar']); $routes->add($route); @@ -478,9 +448,7 @@ public function testRoutesMaintainRequestScheme() Request::create('https://www.foo.com/') ); - /* - * Named Routes - */ + // Named Routes $route = new Route(['GET'], 'foo/bar', ['as' => 'foo']); $routes->add($route); @@ -494,9 +462,7 @@ public function testHttpOnlyRoutes() Request::create('https://www.foo.com/') ); - /* - * Named Routes - */ + // Named Routes $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'http']); $routes->add($route); @@ -513,9 +479,7 @@ public function testRoutesWithDomains() $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']); $routes->add($route); - /* - * Wildcards & Domains... - */ + // Wildcards & Domains... $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'bar', 'domain' => 'sub.{foo}.com']); $routes->add($route); @@ -534,9 +498,7 @@ public function testRoutesWithDomainsAndPorts() $route = new Route(['GET'], 'foo/bar', ['as' => 'foo', 'domain' => 'sub.foo.com']); $routes->add($route); - /* - * Wildcards & Domains... - */ + // Wildcards & Domains... $route = new Route(['GET'], 'foo/bar/{baz}', ['as' => 'bar', 'domain' => 'sub.{foo}.com']); $routes->add($route); @@ -546,9 +508,7 @@ public function testRoutesWithDomainsAndPorts() public function testRoutesWithDomainsStripsProtocols() { - /* - * http:// Route - */ + // http:// Route $url = new UrlGenerator( $routes = new RouteCollection, Request::create('http://www.foo.com/') @@ -559,9 +519,7 @@ public function testRoutesWithDomainsStripsProtocols() $this->assertSame('http://sub.foo.com/foo/bar', $url->route('foo')); - /* - * https:// Route - */ + // https:// Route $url = new UrlGenerator( $routes = new RouteCollection, Request::create('https://www.foo.com/') @@ -580,9 +538,7 @@ public function testHttpsRoutesWithDomains() Request::create('https://foo.com/') ); - /* - * When on HTTPS, no need to specify 443 - */ + // When on HTTPS, no need to specify 443 $route = new Route(['GET'], 'foo/bar', ['as' => 'baz', 'domain' => 'sub.foo.com']); $routes->add($route); @@ -716,9 +672,7 @@ public function testUseRootUrl() $url->useOrigin('http://www.foo.com/'); $this->assertSame('http://www.foo.com/bar', $url->to('/bar')); - /* - * Route Based... - */ + // Route Based... $url = new UrlGenerator( $routes = new RouteCollection, Request::create('http://www.foo.com/') From c199db186adeac1f744236846e1b7c780b56013a Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 12 Mar 2025 09:21:19 -0500 Subject: [PATCH 171/455] do not use mix of newline and inline formatting (#54967) fully newline or fully inline are both okay options for formatting, but this mix of both is very hard to read, especially when you're throwing ternary statements in there. this commit switches these into purely newline format. --- .../Eloquent/Concerns/HasRelationships.php | 128 ++++++++++++++---- 1 file changed, 98 insertions(+), 30 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index b991fd08227c..a484bf01b679 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -153,9 +153,13 @@ public function hasOneThrough($related, $through, $firstKey = null, $secondKey = $secondKey = $secondKey ?: $through->getForeignKey(); return $this->newHasOneThrough( - $this->newRelatedInstance($related)->newQuery(), $this, $through, - $firstKey, $secondKey, $localKey ?: $this->getKeyName(), - $secondLocalKey ?: $through->getKeyName() + $this->newRelatedInstance($related)->newQuery(), + $this, + $through, + $firstKey, + $secondKey, + $localKey ?: $this->getKeyName(), + $secondLocalKey ?: $through->getKeyName(), ); } @@ -562,9 +566,15 @@ protected function newMorphMany(Builder $query, Model $parent, $type, $id, $loca * @param string|null $relation * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ - public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, - $parentKey = null, $relatedKey = null, $relation = null) - { + public function belongsToMany( + $related, + $table = null, + $foreignPivotKey = null, + $relatedPivotKey = null, + $parentKey = null, + $relatedKey = null, + $relation = null, + ) { // If no relationship name was passed, we will pull backtraces to get the // name of the calling function. We will use that function name as the // title of this relation since that is a great convention to apply. @@ -589,9 +599,14 @@ public function belongsToMany($related, $table = null, $foreignPivotKey = null, } return $this->newBelongsToMany( - $instance->newQuery(), $this, $table, $foreignPivotKey, - $relatedPivotKey, $parentKey ?: $this->getKeyName(), - $relatedKey ?: $instance->getKeyName(), $relation + $instance->newQuery(), + $this, + $table, + $foreignPivotKey, + $relatedPivotKey, + $parentKey ?: $this->getKeyName(), + $relatedKey ?: $instance->getKeyName(), + $relation, ); } @@ -611,9 +626,16 @@ public function belongsToMany($related, $table = null, $foreignPivotKey = null, * @param string|null $relationName * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ - protected function newBelongsToMany(Builder $query, Model $parent, $table, $foreignPivotKey, $relatedPivotKey, - $parentKey, $relatedKey, $relationName = null) - { + protected function newBelongsToMany( + Builder $query, + Model $parent, + $table, + $foreignPivotKey, + $relatedPivotKey, + $parentKey, + $relatedKey, + $relationName = null, + ) { return new BelongsToMany($query, $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName); } @@ -633,10 +655,17 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore * @param bool $inverse * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ - public function morphToMany($related, $name, $table = null, $foreignPivotKey = null, - $relatedPivotKey = null, $parentKey = null, - $relatedKey = null, $relation = null, $inverse = false) - { + public function morphToMany( + $related, + $name, + $table = null, + $foreignPivotKey = null, + $relatedPivotKey = null, + $parentKey = null, + $relatedKey = null, + $relation = null, + $inverse = false, + ) { $relation = $relation ?: $this->guessBelongsToManyRelation(); // First, we will need to determine the foreign key and "other key" for the @@ -660,9 +689,16 @@ public function morphToMany($related, $name, $table = null, $foreignPivotKey = n } return $this->newMorphToMany( - $instance->newQuery(), $this, $name, $table, - $foreignPivotKey, $relatedPivotKey, $parentKey ?: $this->getKeyName(), - $relatedKey ?: $instance->getKeyName(), $relation, $inverse + $instance->newQuery(), + $this, + $name, + $table, + $foreignPivotKey, + $relatedPivotKey, + $parentKey ?: $this->getKeyName(), + $relatedKey ?: $instance->getKeyName(), + $relation, + $inverse, ); } @@ -684,12 +720,30 @@ public function morphToMany($related, $name, $table = null, $foreignPivotKey = n * @param bool $inverse * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ - protected function newMorphToMany(Builder $query, Model $parent, $name, $table, $foreignPivotKey, - $relatedPivotKey, $parentKey, $relatedKey, - $relationName = null, $inverse = false) - { - return new MorphToMany($query, $parent, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, - $relationName, $inverse); + protected function newMorphToMany( + Builder $query, + Model $parent, + $name, + $table, + $foreignPivotKey, + $relatedPivotKey, + $parentKey, + $relatedKey, + $relationName = null, + $inverse = false, + ) { + return new MorphToMany( + $query, + $parent, + $name, + $table, + $foreignPivotKey, + $relatedPivotKey, + $parentKey, + $relatedKey, + $relationName, + $inverse, + ); } /** @@ -707,9 +761,16 @@ protected function newMorphToMany(Builder $query, Model $parent, $name, $table, * @param string|null $relation * @return \Illuminate\Database\Eloquent\Relations\MorphToMany */ - public function morphedByMany($related, $name, $table = null, $foreignPivotKey = null, - $relatedPivotKey = null, $parentKey = null, $relatedKey = null, $relation = null) - { + public function morphedByMany( + $related, + $name, + $table = null, + $foreignPivotKey = null, + $relatedPivotKey = null, + $parentKey = null, + $relatedKey = null, + $relation = null, + ) { $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey(); // For the inverse of the polymorphic many-to-many relations, we will change @@ -718,8 +779,15 @@ public function morphedByMany($related, $name, $table = null, $foreignPivotKey = $relatedPivotKey = $relatedPivotKey ?: $name.'_id'; return $this->morphToMany( - $related, $name, $table, $foreignPivotKey, - $relatedPivotKey, $parentKey, $relatedKey, $relation, true + $related, + $name, + $table, + $foreignPivotKey, + $relatedPivotKey, + $parentKey, + $relatedKey, + $relation, + true, ); } From 3786b5166848af5f2a59db615a03ead43eb2bf20 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 12 Mar 2025 09:22:47 -0500 Subject: [PATCH 172/455] use single indent for multiline ternarys (#54971) this continues on some of my earlier formatting changes. you can read #53748 for my arguments why single indent is better. --- src/Illuminate/Auth/Access/Gate.php | 8 ++++---- src/Illuminate/Auth/DatabaseUserProvider.php | 3 ++- src/Illuminate/Auth/EloquentUserProvider.php | 4 ++-- .../Auth/Middleware/EnsureEmailIsVerified.php | 4 ++-- src/Illuminate/Auth/SessionGuard.php | 4 ++-- .../Broadcasting/BroadcastController.php | 2 +- .../Broadcasting/BroadcastEvent.php | 6 +++--- .../Broadcasters/AblyBroadcaster.php | 8 ++++---- .../Broadcasting/Broadcasters/Broadcaster.php | 3 ++- .../Broadcasters/PusherBroadcaster.php | 4 ++-- .../Broadcasters/RedisBroadcaster.php | 4 ++-- .../InteractsWithBroadcasting.php | 4 ++-- .../Broadcasting/UniqueBroadcastEvent.php | 4 ++-- src/Illuminate/Bus/Dispatcher.php | 4 ++-- src/Illuminate/Bus/PendingBatch.php | 12 +++++------ src/Illuminate/Bus/UniqueLock.php | 16 +++++++-------- src/Illuminate/Cache/CacheLock.php | 4 ++-- src/Illuminate/Cache/DynamoDbStore.php | 4 ++-- src/Illuminate/Collections/Arr.php | 8 ++++---- .../Collections/Traits/EnumeratesValues.php | 8 ++++---- src/Illuminate/Console/Application.php | 4 ++-- src/Illuminate/Console/Command.php | 4 ++-- src/Illuminate/Console/GeneratorCommand.php | 4 ++-- src/Illuminate/Console/Scheduling/Event.php | 4 ++-- .../Console/Scheduling/Schedule.php | 8 ++++---- .../Scheduling/ScheduleListCommand.php | 4 ++-- src/Illuminate/Container/BoundMethod.php | 11 +++++----- src/Illuminate/Container/Container.php | 12 +++++------ .../Cookie/Middleware/EncryptCookies.php | 8 ++++---- .../Database/Concerns/ManagesTransactions.php | 4 ++-- .../Database/Connectors/ConnectionFactory.php | 8 ++++---- .../Database/Connectors/MySqlConnector.php | 8 ++++---- .../Connectors/SqlServerConnector.php | 3 ++- .../Console/Factories/FactoryMakeCommand.php | 4 ++-- .../Console/Migrations/BaseCommand.php | 4 ++-- .../Console/Migrations/MigrateMakeCommand.php | 4 ++-- src/Illuminate/Database/DatabaseManager.php | 3 ++- .../BroadcastableModelEventOccurred.php | 8 ++++---- .../Database/Eloquent/BroadcastsEvents.php | 12 +++++------ src/Illuminate/Database/Eloquent/Builder.php | 7 ++++--- .../Database/Eloquent/Casts/Json.php | 4 ++-- .../Database/Eloquent/Collection.php | 8 ++++---- .../Eloquent/Concerns/GuardsAttributes.php | 4 ++-- .../Eloquent/Concerns/HasAttributes.php | 12 +++++------ .../Eloquent/Concerns/HasRelationships.php | 4 ++-- .../Concerns/QueriesRelationships.php | 8 ++++---- .../Database/Eloquent/Factories/Factory.php | 4 ++-- .../Database/Eloquent/MassPrunable.php | 4 ++-- src/Illuminate/Database/Eloquent/Prunable.php | 4 ++-- .../Eloquent/Relations/BelongsToMany.php | 8 ++++---- .../Concerns/InteractsWithPivotTable.php | 8 ++++---- .../Database/Eloquent/Relations/HasMany.php | 4 ++-- .../Eloquent/Relations/HasManyThrough.php | 4 ++-- .../Database/Eloquent/Relations/MorphMany.php | 4 ++-- .../Database/Eloquent/Relations/MorphTo.php | 12 +++++------ .../Eloquent/Relations/MorphToMany.php | 6 +++--- .../Database/Eloquent/Relations/Relation.php | 13 ++++++------ src/Illuminate/Database/Grammar.php | 4 ++-- .../Database/Migrations/MigrationCreator.php | 12 +++++------ .../Database/Migrations/Migrator.php | 8 ++++---- src/Illuminate/Database/Query/Builder.php | 15 +++++++------- .../Database/Query/Grammars/SQLiteGrammar.php | 4 ++-- .../Query/Grammars/SqlServerGrammar.php | 8 ++++---- .../Database/Schema/Grammars/Grammar.php | 4 ++-- .../Database/Schema/MySqlSchemaState.php | 4 ++-- src/Illuminate/Events/Dispatcher.php | 14 ++++++------- .../Filesystem/FilesystemAdapter.php | 8 ++++---- src/Illuminate/Foundation/Application.php | 12 +++++------ .../Foundation/Bus/PendingChain.php | 4 ++-- .../Foundation/Console/CastMakeCommand.php | 4 ++-- .../Console/ComponentMakeCommand.php | 4 ++-- .../Foundation/Console/EnumMakeCommand.php | 4 ++-- .../Console/EnvironmentDecryptCommand.php | 4 ++-- .../Console/EnvironmentEncryptCommand.php | 4 ++-- .../Foundation/Console/EventMakeCommand.php | 4 ++-- .../Foundation/Console/JobMakeCommand.php | 8 ++++---- .../Console/JobMiddlewareMakeCommand.php | 4 ++-- .../Console/ListenerMakeCommand.php | 12 +++++------ .../Foundation/Console/ModelMakeCommand.php | 4 ++-- .../Foundation/Console/PolicyMakeCommand.php | 8 ++++---- .../Foundation/Console/RequestMakeCommand.php | 4 ++-- .../Console/ResourceMakeCommand.php | 8 ++++---- .../Foundation/Console/TestMakeCommand.php | 4 ++-- .../Foundation/Console/ViewMakeCommand.php | 4 ++-- .../Foundation/Exceptions/Handler.php | 12 +++++------ .../Foundation/Http/FormRequest.php | 4 ++-- .../PreventRequestsDuringMaintenance.php | 4 ++-- .../Providers/EventServiceProvider.php | 4 ++-- .../Testing/DatabaseTransactions.php | 3 ++- .../Foundation/Testing/DatabaseTruncation.php | 2 +- .../Foundation/Testing/RefreshDatabase.php | 3 ++- src/Illuminate/Foundation/helpers.php | 4 ++-- src/Illuminate/Http/Client/Response.php | 4 ++-- .../Http/Concerns/InteractsWithInput.php | 4 ++-- .../Http/Middleware/TrustProxies.php | 4 ++-- .../Http/Resources/CollectsResources.php | 4 ++-- .../ConditionallyLoadsAttributes.php | 4 ++-- src/Illuminate/Mail/MailManager.php | 4 ++-- src/Illuminate/Mail/Mailable.php | 4 ++-- src/Illuminate/Mail/Mailer.php | 8 ++++---- .../Channels/DatabaseChannel.php | 11 +++++----- .../Notifications/Channels/MailChannel.php | 4 ++-- .../Events/BroadcastNotificationCreated.php | 8 ++++---- .../Notifications/NotificationSender.php | 3 ++- .../Pagination/AbstractCursorPaginator.php | 4 ++-- src/Illuminate/Pipeline/Pipeline.php | 4 ++-- src/Illuminate/Process/Factory.php | 4 ++-- src/Illuminate/Process/FakeInvokedProcess.php | 4 ++-- .../Process/FakeProcessDescription.php | 8 ++++---- .../Process/FakeProcessSequence.php | 4 ++-- src/Illuminate/Process/PendingProcess.php | 4 ++-- src/Illuminate/Queue/CallQueuedClosure.php | 4 ++-- src/Illuminate/Queue/Console/ClearCommand.php | 2 +- .../Queue/Console/ListenCommand.php | 4 ++-- src/Illuminate/Queue/Console/RetryCommand.php | 4 ++-- src/Illuminate/Queue/Console/WorkCommand.php | 2 +- .../Queue/Middleware/RateLimited.php | 4 ++-- src/Illuminate/Queue/Queue.php | 14 +++++++------ .../SerializesAndRestoresModelIdentifiers.php | 4 ++-- src/Illuminate/Queue/Worker.php | 4 ++-- .../Routing/Console/ControllerMakeCommand.php | 8 ++++---- .../Routing/ImplicitRouteBinding.php | 8 ++++---- .../Routing/Middleware/ThrottleRequests.php | 4 ++-- src/Illuminate/Routing/Redirector.php | 4 ++-- src/Illuminate/Routing/ResourceRegistrar.php | 4 ++-- src/Illuminate/Routing/Route.php | 6 +++--- src/Illuminate/Routing/RouteBinding.php | 4 ++-- src/Illuminate/Routing/RouteGroup.php | 4 ++-- .../Routing/RouteSignatureParameters.php | 8 ++++---- src/Illuminate/Routing/RouteUrlGenerator.php | 6 +++--- src/Illuminate/Routing/Router.php | 2 +- src/Illuminate/Routing/UrlGenerator.php | 4 ++-- .../Session/Middleware/StartSession.php | 8 ++++---- src/Illuminate/Session/SessionManager.php | 14 ++++++------- src/Illuminate/Support/Facades/Bus.php | 4 ++-- src/Illuminate/Support/Facades/Event.php | 4 ++-- src/Illuminate/Support/Facades/Mail.php | 4 ++-- src/Illuminate/Support/Facades/Queue.php | 4 ++-- src/Illuminate/Support/InteractsWithTime.php | 8 ++++---- .../Support/NamespacedItemResolver.php | 4 ++-- src/Illuminate/Support/Str.php | 16 +++++++-------- .../Support/Testing/Fakes/BusFake.php | 4 ++-- .../Support/Testing/Fakes/EventFake.php | 4 ++-- .../Support/Testing/Fakes/QueueFake.php | 4 ++-- src/Illuminate/Testing/TestResponse.php | 20 +++++++++---------- .../Concerns/FilterEmailValidation.php | 4 ++-- .../Validation/Concerns/FormatsMessages.php | 10 +++++----- .../Concerns/ValidatesAttributes.php | 14 ++++++------- .../Validation/ConditionalRules.php | 12 +++++------ .../Validation/InvokableValidationRule.php | 4 ++-- src/Illuminate/Validation/Rules/Password.php | 4 ++-- .../Validation/ValidationRuleParser.php | 4 ++-- src/Illuminate/Validation/Validator.php | 16 +++++++-------- .../View/Compilers/BladeCompiler.php | 16 +++++++-------- .../View/Compilers/ComponentTagCompiler.php | 20 +++++++++---------- .../Compilers/Concerns/CompilesComponents.php | 10 +++++----- src/Illuminate/View/Component.php | 4 ++-- src/Illuminate/View/ComponentAttributeBag.php | 8 ++++---- src/Illuminate/View/Concerns/ManagesLoops.php | 4 ++-- src/Illuminate/View/Factory.php | 4 ++-- src/Illuminate/View/View.php | 4 ++-- 161 files changed, 505 insertions(+), 491 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index d209ab3730bc..1d0ab89597b4 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -180,8 +180,8 @@ protected function authorizeOnDemand($condition, $message, $code, $allowWhenResp if ($condition instanceof Closure) { $response = $this->canBeCalledWithUser($user, $condition) - ? $condition($user) - : new Response(false, $message, $code); + ? $condition($user) + : new Response(false, $message, $code); } else { $response = $condition; } @@ -277,8 +277,8 @@ protected function buildAbilityCallback($ability, $callback) } return isset($method) - ? $policy->{$method}(...func_get_args()) - : $policy(...func_get_args()); + ? $policy->{$method}(...func_get_args()) + : $policy(...func_get_args()); }; } diff --git a/src/Illuminate/Auth/DatabaseUserProvider.php b/src/Illuminate/Auth/DatabaseUserProvider.php index def86b346a55..a1332d596a9b 100755 --- a/src/Illuminate/Auth/DatabaseUserProvider.php +++ b/src/Illuminate/Auth/DatabaseUserProvider.php @@ -74,7 +74,8 @@ public function retrieveByToken($identifier, #[\SensitiveParameter] $token) ); return $user && $user->getRememberToken() && hash_equals($user->getRememberToken(), $token) - ? $user : null; + ? $user + : null; } /** diff --git a/src/Illuminate/Auth/EloquentUserProvider.php b/src/Illuminate/Auth/EloquentUserProvider.php index dc7a21ecac5d..8a4a21c788ab 100755 --- a/src/Illuminate/Auth/EloquentUserProvider.php +++ b/src/Illuminate/Auth/EloquentUserProvider.php @@ -189,8 +189,8 @@ public function rehashPasswordIfRequired(UserContract $user, #[\SensitiveParamet protected function newModelQuery($model = null) { $query = is_null($model) - ? $this->createModel()->newQuery() - : $model->newQuery(); + ? $this->createModel()->newQuery() + : $model->newQuery(); with($query, $this->queryCallback); diff --git a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php index 10a3f7c65538..227174df2148 100644 --- a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php +++ b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php @@ -34,8 +34,8 @@ public function handle($request, Closure $next, $redirectToRoute = null) ($request->user() instanceof MustVerifyEmail && ! $request->user()->hasVerifiedEmail())) { return $request->expectsJson() - ? abort(403, 'Your email address is not verified.') - : Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice')); + ? abort(403, 'Your email address is not verified.') + : Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice')); } return $next($request); diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 4aede1ae6767..928c970643f7 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -239,8 +239,8 @@ public function id() } return $this->user() - ? $this->user()->getAuthIdentifier() - : $this->session->get($this->getName()); + ? $this->user()->getAuthIdentifier() + : $this->session->get($this->getName()); } /** diff --git a/src/Illuminate/Broadcasting/BroadcastController.php b/src/Illuminate/Broadcasting/BroadcastController.php index f2936ab416e0..01ce074eec88 100644 --- a/src/Illuminate/Broadcasting/BroadcastController.php +++ b/src/Illuminate/Broadcasting/BroadcastController.php @@ -41,6 +41,6 @@ public function authenticateUser(Request $request) } return Broadcast::resolveAuthenticatedUser($request) - ?? throw new AccessDeniedHttpException; + ?? throw new AccessDeniedHttpException; } } diff --git a/src/Illuminate/Broadcasting/BroadcastEvent.php b/src/Illuminate/Broadcasting/BroadcastEvent.php index 1f7d927e7b31..3eb1c856db96 100644 --- a/src/Illuminate/Broadcasting/BroadcastEvent.php +++ b/src/Illuminate/Broadcasting/BroadcastEvent.php @@ -75,7 +75,7 @@ public function __construct($event) public function handle(BroadcastingFactory $manager) { $name = method_exists($this->event, 'broadcastAs') - ? $this->event->broadcastAs() : get_class($this->event); + ? $this->event->broadcastAs() : get_class($this->event); $channels = Arr::wrap($this->event->broadcastOn()); @@ -84,8 +84,8 @@ public function handle(BroadcastingFactory $manager) } $connections = method_exists($this->event, 'broadcastConnections') - ? $this->event->broadcastConnections() - : [null]; + ? $this->event->broadcastConnections() + : [null]; $payload = $this->getPayloadFromEvent($this->event); diff --git a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php index 01c673c22f32..e2b70cead0dd 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php @@ -78,8 +78,8 @@ public function validAuthenticationResponse($request, $result) $user = $this->retrieveUser($request, $channelName); $broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting') - ? $user->getAuthIdentifierForBroadcasting() - : $user->getAuthIdentifier(); + ? $user->getAuthIdentifierForBroadcasting() + : $user->getAuthIdentifier(); $signature = $this->generateAblySignature( $request->channel_name, @@ -175,8 +175,8 @@ public function normalizeChannelName($channel) { if ($this->isGuardedChannel($channel)) { return str_starts_with($channel, 'private-') - ? Str::replaceFirst('private-', '', $channel) - : Str::replaceFirst('presence-', '', $channel); + ? Str::replaceFirst('private-', '', $channel) + : Str::replaceFirst('presence-', '', $channel); } return $channel; diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index eb21f2c0662f..6ebde3b7e3af 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -299,7 +299,8 @@ protected function binder() { if (! $this->bindingRegistrar) { $this->bindingRegistrar = Container::getInstance()->bound(BindingRegistrar::class) - ? Container::getInstance()->make(BindingRegistrar::class) : null; + ? Container::getInstance()->make(BindingRegistrar::class) + : null; } return $this->bindingRegistrar; diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 962d814183a8..cc3b80accb31 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -110,8 +110,8 @@ public function validAuthenticationResponse($request, $result) $user = $this->retrieveUser($request, $channelName); $broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting') - ? $user->getAuthIdentifierForBroadcasting() - : $user->getAuthIdentifier(); + ? $user->getAuthIdentifierForBroadcasting() + : $user->getAuthIdentifier(); return $this->decodePusherResponse( $request, diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index 03245eac6e6f..d7ff8f5de76e 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -92,8 +92,8 @@ public function validAuthenticationResponse($request, $result) $user = $this->retrieveUser($request, $channelName); $broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting') - ? $user->getAuthIdentifierForBroadcasting() - : $user->getAuthIdentifier(); + ? $user->getAuthIdentifierForBroadcasting() + : $user->getAuthIdentifier(); return json_encode(['channel_data' => [ 'user_id' => $broadcastIdentifier, diff --git a/src/Illuminate/Broadcasting/InteractsWithBroadcasting.php b/src/Illuminate/Broadcasting/InteractsWithBroadcasting.php index fd27a8cabb67..48fcba6bf802 100644 --- a/src/Illuminate/Broadcasting/InteractsWithBroadcasting.php +++ b/src/Illuminate/Broadcasting/InteractsWithBroadcasting.php @@ -22,8 +22,8 @@ trait InteractsWithBroadcasting public function broadcastVia($connection = null) { $this->broadcastConnection = is_null($connection) - ? [null] - : Arr::wrap($connection); + ? [null] + : Arr::wrap($connection); return $this; } diff --git a/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php b/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php index 83c752df08fb..098d4eaf5359 100644 --- a/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php +++ b/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php @@ -55,7 +55,7 @@ public function __construct($event) public function uniqueVia() { return method_exists($this->event, 'uniqueVia') - ? $this->event->uniqueVia() - : Container::getInstance()->make(Repository::class); + ? $this->event->uniqueVia() + : Container::getInstance()->make(Repository::class); } } diff --git a/src/Illuminate/Bus/Dispatcher.php b/src/Illuminate/Bus/Dispatcher.php index 5427c3ffb1b5..d239646190ef 100644 --- a/src/Illuminate/Bus/Dispatcher.php +++ b/src/Illuminate/Bus/Dispatcher.php @@ -74,8 +74,8 @@ public function __construct(Container $container, ?Closure $queueResolver = null public function dispatch($command) { return $this->queueResolver && $this->commandShouldBeQueued($command) - ? $this->dispatchToQueue($command) - : $this->dispatchNow($command); + ? $this->dispatchToQueue($command) + : $this->dispatchNow($command); } /** diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 3a3074dfe186..356d3d9468e2 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -171,8 +171,8 @@ public function progressCallbacks() public function then($callback) { $this->options['then'][] = $callback instanceof Closure - ? new SerializableClosure($callback) - : $callback; + ? new SerializableClosure($callback) + : $callback; return $this; } @@ -196,8 +196,8 @@ public function thenCallbacks() public function catch($callback) { $this->options['catch'][] = $callback instanceof Closure - ? new SerializableClosure($callback) - : $callback; + ? new SerializableClosure($callback) + : $callback; return $this; } @@ -221,8 +221,8 @@ public function catchCallbacks() public function finally($callback) { $this->options['finally'][] = $callback instanceof Closure - ? new SerializableClosure($callback) - : $callback; + ? new SerializableClosure($callback) + : $callback; return $this; } diff --git a/src/Illuminate/Bus/UniqueLock.php b/src/Illuminate/Bus/UniqueLock.php index 9a2726e9d8a5..5e207d550941 100644 --- a/src/Illuminate/Bus/UniqueLock.php +++ b/src/Illuminate/Bus/UniqueLock.php @@ -33,12 +33,12 @@ public function __construct(Cache $cache) public function acquire($job) { $uniqueFor = method_exists($job, 'uniqueFor') - ? $job->uniqueFor() - : ($job->uniqueFor ?? 0); + ? $job->uniqueFor() + : ($job->uniqueFor ?? 0); $cache = method_exists($job, 'uniqueVia') - ? $job->uniqueVia() - : $this->cache; + ? $job->uniqueVia() + : $this->cache; return (bool) $cache->lock($this->getKey($job), $uniqueFor)->get(); } @@ -52,8 +52,8 @@ public function acquire($job) public function release($job) { $cache = method_exists($job, 'uniqueVia') - ? $job->uniqueVia() - : $this->cache; + ? $job->uniqueVia() + : $this->cache; $cache->lock($this->getKey($job))->forceRelease(); } @@ -67,8 +67,8 @@ public function release($job) public static function getKey($job) { $uniqueId = method_exists($job, 'uniqueId') - ? $job->uniqueId() - : ($job->uniqueId ?? ''); + ? $job->uniqueId() + : ($job->uniqueId ?? ''); return 'laravel_unique_job:'.get_class($job).':'.$uniqueId; } diff --git a/src/Illuminate/Cache/CacheLock.php b/src/Illuminate/Cache/CacheLock.php index 5cc4eeaf4863..cb60da867e33 100644 --- a/src/Illuminate/Cache/CacheLock.php +++ b/src/Illuminate/Cache/CacheLock.php @@ -45,8 +45,8 @@ public function acquire() } return ($this->seconds > 0) - ? $this->store->put($this->name, $this->owner, $this->seconds) - : $this->store->forever($this->name, $this->owner); + ? $this->store->put($this->name, $this->owner, $this->seconds) + : $this->store->forever($this->name, $this->owner); } /** diff --git a/src/Illuminate/Cache/DynamoDbStore.php b/src/Illuminate/Cache/DynamoDbStore.php index 7f3b419817a8..e970d0d85738 100644 --- a/src/Illuminate/Cache/DynamoDbStore.php +++ b/src/Illuminate/Cache/DynamoDbStore.php @@ -470,8 +470,8 @@ public function flush() protected function toTimestamp($seconds) { return $seconds > 0 - ? $this->availableAt($seconds) - : $this->currentTime(); + ? $this->availableAt($seconds) + : $this->currentTime(); } /** diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 63bb3111b66c..25e240e693d6 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -849,12 +849,12 @@ public static function sortRecursive($array, $options = SORT_REGULAR, $descendin if (! array_is_list($array)) { $descending - ? krsort($array, $options) - : ksort($array, $options); + ? krsort($array, $options) + : ksort($array, $options); } else { $descending - ? rsort($array, $options) - : sort($array, $options); + ? rsort($array, $options) + : sort($array, $options); } return $array; diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 64736927f1ce..71f07cd82ac4 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -505,8 +505,8 @@ public function forPage($page, $perPage) public function partition($key, $operator = null, $value = null) { $callback = func_num_args() === 1 - ? $this->valueRetriever($key) - : $this->operatorForWhere(...func_get_args()); + ? $this->valueRetriever($key) + : $this->operatorForWhere(...func_get_args()); [$passed, $failed] = Arr::partition($this->getIterator(), $callback); @@ -991,8 +991,8 @@ public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) public function __toString() { return $this->escapeWhenCastingToString - ? e($this->toJson()) - : $this->toJson(); + ? e($this->toJson()) + : $this->toJson(); } /** diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 63e364e2d57d..86399d0ac24a 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -200,8 +200,8 @@ protected function parseCommand($command, $parameters) public function output() { return $this->lastOutput && method_exists($this->lastOutput, 'fetch') - ? $this->lastOutput->fetch() - : ''; + ? $this->lastOutput->fetch() + : ''; } /** diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 3d5167ef82ba..635c416100ef 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -203,8 +203,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int )); return (int) (is_numeric($this->option('isolated')) - ? $this->option('isolated') - : $this->isolatedExitCode); + ? $this->option('isolated') + : $this->isolatedExitCode); } $method = method_exists($this, 'handle') ? 'handle' : '__invoke'; diff --git a/src/Illuminate/Console/GeneratorCommand.php b/src/Illuminate/Console/GeneratorCommand.php index af0049bbd021..032b0b042c6b 100644 --- a/src/Illuminate/Console/GeneratorCommand.php +++ b/src/Illuminate/Console/GeneratorCommand.php @@ -236,8 +236,8 @@ protected function qualifyModel(string $model) } return is_dir(app_path('Models')) - ? $rootNamespace.'Models\\'.$model - : $rootNamespace.$model; + ? $rootNamespace.'Models\\'.$model + : $rootNamespace.$model; } /** diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 238ce0d57543..74c588ef037e 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -743,8 +743,8 @@ protected function withOutputCallback(Closure $callback, $onlyIfOutputExists = f $output = $this->output && is_file($this->output) ? file_get_contents($this->output) : ''; return $onlyIfOutputExists && empty($output) - ? null - : $container->call($callback, ['output' => new Stringable($output)]); + ? null + : $container->call($callback, ['output' => new Stringable($output)]); }; } diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index 839d36272122..975e7fd6e4eb 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -119,12 +119,12 @@ public function __construct($timezone = null) $container = Container::getInstance(); $this->eventMutex = $container->bound(EventMutex::class) - ? $container->make(EventMutex::class) - : $container->make(CacheEventMutex::class); + ? $container->make(EventMutex::class) + : $container->make(CacheEventMutex::class); $this->schedulingMutex = $container->bound(SchedulingMutex::class) - ? $container->make(SchedulingMutex::class) - : $container->make(CacheSchedulingMutex::class); + ? $container->make(SchedulingMutex::class) + : $container->make(CacheSchedulingMutex::class); } /** diff --git a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php index df5fe53918fa..0bb8f11ab498 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleListCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleListCommand.php @@ -190,8 +190,8 @@ private function getRepeatExpression($event) private function sortEvents(\Illuminate\Support\Collection $events, DateTimeZone $timezone) { return $this->option('next') - ? $events->sortBy(fn ($event) => $this->getNextDueDateForEvent($event, $timezone)) - : $events; + ? $events->sortBy(fn ($event) => $this->getNextDueDateForEvent($event, $timezone)) + : $events; } /** diff --git a/src/Illuminate/Container/BoundMethod.php b/src/Illuminate/Container/BoundMethod.php index d719e918217d..32c1da23ef32 100644 --- a/src/Illuminate/Container/BoundMethod.php +++ b/src/Illuminate/Container/BoundMethod.php @@ -56,7 +56,8 @@ protected static function callClass($container, $target, array $parameters = [], // name. We will split on this @ sign and then build a callable array that // we can pass right back into the "call" method for dependency binding. $method = count($segments) === 2 - ? $segments[1] : $defaultMethod; + ? $segments[1] + : $defaultMethod; if (is_null($method)) { throw new InvalidArgumentException('Method not provided.'); @@ -146,8 +147,8 @@ protected static function getCallReflector($callback) } return is_array($callback) - ? new ReflectionMethod($callback[0], $callback[1]) - : new ReflectionFunction($callback); + ? new ReflectionMethod($callback[0], $callback[1]) + : new ReflectionFunction($callback); } /** @@ -184,8 +185,8 @@ protected static function addDependencyForCallParameter( $variadicDependencies = $container->make($className); $pendingDependencies = array_merge($pendingDependencies, is_array($variadicDependencies) - ? $variadicDependencies - : [$variadicDependencies]); + ? $variadicDependencies + : [$variadicDependencies]); } else { $pendingDependencies[] = $container->make($className); } diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index bdfe7dd13cc5..a36398a47ca7 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -1097,8 +1097,8 @@ protected function resolveDependencies(array $dependencies) // primitive type which we can not resolve since it is not a class and // we will just bomb out with an error since we have no-where to go. $result ??= is_null(Util::getParameterClassName($dependency)) - ? $this->resolvePrimitive($dependency) - : $this->resolveClass($dependency); + ? $this->resolvePrimitive($dependency) + : $this->resolveClass($dependency); $this->fireAfterResolvingAttributeCallbacks($dependency->getAttributes(), $result); @@ -1203,8 +1203,8 @@ protected function resolveClass(ReflectionParameter $parameter) try { return $parameter->isVariadic() - ? $this->resolveVariadicClass($parameter) - : $this->make($className); + ? $this->resolveVariadicClass($parameter) + : $this->make($className); } // If we can not resolve the class instance, we will check to see if the value @@ -1520,8 +1520,8 @@ public function getBindings() public function getAlias($abstract) { return isset($this->aliases[$abstract]) - ? $this->getAlias($this->aliases[$abstract]) - : $abstract; + ? $this->getAlias($this->aliases[$abstract]) + : $abstract; } /** diff --git a/src/Illuminate/Cookie/Middleware/EncryptCookies.php b/src/Illuminate/Cookie/Middleware/EncryptCookies.php index 54079befeaa7..aefd7bac2538 100644 --- a/src/Illuminate/Cookie/Middleware/EncryptCookies.php +++ b/src/Illuminate/Cookie/Middleware/EncryptCookies.php @@ -110,8 +110,8 @@ 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->getAllKeys()); + ? $this->validateArray($key, $value) + : CookieValuePrefix::validate($key, $value, $this->encrypter->getAllKeys()); } /** @@ -142,8 +142,8 @@ protected function validateArray(string $key, array $value) protected function decryptCookie($name, $cookie) { return is_array($cookie) - ? $this->decryptArray($cookie) - : $this->encrypter->decrypt($cookie, static::serialized($name)); + ? $this->decryptArray($cookie) + : $this->encrypter->decrypt($cookie, static::serialized($name)); } /** diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index e7ac09423d16..23bc60434e49 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -255,8 +255,8 @@ public function rollBack($toLevel = null) // that this given transaction level is valid before attempting to rollback to // that level. If it's not we will just return out and not attempt anything. $toLevel = is_null($toLevel) - ? $this->transactions - 1 - : $toLevel; + ? $this->transactions - 1 + : $toLevel; if ($toLevel < 0 || $toLevel >= $this->transactions) { return; diff --git a/src/Illuminate/Database/Connectors/ConnectionFactory.php b/src/Illuminate/Database/Connectors/ConnectionFactory.php index e8e187565f0e..9d28225de4c5 100755 --- a/src/Illuminate/Database/Connectors/ConnectionFactory.php +++ b/src/Illuminate/Database/Connectors/ConnectionFactory.php @@ -138,8 +138,8 @@ protected function getWriteConfig(array $config) protected function getReadWriteConfig(array $config, $type) { return isset($config[$type][0]) - ? Arr::random($config[$type]) - : $config[$type]; + ? Arr::random($config[$type]) + : $config[$type]; } /** @@ -163,8 +163,8 @@ protected function mergeReadWriteConfig(array $config, array $merge) protected function createPdoResolver(array $config) { return array_key_exists('host', $config) - ? $this->createPdoResolverWithHosts($config) - : $this->createPdoResolverWithoutHosts($config); + ? $this->createPdoResolverWithHosts($config) + : $this->createPdoResolverWithoutHosts($config); } /** diff --git a/src/Illuminate/Database/Connectors/MySqlConnector.php b/src/Illuminate/Database/Connectors/MySqlConnector.php index 14c520ed2495..fc55b801407f 100755 --- a/src/Illuminate/Database/Connectors/MySqlConnector.php +++ b/src/Illuminate/Database/Connectors/MySqlConnector.php @@ -45,8 +45,8 @@ public function connect(array $config) protected function getDsn(array $config) { return $this->hasSocket($config) - ? $this->getSocketDsn($config) - : $this->getHostDsn($config); + ? $this->getSocketDsn($config) + : $this->getHostDsn($config); } /** @@ -80,8 +80,8 @@ protected function getSocketDsn(array $config) protected function getHostDsn(array $config) { return isset($config['port']) - ? "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']}" - : "mysql:host={$config['host']};dbname={$config['database']}"; + ? "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']}" + : "mysql:host={$config['host']};dbname={$config['database']}"; } /** diff --git a/src/Illuminate/Database/Connectors/SqlServerConnector.php b/src/Illuminate/Database/Connectors/SqlServerConnector.php index b6ed47d196ac..14cb72dbbf41 100755 --- a/src/Illuminate/Database/Connectors/SqlServerConnector.php +++ b/src/Illuminate/Database/Connectors/SqlServerConnector.php @@ -113,7 +113,8 @@ protected function getDblibDsn(array $config) protected function getOdbcDsn(array $config) { return isset($config['odbc_datasource_name']) - ? 'odbc:'.$config['odbc_datasource_name'] : ''; + ? 'odbc:'.$config['odbc_datasource_name'] + : ''; } /** diff --git a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php index 495a33ccd001..6d080a143923 100644 --- a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php +++ b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php @@ -66,8 +66,8 @@ protected function buildClass($name) $factory = class_basename(Str::ucfirst(str_replace('Factory', '', $name))); $namespaceModel = $this->option('model') - ? $this->qualifyModel($this->option('model')) - : $this->qualifyModel($this->guessModelName($name)); + ? $this->qualifyModel($this->option('model')) + : $this->qualifyModel($this->guessModelName($name)); $model = class_basename($namespaceModel); diff --git a/src/Illuminate/Database/Console/Migrations/BaseCommand.php b/src/Illuminate/Database/Console/Migrations/BaseCommand.php index d2a8aee0d9a5..a250d2945fde 100755 --- a/src/Illuminate/Database/Console/Migrations/BaseCommand.php +++ b/src/Illuminate/Database/Console/Migrations/BaseCommand.php @@ -20,8 +20,8 @@ protected function getMigrationPaths() if ($this->input->hasOption('path') && $this->option('path')) { return (new Collection($this->option('path')))->map(function ($path) { return ! $this->usingRealPath() - ? $this->laravel->basePath().'/'.$path - : $path; + ? $this->laravel->basePath().'/'.$path + : $path; })->all(); } diff --git a/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php index 367f14839e64..e3fb4076e476 100644 --- a/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php @@ -125,8 +125,8 @@ protected function getMigrationPath() { if (! is_null($targetPath = $this->input->getOption('path'))) { return ! $this->usingRealPath() - ? $this->laravel->basePath().'/'.$targetPath - : $targetPath; + ? $this->laravel->basePath().'/'.$targetPath + : $targetPath; } return parent::getMigrationPath(); diff --git a/src/Illuminate/Database/DatabaseManager.php b/src/Illuminate/Database/DatabaseManager.php index 34ba2cc01bd9..d3018bcd3db4 100755 --- a/src/Illuminate/Database/DatabaseManager.php +++ b/src/Illuminate/Database/DatabaseManager.php @@ -177,7 +177,8 @@ protected function parseConnectionName($name) $name = $name ?: $this->getDefaultConnection(); return Str::endsWith($name, ['::read', '::write']) - ? explode('::', $name, 2) : [$name, null]; + ? explode('::', $name, 2) + : [$name, null]; } /** diff --git a/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php b/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php index 84eaf9e10582..1887ae8e40dc 100644 --- a/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php +++ b/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php @@ -75,8 +75,8 @@ public function __construct($model, $event) public function broadcastOn() { $channels = empty($this->channels) - ? ($this->model->broadcastOn($this->event) ?: []) - : $this->channels; + ? ($this->model->broadcastOn($this->event) ?: []) + : $this->channels; return (new BaseCollection($channels)) ->map(fn ($channel) => $channel instanceof Model ? new PrivateChannel($channel) : $channel) @@ -93,8 +93,8 @@ public function broadcastAs() $default = class_basename($this->model).ucfirst($this->event); return method_exists($this->model, 'broadcastAs') - ? ($this->model->broadcastAs($this->event) ?: $default) - : $default; + ? ($this->model->broadcastAs($this->event) ?: $default) + : $default; } /** diff --git a/src/Illuminate/Database/Eloquent/BroadcastsEvents.php b/src/Illuminate/Database/Eloquent/BroadcastsEvents.php index f075dbc58322..c0461ddb0afd 100644 --- a/src/Illuminate/Database/Eloquent/BroadcastsEvents.php +++ b/src/Illuminate/Database/Eloquent/BroadcastsEvents.php @@ -130,16 +130,16 @@ public function newBroadcastableModelEvent($event) { return tap($this->newBroadcastableEvent($event), function ($event) { $event->connection = property_exists($this, 'broadcastConnection') - ? $this->broadcastConnection - : $this->broadcastConnection(); + ? $this->broadcastConnection + : $this->broadcastConnection(); $event->queue = property_exists($this, 'broadcastQueue') - ? $this->broadcastQueue - : $this->broadcastQueue(); + ? $this->broadcastQueue + : $this->broadcastQueue(); $event->afterCommit = property_exists($this, 'broadcastAfterCommit') - ? $this->broadcastAfterCommit - : $this->broadcastAfterCommit(); + ? $this->broadcastAfterCommit + : $this->broadcastAfterCommit(); }); } diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 34c31d8e73a1..b01a2b79e4b7 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1505,7 +1505,8 @@ protected function callScope(callable $scope, array $parameters = []) // scope so that we can properly group the added scope constraints in the // query as their own isolated nested where statement and avoid issues. $originalWhereCount = is_null($query->wheres) - ? 0 : count($query->wheres); + ? 0 + : count($query->wheres); $result = $scope(...$parameters) ?? $this; @@ -1779,8 +1780,8 @@ protected function createSelectWithConstraint($name) return [explode(':', $name)[0], static function ($query) use ($name) { $query->select(array_map(static function ($column) use ($query) { return $query instanceof BelongsToMany - ? $query->getRelated()->qualifyColumn($column) - : $column; + ? $query->getRelated()->qualifyColumn($column) + : $column; }, explode(',', explode(':', $name)[1]))); }]; } diff --git a/src/Illuminate/Database/Eloquent/Casts/Json.php b/src/Illuminate/Database/Eloquent/Casts/Json.php index 6b1a3dc77796..11bd16a6d8b8 100644 --- a/src/Illuminate/Database/Eloquent/Casts/Json.php +++ b/src/Illuminate/Database/Eloquent/Casts/Json.php @@ -32,8 +32,8 @@ public static function encode(mixed $value): mixed public static function decode(mixed $value, ?bool $associative = true): mixed { return isset(static::$decoder) - ? (static::$decoder)($value, $associative) - : json_decode($value, $associative); + ? (static::$decoder)($value, $associative) + : json_decode($value, $associative); } /** diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 5e35ad0eea4d..d030a3bc93e9 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -754,8 +754,8 @@ public function getQueueableClass() protected function getQueueableModelClass($model) { return method_exists($model, 'getQueueableClassName') - ? $model->getQueueableClassName() - : get_class($model); + ? $model->getQueueableClassName() + : get_class($model); } /** @@ -770,8 +770,8 @@ public function getQueueableIds() } return $this->first() instanceof QueueableEntity - ? $this->map->getQueueableId()->all() - : $this->modelKeys(); + ? $this->map->getQueueableId()->all() + : $this->modelKeys(); } /** diff --git a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php index 67229b4a0332..6a02def76ea3 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php @@ -76,8 +76,8 @@ public function mergeFillable(array $fillable) public function getGuarded() { return $this->guarded === false - ? [] - : $this->guarded; + ? [] + : $this->guarded; } /** diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index d02f8f617128..c79f3483a4e6 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -482,8 +482,8 @@ public function getAttribute($key) } return $this->isRelation($key) || $this->relationLoaded($key) - ? $this->getRelationValue($key) - : $this->throwMissingAttributeExceptionIfApplicable($key); + ? $this->getRelationValue($key) + : $this->throwMissingAttributeExceptionIfApplicable($key); } /** @@ -744,8 +744,8 @@ protected function mutateAttributeForArray($key, $value) $value = $this->mutateAttributeMarkedAttribute($key, $value); $value = $value instanceof DateTimeInterface - ? $this->serializeDate($value) - : $value; + ? $this->serializeDate($value) + : $value; } else { $value = $this->mutateAttribute($key, $value); } @@ -1250,8 +1250,8 @@ protected function setEnumCastableAttribute($key, $value) protected function getEnumCaseFromValue($enumClass, $value) { return is_subclass_of($enumClass, BackedEnum::class) - ? $enumClass::from($value) - : constant($enumClass.'::'.$value); + ? $enumClass::from($value) + : constant($enumClass.'::'.$value); } /** diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index a484bf01b679..a9a307db549c 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -306,8 +306,8 @@ public function morphTo($name = null, $type = null, $id = null, $ownerKey = null // the relationship. In this case we'll just pass in a dummy query where we // need to remove any eager loads that may already be defined on a model. return is_null($class = $this->getAttributeFromArray($type)) || $class === '' - ? $this->morphEagerTo($name, $type, $id, $ownerKey) - : $this->morphInstanceTo($class, $name, $type, $id, $ownerKey); + ? $this->morphEagerTo($name, $type, $id, $ownerKey) + : $this->morphInstanceTo($class, $name, $type, $id, $ownerKey); } /** diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 58cc93a51b54..01c40915205a 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -53,8 +53,8 @@ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', ? // the subquery to only run a "where exists" clause instead of this full "count" // clause. This will make these queries run much faster compared with a count. $method = $this->canUseExistsForExistenceCheck($operator, $count) - ? 'getRelationExistenceQuery' - : 'getRelationExistenceCountQuery'; + ? 'getRelationExistenceQuery' + : 'getRelationExistenceCountQuery'; $hasQuery = $relation->{$method}( $relation->getRelated()->newQueryWithoutRelationships(), $this @@ -967,8 +967,8 @@ protected function addHasWhere(Builder $hasQuery, Relation $relation, $operator, $hasQuery->mergeConstraintsFrom($relation->getQuery()); return $this->canUseExistsForExistenceCheck($operator, $count) - ? $this->addWhereExistsQuery($hasQuery->toBase(), $boolean, $operator === '<' && $count === 1) - : $this->addWhereCountQuery($hasQuery->toBase(), $operator, $count, $boolean); + ? $this->addWhereExistsQuery($hasQuery->toBase(), $boolean, $operator === '<' && $count === 1) + : $this->addWhereCountQuery($hasQuery->toBase(), $operator, $count, $boolean); } /** diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index 7c7fc743a866..58b00873b307 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -827,8 +827,8 @@ public function modelName() $appNamespace = static::appNamespace(); return class_exists($appNamespace.'Models\\'.$namespacedFactoryBasename) - ? $appNamespace.'Models\\'.$namespacedFactoryBasename - : $appNamespace.$factoryBasename; + ? $appNamespace.'Models\\'.$namespacedFactoryBasename + : $appNamespace.$factoryBasename; }; return $resolver($this); diff --git a/src/Illuminate/Database/Eloquent/MassPrunable.php b/src/Illuminate/Database/Eloquent/MassPrunable.php index e2321343e62a..d9372eb335a4 100644 --- a/src/Illuminate/Database/Eloquent/MassPrunable.php +++ b/src/Illuminate/Database/Eloquent/MassPrunable.php @@ -25,8 +25,8 @@ public function pruneAll(int $chunkSize = 1000) do { $total += $count = in_array(SoftDeletes::class, class_uses_recursive(get_class($this))) - ? $query->forceDelete() - : $query->delete(); + ? $query->forceDelete() + : $query->delete(); if ($count > 0) { event(new ModelsPruned(static::class, $total)); diff --git a/src/Illuminate/Database/Eloquent/Prunable.php b/src/Illuminate/Database/Eloquent/Prunable.php index 737769107191..f36e1dc5c8f9 100644 --- a/src/Illuminate/Database/Eloquent/Prunable.php +++ b/src/Illuminate/Database/Eloquent/Prunable.php @@ -51,8 +51,8 @@ public function prune() $this->pruning(); return in_array(SoftDeletes::class, class_uses_recursive(static::class)) - ? $this->forceDelete() - : $this->delete(); + ? $this->forceDelete() + : $this->delete(); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 5618f0190f51..4ff65b02a9d0 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -868,8 +868,8 @@ public function firstOr($columns = ['*'], ?Closure $callback = null) public function getResults() { return ! is_null($this->parent->{$this->parentKey}) - ? $this->get() - : $this->related->newCollection(); + ? $this->get() + : $this->related->newCollection(); } /** @inheritDoc */ @@ -1651,7 +1651,7 @@ public function qualifyPivotColumn($column) } return str_contains($column, '.') - ? $column - : $this->table.'.'.$column; + ? $column + : $this->table.'.'.$column; } } diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index adbbefcf8c09..015554ed767a 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -356,8 +356,8 @@ protected function formatAttachRecord($key, $value, $attributes, $hasTimestamps) protected function extractAttachIdAndAttributes($key, $value, array $attributes) { return is_array($value) - ? [$key, array_merge($value, $attributes)] - : [$value, $attributes]; + ? [$key, array_merge($value, $attributes)] + : [$value, $attributes]; } /** @@ -671,8 +671,8 @@ protected function castKey($key) protected function castAttributes($attributes) { return $this->using - ? $this->newPivot()->fill($attributes)->getAttributes() - : $attributes; + ? $this->newPivot()->fill($attributes)->getAttributes() + : $attributes; } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/HasMany.php b/src/Illuminate/Database/Eloquent/Relations/HasMany.php index 15b66f56dec6..1337b50246b0 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasMany.php @@ -38,8 +38,8 @@ function ($hasOne) { public function getResults() { return ! is_null($this->getParentKey()) - ? $this->query->get() - : $this->related->newCollection(); + ? $this->query->get() + : $this->related->newCollection(); } /** @inheritDoc */ diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 9f9ba0484d29..b0905f3ae2bb 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -68,7 +68,7 @@ public function match(array $models, EloquentCollection $results, $relation) public function getResults() { return ! is_null($this->farParent->{$this->localKey}) - ? $this->get() - : $this->related->newCollection(); + ? $this->get() + : $this->related->newCollection(); } } diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphMany.php index 86fab64d4e80..fd7830956dda 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphMany.php @@ -39,8 +39,8 @@ function ($morphOne) { public function getResults() { return ! is_null($this->getParentKey()) - ? $this->query->get() - : $this->related->newCollection(); + ? $this->query->get() + : $this->related->newCollection(); } /** @inheritDoc */ diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index cc42984552a1..ffa90acdf1a1 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -176,10 +176,10 @@ protected function getResultsByType($type) protected function gatherKeysByType($type, $keyType) { return $keyType !== 'string' - ? array_keys($this->dictionary[$type]) - : array_map(function ($modelId) { - return (string) $modelId; - }, array_filter(array_keys($this->dictionary[$type]))); + ? array_keys($this->dictionary[$type]) + : array_map(function ($modelId) { + return (string) $modelId; + }, array_filter(array_keys($this->dictionary[$type]))); } /** @@ -237,8 +237,8 @@ public function associate($model) { if ($model instanceof Model) { $foreignKey = $this->ownerKey && $model->{$this->ownerKey} - ? $this->ownerKey - : $model->getKeyName(); + ? $this->ownerKey + : $model->getKeyName(); } $this->parent->setAttribute( diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 157202bccf21..66f3f8e4792d 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -128,9 +128,9 @@ protected function getCurrentlyAttachedPivots() { return parent::getCurrentlyAttachedPivots()->map(function ($record) { return $record instanceof MorphPivot - ? $record->setMorphType($this->morphType) - ->setMorphClass($this->morphClass) - : $record; + ? $record->setMorphType($this->morphType) + ->setMorphClass($this->morphClass) + : $record; }); } diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index e9e431adda51..f6c64aeac1bc 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -172,8 +172,8 @@ abstract public function getResults(); public function getEager() { return $this->eagerKeysWereEmpty - ? $this->query->getModel()->newCollection() - : $this->get(); + ? $this->query->getModel()->newCollection() + : $this->get(); } /** @@ -424,9 +424,9 @@ protected function whereInEager(string $whereIn, string $key, array $modelKeys, protected function whereInMethod(Model $model, $key) { return $model->getKeyName() === last(explode('.', $key)) - && in_array($model->getKeyType(), ['int', 'integer']) - ? 'whereIntegerInRaw' - : 'whereIn'; + && in_array($model->getKeyType(), ['int', 'integer']) + ? 'whereIntegerInRaw' + : 'whereIn'; } /** @@ -477,7 +477,8 @@ public static function morphMap(?array $map = null, $merge = true) if (is_array($map)) { static::$morphMap = $merge && static::$morphMap - ? $map + static::$morphMap : $map; + ? $map + static::$morphMap + : $map; } return static::$morphMap; diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 4ff5ddc34a17..8b326ca22a98 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -144,8 +144,8 @@ protected function wrapSegments($segments) { return (new Collection($segments))->map(function ($segment, $key) use ($segments) { return $key == 0 && count($segments) > 1 - ? $this->wrapTable($segment) - : $this->wrapValue($segment); + ? $this->wrapTable($segment) + : $this->wrapValue($segment); })->implode('.'); } diff --git a/src/Illuminate/Database/Migrations/MigrationCreator.php b/src/Illuminate/Database/Migrations/MigrationCreator.php index d8f1ce9d0b1e..8cd08674c536 100755 --- a/src/Illuminate/Database/Migrations/MigrationCreator.php +++ b/src/Illuminate/Database/Migrations/MigrationCreator.php @@ -114,16 +114,16 @@ protected function getStub($table, $create) { if (is_null($table)) { $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.stub') - ? $customPath - : $this->stubPath().'/migration.stub'; + ? $customPath + : $this->stubPath().'/migration.stub'; } elseif ($create) { $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.create.stub') - ? $customPath - : $this->stubPath().'/migration.create.stub'; + ? $customPath + : $this->stubPath().'/migration.create.stub'; } else { $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.update.stub') - ? $customPath - : $this->stubPath().'/migration.update.stub'; + ? $customPath + : $this->stubPath().'/migration.update.stub'; } return $this->files->get($stub); diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index eb97a6c51a5b..1d47edea85d0 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -437,8 +437,8 @@ protected function runMigration($migration, $method) $this->getSchemaGrammar($connection)->supportsSchemaTransactions() && $migration->withinTransaction - ? $connection->transaction($callback) - : $callback(); + ? $connection->transaction($callback) + : $callback(); } /** @@ -541,8 +541,8 @@ protected function resolvePath(string $path) if (is_object($migration)) { return method_exists($migration, '__construct') - ? $this->files->getRequire($path) - : clone $migration; + ? $this->files->getRequire($path) + : clone $migration; } return new $class; diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index b9ccfa6ead1a..03e78cd3bd61 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2852,7 +2852,8 @@ protected function removeExistingOrdersFor($column) return (new Collection($this->orders)) ->reject(function ($order) use ($column) { return isset($order['column']) - ? $order['column'] === $column : false; + ? $order['column'] === $column + : false; })->values()->all(); } @@ -3305,7 +3306,7 @@ protected function withoutSelectAliases(array $columns) { return array_map(function ($column) { return is_string($column) && ($aliasPosition = stripos($column, ' as ')) !== false - ? substr($column, 0, $aliasPosition) : $column; + ? substr($column, 0, $aliasPosition) : $column; }, $columns); } @@ -3377,8 +3378,8 @@ function () { return $this->applyAfterQueryCallbacks( is_array($queryResult[0]) - ? $this->pluckFromArrayColumn($queryResult, $column, $key) - : $this->pluckFromObjectColumn($queryResult, $column, $key) + ? $this->pluckFromArrayColumn($queryResult, $column, $key) + : $this->pluckFromObjectColumn($queryResult, $column, $key) ); } @@ -3633,7 +3634,7 @@ public function numericAggregate($function, $columns = ['*']) // cast it to one. When it does we will cast it to a float since it needs to be // cast to the expected data type for the developers out of pure convenience. return ! str_contains((string) $result, '.') - ? (int) $result : (float) $result; + ? (int) $result : (float) $result; } /** @@ -4070,8 +4071,8 @@ protected function forSubQuery() public function getColumns() { return ! is_null($this->columns) - ? array_map(fn ($column) => $this->grammar->getValue($column), $this->columns) - : []; + ? array_map(fn ($column) => $this->grammar->getValue($column), $this->columns) + : []; } /** diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index e3983855e6b5..9fb8d8a31589 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -161,8 +161,8 @@ protected function dateBasedWhere($type, Builder $query, $where) protected function compileIndexHint(Builder $query, $indexHint) { return $indexHint->type === 'force' - ? "indexed by {$indexHint->index}" - : ''; + ? "indexed by {$indexHint->index}" + : ''; } /** diff --git a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php index 0b2dd381c1ab..c5e91c50e1bf 100755 --- a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php @@ -114,8 +114,8 @@ protected function compileFrom(Builder $query, $table) protected function compileIndexHint(Builder $query, $indexHint) { return $indexHint->type === 'force' - ? "with (index({$indexHint->index}))" - : ''; + ? "with (index({$indexHint->index}))" + : ''; } /** @@ -281,8 +281,8 @@ protected function compileDeleteWithoutJoins(Builder $query, $table, $where) $sql = parent::compileDeleteWithoutJoins($query, $table, $where); return ! is_null($query->limit) && $query->limit > 0 && $query->offset <= 0 - ? Str::replaceFirst('delete', 'delete top ('.$query->limit.')', $sql) - : $sql; + ? Str::replaceFirst('delete', 'delete top ('.$query->limit.')', $sql) + : $sql; } /** diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index 92ccf334ad86..5bbfc3a79d0a 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -482,8 +482,8 @@ protected function getDefaultValue($value) } return is_bool($value) - ? "'".(int) $value."'" - : "'".(string) $value."'"; + ? "'".(int) $value."'" + : "'".(string) $value."'"; } /** diff --git a/src/Illuminate/Database/Schema/MySqlSchemaState.php b/src/Illuminate/Database/Schema/MySqlSchemaState.php index be5e227359f3..30729f1ef2e8 100644 --- a/src/Illuminate/Database/Schema/MySqlSchemaState.php +++ b/src/Illuminate/Database/Schema/MySqlSchemaState.php @@ -108,8 +108,8 @@ protected function connectionString() $config = $this->connection->getConfig(); $value .= $config['unix_socket'] ?? false - ? ' --socket="${:LARAVEL_LOAD_SOCKET}"' - : ' --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}"'; + ? ' --socket="${:LARAVEL_LOAD_SOCKET}"' + : ' --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}"'; if (isset($config['options'][\PDO::MYSQL_ATTR_SSL_CA])) { $value .= ' --ssl-ca="${:LARAVEL_LOAD_SSL_CA}"'; diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 5a3c9702e198..181ed211b461 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -344,7 +344,7 @@ protected function shouldBroadcast(array $payload) protected function broadcastWhen($event) { return method_exists($event, 'broadcastWhen') - ? $event->broadcastWhen() : true; + ? $event->broadcastWhen() : true; } /** @@ -372,8 +372,8 @@ public function getListeners($eventName) ); return class_exists($eventName, false) - ? $this->addInterfaceListeners($eventName, $listeners) - : $listeners; + ? $this->addInterfaceListeners($eventName, $listeners) + : $listeners; } /** @@ -489,8 +489,8 @@ public function createClassListener($listener, $wildcard = false) protected function createClassCallable($listener) { [$class, $method] = is_array($listener) - ? $listener - : $this->parseClassCallable($listener); + ? $listener + : $this->parseClassCallable($listener); if (! method_exists($class, $method)) { $method = '__invoke'; @@ -503,8 +503,8 @@ protected function createClassCallable($listener) $listener = $this->container->make($class); return $this->handlerShouldBeDispatchedAfterDatabaseTransactions($listener) - ? $this->createCallbackForListenerRunningAfterCommits($listener, $method) - : [$listener, $method]; + ? $this->createCallbackForListenerRunningAfterCommits($listener, $method) + : [$listener, $method]; } /** diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 46e23072c58d..234d19abfc97 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -398,8 +398,8 @@ protected function fallbackName($name) public function put($path, $contents, $options = []) { $options = is_string($options) - ? ['visibility' => $options] - : (array) $options; + ? ['visibility' => $options] + : (array) $options; // If the given contents is actually a file or uploaded file instance than we will // automatically store the file using a stream. This provides a convenient path @@ -753,8 +753,8 @@ public function url($path) protected function getFtpUrl($path) { return isset($this->config['url']) - ? $this->concatPathToUrl($this->config['url'], $path) - : $path; + ? $this->concatPathToUrl($this->config['url'], $path) + : $path; } /** diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 4a067367c0ce..9a4f77c49956 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -424,14 +424,14 @@ protected function bindPathsInContainer() $this->useBootstrapPath(value(function () { return is_dir($directory = $this->basePath('.laravel')) - ? $directory - : $this->basePath('bootstrap'); + ? $directory + : $this->basePath('bootstrap'); })); $this->useLangPath(value(function () { return is_dir($directory = $this->resourcePath('lang')) - ? $directory - : $this->basePath('lang'); + ? $directory + : $this->basePath('lang'); })); } @@ -1369,8 +1369,8 @@ protected function normalizeCachePath($key, $default) } return Str::startsWith($env, $this->absoluteCachePathPrefixes) - ? $env - : $this->basePath($env); + ? $env + : $this->basePath($env); } /** diff --git a/src/Illuminate/Foundation/Bus/PendingChain.php b/src/Illuminate/Foundation/Bus/PendingChain.php index f1935e2b6e48..5e02eb8a0ee1 100644 --- a/src/Illuminate/Foundation/Bus/PendingChain.php +++ b/src/Illuminate/Foundation/Bus/PendingChain.php @@ -117,8 +117,8 @@ public function delay($delay) public function catch($callback) { $this->catchCallbacks[] = $callback instanceof Closure - ? new SerializableClosure($callback) - : $callback; + ? new SerializableClosure($callback) + : $callback; return $this; } diff --git a/src/Illuminate/Foundation/Console/CastMakeCommand.php b/src/Illuminate/Foundation/Console/CastMakeCommand.php index 9552472aea6f..b262b40fe396 100644 --- a/src/Illuminate/Foundation/Console/CastMakeCommand.php +++ b/src/Illuminate/Foundation/Console/CastMakeCommand.php @@ -38,8 +38,8 @@ class CastMakeCommand extends GeneratorCommand protected function getStub() { return $this->option('inbound') - ? $this->resolveStubPath('/stubs/cast.inbound.stub') - : $this->resolveStubPath('/stubs/cast.stub'); + ? $this->resolveStubPath('/stubs/cast.inbound.stub') + : $this->resolveStubPath('/stubs/cast.stub'); } /** diff --git a/src/Illuminate/Foundation/Console/ComponentMakeCommand.php b/src/Illuminate/Foundation/Console/ComponentMakeCommand.php index 4c2f2eac81ad..221ef95caecb 100644 --- a/src/Illuminate/Foundation/Console/ComponentMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ComponentMakeCommand.php @@ -154,8 +154,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/EnumMakeCommand.php b/src/Illuminate/Foundation/Console/EnumMakeCommand.php index a7cfb87c9318..fab08bb9433a 100644 --- a/src/Illuminate/Foundation/Console/EnumMakeCommand.php +++ b/src/Illuminate/Foundation/Console/EnumMakeCommand.php @@ -57,8 +57,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php b/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php index 37829f0d2571..945d0781b389 100644 --- a/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php +++ b/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php @@ -77,8 +77,8 @@ public function handle() $key = $this->parseKey($key); $encryptedFile = ($this->option('env') - ? Str::finish(dirname($this->laravel->environmentFilePath()), DIRECTORY_SEPARATOR).'.env.'.$this->option('env') - : $this->laravel->environmentFilePath()).'.encrypted'; + ? Str::finish(dirname($this->laravel->environmentFilePath()), DIRECTORY_SEPARATOR).'.env.'.$this->option('env') + : $this->laravel->environmentFilePath()).'.encrypted'; $outputFile = $this->outputFilePath(); diff --git a/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php b/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php index 03cafa97760c..1cbfbd59841c 100644 --- a/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php +++ b/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php @@ -83,8 +83,8 @@ public function handle() $keyPassed = $key !== null; $environmentFile = $this->option('env') - ? Str::finish(dirname($this->laravel->environmentFilePath()), DIRECTORY_SEPARATOR).'.env.'.$this->option('env') - : $this->laravel->environmentFilePath(); + ? Str::finish(dirname($this->laravel->environmentFilePath()), DIRECTORY_SEPARATOR).'.env.'.$this->option('env') + : $this->laravel->environmentFilePath(); $encryptedFile = $environmentFile.'.encrypted'; diff --git a/src/Illuminate/Foundation/Console/EventMakeCommand.php b/src/Illuminate/Foundation/Console/EventMakeCommand.php index cdecc89fb0ad..515c6fbd8c43 100644 --- a/src/Illuminate/Foundation/Console/EventMakeCommand.php +++ b/src/Illuminate/Foundation/Console/EventMakeCommand.php @@ -61,8 +61,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/JobMakeCommand.php b/src/Illuminate/Foundation/Console/JobMakeCommand.php index 39236c8e504e..9f0f1b0e9ffc 100644 --- a/src/Illuminate/Foundation/Console/JobMakeCommand.php +++ b/src/Illuminate/Foundation/Console/JobMakeCommand.php @@ -41,8 +41,8 @@ class JobMakeCommand extends GeneratorCommand protected function getStub() { return $this->option('sync') - ? $this->resolveStubPath('/stubs/job.stub') - : $this->resolveStubPath('/stubs/job.queued.stub'); + ? $this->resolveStubPath('/stubs/job.stub') + : $this->resolveStubPath('/stubs/job.queued.stub'); } /** @@ -54,8 +54,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/JobMiddlewareMakeCommand.php b/src/Illuminate/Foundation/Console/JobMiddlewareMakeCommand.php index b3ccf8e45ce4..5f94b835956f 100644 --- a/src/Illuminate/Foundation/Console/JobMiddlewareMakeCommand.php +++ b/src/Illuminate/Foundation/Console/JobMiddlewareMakeCommand.php @@ -52,8 +52,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php index d5589ece59a9..a2d2dfaa5535 100644 --- a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php @@ -74,8 +74,8 @@ protected function buildClass($name) protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** @@ -87,13 +87,13 @@ protected function getStub() { if ($this->option('queued')) { return $this->option('event') - ? $this->resolveStubPath('/stubs/listener.typed.queued.stub') - : $this->resolveStubPath('/stubs/listener.queued.stub'); + ? $this->resolveStubPath('/stubs/listener.typed.queued.stub') + : $this->resolveStubPath('/stubs/listener.queued.stub'); } return $this->option('event') - ? $this->resolveStubPath('/stubs/listener.typed.stub') - : $this->resolveStubPath('/stubs/listener.stub'); + ? $this->resolveStubPath('/stubs/listener.typed.stub') + : $this->resolveStubPath('/stubs/listener.stub'); } /** diff --git a/src/Illuminate/Foundation/Console/ModelMakeCommand.php b/src/Illuminate/Foundation/Console/ModelMakeCommand.php index 743fd170f9fa..5fd029b8cad8 100644 --- a/src/Illuminate/Foundation/Console/ModelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ModelMakeCommand.php @@ -211,8 +211,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php index a48eefe2c30d..521c135b062b 100644 --- a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php +++ b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php @@ -161,8 +161,8 @@ protected function replaceModel($stub, $model) protected function getStub() { return $this->option('model') - ? $this->resolveStubPath('/stubs/policy.stub') - : $this->resolveStubPath('/stubs/policy.plain.stub'); + ? $this->resolveStubPath('/stubs/policy.stub') + : $this->resolveStubPath('/stubs/policy.plain.stub'); } /** @@ -174,8 +174,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/RequestMakeCommand.php b/src/Illuminate/Foundation/Console/RequestMakeCommand.php index ad02e29f175e..a60b0c69728a 100644 --- a/src/Illuminate/Foundation/Console/RequestMakeCommand.php +++ b/src/Illuminate/Foundation/Console/RequestMakeCommand.php @@ -49,8 +49,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/ResourceMakeCommand.php b/src/Illuminate/Foundation/Console/ResourceMakeCommand.php index e8fd022568eb..51d96120cc00 100644 --- a/src/Illuminate/Foundation/Console/ResourceMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ResourceMakeCommand.php @@ -52,8 +52,8 @@ public function handle() protected function getStub() { return $this->collection() - ? $this->resolveStubPath('/stubs/resource-collection.stub') - : $this->resolveStubPath('/stubs/resource.stub'); + ? $this->resolveStubPath('/stubs/resource-collection.stub') + : $this->resolveStubPath('/stubs/resource.stub'); } /** @@ -76,8 +76,8 @@ protected function collection() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/TestMakeCommand.php b/src/Illuminate/Foundation/Console/TestMakeCommand.php index 85440589f52d..e24766a9021c 100644 --- a/src/Illuminate/Foundation/Console/TestMakeCommand.php +++ b/src/Illuminate/Foundation/Console/TestMakeCommand.php @@ -58,8 +58,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Console/ViewMakeCommand.php b/src/Illuminate/Foundation/Console/ViewMakeCommand.php index afd21e9bc456..c06675041373 100644 --- a/src/Illuminate/Foundation/Console/ViewMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ViewMakeCommand.php @@ -104,8 +104,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 52f10c379ee7..f79734bdb8e2 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -702,8 +702,8 @@ protected function renderViaCallbacks($request, Throwable $e) protected function renderExceptionResponse($request, Throwable $e) { return $this->shouldReturnJson($request, $e) - ? $this->prepareJsonResponse($request, $e) - : $this->prepareResponse($request, $e); + ? $this->prepareJsonResponse($request, $e) + : $this->prepareResponse($request, $e); } /** @@ -716,8 +716,8 @@ protected function renderExceptionResponse($request, Throwable $e) protected function unauthenticated($request, AuthenticationException $exception) { return $this->shouldReturnJson($request, $exception) - ? response()->json(['message' => $exception->getMessage()], 401) - : redirect()->guest($exception->redirectTo($request) ?? route('login')); + ? response()->json(['message' => $exception->getMessage()], 401) + : redirect()->guest($exception->redirectTo($request) ?? route('login')); } /** @@ -734,8 +734,8 @@ protected function convertValidationExceptionToResponse(ValidationException $e, } return $this->shouldReturnJson($request, $e) - ? $this->invalidJson($request, $e) - : $this->invalid($request, $e); + ? $this->invalidJson($request, $e) + : $this->invalid($request, $e); } /** diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 268c57e1a91f..b5beb3af52f2 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -229,8 +229,8 @@ protected function failedAuthorization() public function safe(?array $keys = null) { return is_array($keys) - ? $this->validator->safe()->only($keys) - : $this->validator->safe(); + ? $this->validator->safe()->only($keys) + : $this->validator->safe(); } /** diff --git a/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php b/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php index 6adb87d01161..1f0b22981e5a 100644 --- a/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php +++ b/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php @@ -83,8 +83,8 @@ public function handle($request, Closure $next) if (isset($data['redirect'])) { $path = $data['redirect'] === '/' - ? $data['redirect'] - : trim($data['redirect'], '/'); + ? $data['redirect'] + : trim($data['redirect'], '/'); if ($request->path() !== $path) { return redirect($path); diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 788d6ed54b4b..d5074505302d 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -124,8 +124,8 @@ public function getEvents() protected function discoveredEvents() { return $this->shouldDiscoverEvents() - ? $this->discoverEvents() - : []; + ? $this->discoverEvents() + : []; } /** diff --git a/src/Illuminate/Foundation/Testing/DatabaseTransactions.php b/src/Illuminate/Foundation/Testing/DatabaseTransactions.php index f84a23fe51d4..0eaa2f079457 100644 --- a/src/Illuminate/Foundation/Testing/DatabaseTransactions.php +++ b/src/Illuminate/Foundation/Testing/DatabaseTransactions.php @@ -48,6 +48,7 @@ public function beginDatabaseTransaction() protected function connectionsToTransact() { return property_exists($this, 'connectionsToTransact') - ? $this->connectionsToTransact : [null]; + ? $this->connectionsToTransact + : [null]; } } diff --git a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php index b72c3150c762..b679466f4eba 100644 --- a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php +++ b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php @@ -141,7 +141,7 @@ protected function tableExistsIn(array $table, array $tables): bool protected function connectionsToTruncate(): array { return property_exists($this, 'connectionsToTruncate') - ? $this->connectionsToTruncate : [null]; + ? $this->connectionsToTruncate : [null]; } /** diff --git a/src/Illuminate/Foundation/Testing/RefreshDatabase.php b/src/Illuminate/Foundation/Testing/RefreshDatabase.php index 245601bac916..f039c510f8c2 100644 --- a/src/Illuminate/Foundation/Testing/RefreshDatabase.php +++ b/src/Illuminate/Foundation/Testing/RefreshDatabase.php @@ -156,7 +156,8 @@ public function beginDatabaseTransaction() protected function connectionsToTransact() { return property_exists($this, 'connectionsToTransact') - ? $this->connectionsToTransact : [config('database.default')]; + ? $this->connectionsToTransact + : [config('database.default')]; } /** diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 90fd06f44f0d..590ea00e7efa 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -424,8 +424,8 @@ function defer(?callable $callback = null, ?string $name = null, bool $always = function dispatch($job) { return $job instanceof Closure - ? new PendingClosureDispatch(CallQueuedClosure::create($job)) - : new PendingDispatch($job); + ? new PendingClosureDispatch(CallQueuedClosure::create($job)) + : new PendingDispatch($job); } } diff --git a/src/Illuminate/Http/Client/Response.php b/src/Illuminate/Http/Client/Response.php index ac51d9c7ade8..97a6cacea7c3 100644 --- a/src/Illuminate/Http/Client/Response.php +++ b/src/Illuminate/Http/Client/Response.php @@ -527,7 +527,7 @@ public function __toString() public function __call($method, $parameters) { return static::hasMacro($method) - ? $this->macroCall($method, $parameters) - : $this->response->{$method}(...$parameters); + ? $this->macroCall($method, $parameters) + : $this->response->{$method}(...$parameters); } } diff --git a/src/Illuminate/Http/Concerns/InteractsWithInput.php b/src/Illuminate/Http/Concerns/InteractsWithInput.php index 1435a8ad541e..3cbeb947de7a 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithInput.php +++ b/src/Illuminate/Http/Concerns/InteractsWithInput.php @@ -198,8 +198,8 @@ protected function convertUploadedFiles(array $files) } return is_array($file) - ? $this->convertUploadedFiles($file) - : UploadedFile::createFromBase($file); + ? $this->convertUploadedFiles($file) + : UploadedFile::createFromBase($file); }, $files); } diff --git a/src/Illuminate/Http/Middleware/TrustProxies.php b/src/Illuminate/Http/Middleware/TrustProxies.php index 6b1b6765dc43..1dcaf1b81387 100644 --- a/src/Illuminate/Http/Middleware/TrustProxies.php +++ b/src/Illuminate/Http/Middleware/TrustProxies.php @@ -77,8 +77,8 @@ protected function setTrustedProxyIpAddresses(Request $request) } $trustedIps = is_string($trustedIps) - ? array_map(trim(...), explode(',', $trustedIps)) - : $trustedIps; + ? array_map(trim(...), explode(',', $trustedIps)) + : $trustedIps; if (is_array($trustedIps)) { return $this->setTrustedProxyIpAddressesToSpecificIps($request, $trustedIps); diff --git a/src/Illuminate/Http/Resources/CollectsResources.php b/src/Illuminate/Http/Resources/CollectsResources.php index c1bad66733c8..08ec46b52e39 100644 --- a/src/Illuminate/Http/Resources/CollectsResources.php +++ b/src/Illuminate/Http/Resources/CollectsResources.php @@ -36,8 +36,8 @@ protected function collectResource($resource) : $resource->toBase(); return ($resource instanceof AbstractPaginator || $resource instanceof AbstractCursorPaginator) - ? $resource->setCollection($this->collection) - : $this->collection; + ? $resource->setCollection($this->collection) + : $this->collection; } /** diff --git a/src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php b/src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php index 0fc456870e67..16e026986484 100644 --- a/src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php +++ b/src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php @@ -199,8 +199,8 @@ public function whenHas($attribute, $value = null, $default = null) } return func_num_args() === 1 - ? $this->resource->{$attribute} - : value($value, $this->resource->{$attribute}); + ? $this->resource->{$attribute} + : value($value, $this->resource->{$attribute}); } /** diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index 330a13ecaf42..e6589e8827f8 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -365,8 +365,8 @@ protected function createPostmarkTransport(array $config) $factory = new PostmarkTransportFactory(null, $this->getHttpClient($config)); $options = isset($config['message_stream_id']) - ? ['message_stream' => $config['message_stream_id']] - : []; + ? ['message_stream' => $config['message_stream_id']] + : []; return $factory->create(new Dsn( 'postmark+api', diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 925cb032f9b0..afac565ec7a8 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -200,8 +200,8 @@ public function send($mailer) $this->prepareMailableForDelivery(); $mailer = $mailer instanceof MailFactory - ? $mailer->mailer($this->mailer) - : $mailer; + ? $mailer->mailer($this->mailer) + : $mailer; return $mailer->send($this->buildView(), $this->buildViewData(), function ($message) { $this->buildFrom($message) diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index bd6484f3ea67..864f09b45270 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -350,8 +350,8 @@ public function send($view, array $data = [], $callback = null) protected function sendMailable(MailableContract $mailable) { return $mailable instanceof ShouldQueue - ? $mailable->mailer($this->name)->queue($this->queue) - : $mailable->mailer($this->name)->send($this); + ? $mailable->mailer($this->name)->queue($this->queue) + : $mailable->mailer($this->name)->send($this); } /** @@ -441,8 +441,8 @@ protected function renderView($view, $data) $view = value($view, $data); return $view instanceof Htmlable - ? $view->toHtml() - : $this->views->make($view, $data)->render(); + ? $view->toHtml() + : $this->views->make($view, $data)->render(); } /** diff --git a/src/Illuminate/Notifications/Channels/DatabaseChannel.php b/src/Illuminate/Notifications/Channels/DatabaseChannel.php index 8e341c217683..dcfb891382b6 100644 --- a/src/Illuminate/Notifications/Channels/DatabaseChannel.php +++ b/src/Illuminate/Notifications/Channels/DatabaseChannel.php @@ -33,12 +33,12 @@ protected function buildPayload($notifiable, Notification $notification) return [ 'id' => $notification->id, 'type' => method_exists($notification, 'databaseType') - ? $notification->databaseType($notifiable) - : get_class($notification), + ? $notification->databaseType($notifiable) + : get_class($notification), 'data' => $this->getData($notifiable, $notification), 'read_at' => method_exists($notification, 'initialDatabaseReadAtValue') - ? $notification->initialDatabaseReadAtValue($notifiable) - : null, + ? $notification->initialDatabaseReadAtValue($notifiable) + : null, ]; } @@ -55,7 +55,8 @@ protected function getData($notifiable, Notification $notification) { if (method_exists($notification, 'toDatabase')) { return is_array($data = $notification->toDatabase($notifiable)) - ? $data : $data->data; + ? $data + : $data->data; } if (method_exists($notification, 'toArray')) { diff --git a/src/Illuminate/Notifications/Channels/MailChannel.php b/src/Illuminate/Notifications/Channels/MailChannel.php index fcfa5af02c66..f11016ddb1c6 100644 --- a/src/Illuminate/Notifications/Channels/MailChannel.php +++ b/src/Illuminate/Notifications/Channels/MailChannel.php @@ -265,8 +265,8 @@ protected function getRecipients($notifiable, $notification, $message) return (new Collection($recipients))->mapWithKeys(function ($recipient, $email) { return is_numeric($email) - ? [$email => (is_string($recipient) ? $recipient : $recipient->email)] - : [$email => $recipient]; + ? [$email => (is_string($recipient) ? $recipient : $recipient->email)] + : [$email => $recipient]; })->all(); } diff --git a/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php b/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php index 2ee62c66b417..43f205e3efb0 100644 --- a/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php +++ b/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php @@ -97,8 +97,8 @@ public function broadcastWith() public function broadcastType() { return method_exists($this->notification, 'broadcastType') - ? $this->notification->broadcastType() - : get_class($this->notification); + ? $this->notification->broadcastType() + : get_class($this->notification); } /** @@ -109,7 +109,7 @@ public function broadcastType() public function broadcastAs() { return method_exists($this->notification, 'broadcastAs') - ? $this->notification->broadcastAs() - : __CLASS__; + ? $this->notification->broadcastAs() + : __CLASS__; } } diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index cea407f70b9a..ed08deac0e0e 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -247,7 +247,8 @@ protected function formatNotifiables($notifiables) { if (! $notifiables instanceof Collection && ! is_array($notifiables)) { return $notifiables instanceof Model - ? new EloquentCollection([$notifiables]) : [$notifiables]; + ? new EloquentCollection([$notifiables]) + : [$notifiables]; } return $notifiables; diff --git a/src/Illuminate/Pagination/AbstractCursorPaginator.php b/src/Illuminate/Pagination/AbstractCursorPaginator.php index 87a087983aad..850f8b7fe0f9 100644 --- a/src/Illuminate/Pagination/AbstractCursorPaginator.php +++ b/src/Illuminate/Pagination/AbstractCursorPaginator.php @@ -265,8 +265,8 @@ protected function getPivotParameterForItem($item, $parameterName) protected function ensureParameterIsPrimitive($parameter) { return is_object($parameter) && method_exists($parameter, '__toString') - ? (string) $parameter - : $parameter; + ? (string) $parameter + : $parameter; } /** diff --git a/src/Illuminate/Pipeline/Pipeline.php b/src/Illuminate/Pipeline/Pipeline.php index 6a9f0029735e..28f2b4084a2c 100644 --- a/src/Illuminate/Pipeline/Pipeline.php +++ b/src/Illuminate/Pipeline/Pipeline.php @@ -206,8 +206,8 @@ protected function carry() } $carry = method_exists($pipe, $this->method) - ? $pipe->{$this->method}(...$parameters) - : $pipe(...$parameters); + ? $pipe->{$this->method}(...$parameters) + : $pipe(...$parameters); return $this->handleCarry($carry); } catch (Throwable $e) { diff --git a/src/Illuminate/Process/Factory.php b/src/Illuminate/Process/Factory.php index b37246a8d75d..e30fa8c6c99f 100644 --- a/src/Illuminate/Process/Factory.php +++ b/src/Illuminate/Process/Factory.php @@ -104,8 +104,8 @@ public function fake(Closure|array|null $callback = null) foreach ($callback as $command => $handler) { $this->fakeHandlers[is_numeric($command) ? '*' : $command] = $handler instanceof Closure - ? $handler - : fn () => $handler; + ? $handler + : fn () => $handler; } return $this; diff --git a/src/Illuminate/Process/FakeInvokedProcess.php b/src/Illuminate/Process/FakeInvokedProcess.php index c82f53c869d1..c74928e77c18 100644 --- a/src/Illuminate/Process/FakeInvokedProcess.php +++ b/src/Illuminate/Process/FakeInvokedProcess.php @@ -116,8 +116,8 @@ public function running() $this->invokeOutputHandlerWithNextLineOfOutput(); $this->remainingRunIterations = is_null($this->remainingRunIterations) - ? $this->process->runIterations - : $this->remainingRunIterations; + ? $this->process->runIterations + : $this->remainingRunIterations; if ($this->remainingRunIterations === 0) { while ($this->invokeOutputHandlerWithNextLineOfOutput()) { diff --git a/src/Illuminate/Process/FakeProcessDescription.php b/src/Illuminate/Process/FakeProcessDescription.php index b6a7f7a16a8d..fdf6dc18cdba 100644 --- a/src/Illuminate/Process/FakeProcessDescription.php +++ b/src/Illuminate/Process/FakeProcessDescription.php @@ -205,8 +205,8 @@ protected function resolveOutput() ->filter(fn ($output) => $output['type'] === 'out'); return $output->isNotEmpty() - ? rtrim($output->map->buffer->implode(''), "\n")."\n" - : ''; + ? rtrim($output->map->buffer->implode(''), "\n")."\n" + : ''; } /** @@ -220,7 +220,7 @@ protected function resolveErrorOutput() ->filter(fn ($output) => $output['type'] === 'err'); return $output->isNotEmpty() - ? rtrim($output->map->buffer->implode(''), "\n")."\n" - : ''; + ? rtrim($output->map->buffer->implode(''), "\n")."\n" + : ''; } } diff --git a/src/Illuminate/Process/FakeProcessSequence.php b/src/Illuminate/Process/FakeProcessSequence.php index f039ec37d4dc..02f9f4623777 100644 --- a/src/Illuminate/Process/FakeProcessSequence.php +++ b/src/Illuminate/Process/FakeProcessSequence.php @@ -75,8 +75,8 @@ public function whenEmpty(ProcessResultContract|FakeProcessDescription|array|str protected function toProcessResult(ProcessResultContract|FakeProcessDescription|array|string $process) { return is_array($process) || is_string($process) - ? new FakeProcessResult(output: $process) - : $process; + ? new FakeProcessResult(output: $process) + : $process; } /** diff --git a/src/Illuminate/Process/PendingProcess.php b/src/Illuminate/Process/PendingProcess.php index 454513fd1996..3ce34e6222a7 100644 --- a/src/Illuminate/Process/PendingProcess.php +++ b/src/Illuminate/Process/PendingProcess.php @@ -299,8 +299,8 @@ protected function toSymfonyProcess(array|string|null $command) $command = $command ?? $this->command; $process = is_iterable($command) - ? new Process($command, null, $this->environment) - : Process::fromShellCommandline((string) $command, null, $this->environment); + ? new Process($command, null, $this->environment) + : Process::fromShellCommandline((string) $command, null, $this->environment); $process->setWorkingDirectory((string) ($this->path ?? getcwd())); $process->setTimeout($this->timeout); diff --git a/src/Illuminate/Queue/CallQueuedClosure.php b/src/Illuminate/Queue/CallQueuedClosure.php index 58155523b283..cdf5435171b6 100644 --- a/src/Illuminate/Queue/CallQueuedClosure.php +++ b/src/Illuminate/Queue/CallQueuedClosure.php @@ -78,8 +78,8 @@ public function handle(Container $container) public function onFailure($callback) { $this->failureCallbacks[] = $callback instanceof Closure - ? new SerializableClosure($callback) - : $callback; + ? new SerializableClosure($callback) + : $callback; return $this; } diff --git a/src/Illuminate/Queue/Console/ClearCommand.php b/src/Illuminate/Queue/Console/ClearCommand.php index 8f4187bcac77..2ed23ffff590 100644 --- a/src/Illuminate/Queue/Console/ClearCommand.php +++ b/src/Illuminate/Queue/Console/ClearCommand.php @@ -42,7 +42,7 @@ public function handle() } $connection = $this->argument('connection') - ?: $this->laravel['config']['queue.default']; + ?: $this->laravel['config']['queue.default']; // We need to get the right queue for the connection which is set in the queue // configuration file for the application. We will pull it based on the set diff --git a/src/Illuminate/Queue/Console/ListenCommand.php b/src/Illuminate/Queue/Console/ListenCommand.php index 54bbfd5dca49..9f1b4f7d5a9f 100755 --- a/src/Illuminate/Queue/Console/ListenCommand.php +++ b/src/Illuminate/Queue/Console/ListenCommand.php @@ -100,8 +100,8 @@ protected function getQueue($connection) protected function gatherOptions() { $backoff = $this->hasOption('backoff') - ? $this->option('backoff') - : $this->option('delay'); + ? $this->option('backoff') + : $this->option('delay'); return new ListenerOptions( name: $this->option('name'), diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index 8e0cc2fe5044..d67553803704 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -194,8 +194,8 @@ protected function refreshRetryUntil($payload) $retryUntil = $instance->retryUntil(); $payload['retryUntil'] = $retryUntil instanceof DateTimeInterface - ? $retryUntil->getTimestamp() - : $retryUntil; + ? $retryUntil->getTimestamp() + : $retryUntil; } return json_encode($payload); diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index ace855f789a8..09a45544b071 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -116,7 +116,7 @@ public function handle() $this->listenForEvents(); $connection = $this->argument('connection') - ?: $this->laravel['config']['queue.default']; + ?: $this->laravel['config']['queue.default']; // We need to get the right queue for the connection which is set in the queue // configuration file for the application. We will pull it based on the set diff --git a/src/Illuminate/Queue/Middleware/RateLimited.php b/src/Illuminate/Queue/Middleware/RateLimited.php index e6309ba4317c..8612c634a8ef 100644 --- a/src/Illuminate/Queue/Middleware/RateLimited.php +++ b/src/Illuminate/Queue/Middleware/RateLimited.php @@ -90,8 +90,8 @@ protected function handleJob($job, $next, array $limits) foreach ($limits as $limit) { if ($this->limiter->tooManyAttempts($limit->key, $limit->maxAttempts)) { return $this->shouldRelease - ? $job->release($this->getTimeUntilNextRetry($limit->key)) - : false; + ? $job->release($this->getTimeUntilNextRetry($limit->key)) + : false; } $this->limiter->hit($limit->key, $limit->decaySeconds); diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index a9d59e95ff27..7a00c077204d 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -126,8 +126,8 @@ protected function createPayload($job, $queue, $data = '') protected function createPayloadArray($job, $queue, $data = '') { return is_object($job) - ? $this->createObjectPayload($job, $queue) - : $this->createStringPayload($job, $queue, $data); + ? $this->createObjectPayload($job, $queue) + : $this->createStringPayload($job, $queue, $data); } /** @@ -156,8 +156,8 @@ protected function createObjectPayload($job, $queue) ]); $command = $this->jobShouldBeEncrypted($job) && $this->container->bound(Encrypter::class) - ? $this->container[Encrypter::class]->encrypt(serialize(clone $job)) - : serialize(clone $job); + ? $this->container[Encrypter::class]->encrypt(serialize(clone $job)) + : serialize(clone $job); return array_merge($payload, [ 'data' => array_merge($payload['data'], [ @@ -176,7 +176,8 @@ protected function createObjectPayload($job, $queue) protected function getDisplayName($job) { return method_exists($job, 'displayName') - ? $job->displayName() : get_class($job); + ? $job->displayName() + : get_class($job); } /** @@ -234,7 +235,8 @@ public function getJobExpiration($job) $expiration = $job->retryUntil ?? $job->retryUntil(); return $expiration instanceof DateTimeInterface - ? $expiration->getTimestamp() : $expiration; + ? $expiration->getTimestamp() + : $expiration; } /** diff --git a/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php b/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php index d46ff5255dac..09fbf4829e7c 100644 --- a/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php +++ b/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php @@ -59,8 +59,8 @@ protected function getRestoredPropertyValue($value) } return is_array($value->id) - ? $this->restoreCollection($value) - : $this->restoreModel($value); + ? $this->restoreCollection($value) + : $this->restoreModel($value); } /** diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index c4ffb227a591..3f8fe38b9b82 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -617,8 +617,8 @@ protected function calculateBackoff($job, WorkerOptions $options) $backoff = explode( ',', method_exists($job, 'backoff') && ! is_null($job->backoff()) - ? $job->backoff() - : $options->backoff + ? $job->backoff() + : $options->backoff ); return (int) ($backoff[$job->attempts() - 1] ?? last($backoff)); diff --git a/src/Illuminate/Routing/Console/ControllerMakeCommand.php b/src/Illuminate/Routing/Console/ControllerMakeCommand.php index b02733b38e52..dcf855c3f806 100755 --- a/src/Illuminate/Routing/Console/ControllerMakeCommand.php +++ b/src/Illuminate/Routing/Console/ControllerMakeCommand.php @@ -53,8 +53,8 @@ protected function getStub() $stub = "/stubs/controller.{$type}.stub"; } elseif ($this->option('parent')) { $stub = $this->option('singleton') - ? '/stubs/controller.nested.singleton.stub' - : '/stubs/controller.nested.stub'; + ? '/stubs/controller.nested.singleton.stub' + : '/stubs/controller.nested.stub'; } elseif ($this->option('model')) { $stub = '/stubs/controller.model.stub'; } elseif ($this->option('invokable')) { @@ -85,8 +85,8 @@ protected function getStub() protected function resolveStubPath($stub) { return file_exists($customPath = $this->laravel->basePath(trim($stub, '/'))) - ? $customPath - : __DIR__.$stub; + ? $customPath + : __DIR__.$stub; } /** diff --git a/src/Illuminate/Routing/ImplicitRouteBinding.php b/src/Illuminate/Routing/ImplicitRouteBinding.php index 7d92ec9757f9..642bc3151410 100644 --- a/src/Illuminate/Routing/ImplicitRouteBinding.php +++ b/src/Illuminate/Routing/ImplicitRouteBinding.php @@ -43,15 +43,15 @@ public static function resolveForRoute($container, $route) $parent = $route->parentOfParameter($parameterName); $routeBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance)) - ? 'resolveSoftDeletableRouteBinding' - : 'resolveRouteBinding'; + ? 'resolveSoftDeletableRouteBinding' + : 'resolveRouteBinding'; if ($parent instanceof UrlRoutable && ! $route->preventsScopedBindings() && ($route->enforcesScopedBindings() || array_key_exists($parameterName, $route->bindingFields()))) { $childRouteBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance)) - ? 'resolveSoftDeletableChildRouteBinding' - : 'resolveChildRouteBinding'; + ? 'resolveSoftDeletableChildRouteBinding' + : 'resolveChildRouteBinding'; if (! $model = $parent->{$childRouteBindingMethod}( $parameterName, $parameterValue, $route->bindingFieldFor($parameterName) diff --git a/src/Illuminate/Routing/Middleware/ThrottleRequests.php b/src/Illuminate/Routing/Middleware/ThrottleRequests.php index d9859558c30c..034c91b84286 100644 --- a/src/Illuminate/Routing/Middleware/ThrottleRequests.php +++ b/src/Illuminate/Routing/Middleware/ThrottleRequests.php @@ -241,8 +241,8 @@ protected function buildException($request, $key, $maxAttempts, $responseCallbac ); return is_callable($responseCallback) - ? new HttpResponseException($responseCallback($request, $headers)) - : new ThrottleRequestsException('Too Many Attempts.', null, $headers); + ? new HttpResponseException($responseCallback($request, $headers)) + : new ThrottleRequestsException('Too Many Attempts.', null, $headers); } /** diff --git a/src/Illuminate/Routing/Redirector.php b/src/Illuminate/Routing/Redirector.php index 24de72d1fe7d..d779fcf50844 100755 --- a/src/Illuminate/Routing/Redirector.php +++ b/src/Illuminate/Routing/Redirector.php @@ -74,8 +74,8 @@ public function guest($path, $status = 302, $headers = [], $secure = null) $request = $this->generator->getRequest(); $intended = $request->isMethod('GET') && $request->route() && ! $request->expectsJson() - ? $this->generator->full() - : $this->generator->previous(); + ? $this->generator->full() + : $this->generator->previous(); if ($intended) { $this->setIntendedUrl($intended); diff --git a/src/Illuminate/Routing/ResourceRegistrar.php b/src/Illuminate/Routing/ResourceRegistrar.php index f0668499389e..18dba2cff60f 100644 --- a/src/Illuminate/Routing/ResourceRegistrar.php +++ b/src/Illuminate/Routing/ResourceRegistrar.php @@ -547,8 +547,8 @@ protected function addSingletonDestroy($name, $controller, $options) protected function getShallowName($name, $options) { return isset($options['shallow']) && $options['shallow'] - ? last(explode('.', $name)) - : $name; + ? last(explode('.', $name)) + : $name; } /** diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 8253f0c26428..2542cb2859cb 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -792,7 +792,7 @@ public function domain($domain = null) public function getDomain() { return isset($this->action['domain']) - ? str_replace(['http://', 'https://'], '', $this->action['domain']) : null; + ? str_replace(['http://', 'https://'], '', $this->action['domain']) : null; } /** @@ -1094,8 +1094,8 @@ public function can($ability, $models = []) $ability = enum_value($ability); return empty($models) - ? $this->middleware(['can:'.$ability]) - : $this->middleware(['can:'.$ability.','.implode(',', Arr::wrap($models))]); + ? $this->middleware(['can:'.$ability]) + : $this->middleware(['can:'.$ability.','.implode(',', Arr::wrap($models))]); } /** diff --git a/src/Illuminate/Routing/RouteBinding.php b/src/Illuminate/Routing/RouteBinding.php index ef37e7063564..cec3fa998a07 100644 --- a/src/Illuminate/Routing/RouteBinding.php +++ b/src/Illuminate/Routing/RouteBinding.php @@ -69,8 +69,8 @@ public static function forModel($container, $class, $callback = null) $instance = $container->make($class); $routeBindingMethod = $route?->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance)) - ? 'resolveSoftDeletableRouteBinding' - : 'resolveRouteBinding'; + ? 'resolveSoftDeletableRouteBinding' + : 'resolveRouteBinding'; if ($model = $instance->{$routeBindingMethod}($value)) { return $model; diff --git a/src/Illuminate/Routing/RouteGroup.php b/src/Illuminate/Routing/RouteGroup.php index 2c60273068fd..cca24b29234d 100644 --- a/src/Illuminate/Routing/RouteGroup.php +++ b/src/Illuminate/Routing/RouteGroup.php @@ -46,8 +46,8 @@ protected static function formatNamespace($new, $old) { if (isset($new['namespace'])) { return isset($old['namespace']) && ! str_starts_with($new['namespace'], '\\') - ? trim($old['namespace'], '\\').'\\'.trim($new['namespace'], '\\') - : trim($new['namespace'], '\\'); + ? trim($old['namespace'], '\\').'\\'.trim($new['namespace'], '\\') + : trim($new['namespace'], '\\'); } return $old['namespace'] ?? null; diff --git a/src/Illuminate/Routing/RouteSignatureParameters.php b/src/Illuminate/Routing/RouteSignatureParameters.php index 7a4b6dadb996..872709758314 100644 --- a/src/Illuminate/Routing/RouteSignatureParameters.php +++ b/src/Illuminate/Routing/RouteSignatureParameters.php @@ -19,12 +19,12 @@ class RouteSignatureParameters public static function fromAction(array $action, $conditions = []) { $callback = RouteAction::containsSerializedClosure($action) - ? unserialize($action['uses'])->getClosure() - : $action['uses']; + ? unserialize($action['uses'])->getClosure() + : $action['uses']; $parameters = is_string($callback) - ? static::fromClassMethodString($callback) - : (new ReflectionFunction($callback))->getParameters(); + ? static::fromClassMethodString($callback) + : (new ReflectionFunction($callback))->getParameters(); return match (true) { ! empty($conditions['subClass']) => array_filter($parameters, fn ($p) => Reflector::isParameterSubclassOf($p, $conditions['subClass'])), diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index a0e5cf6413c5..4cb4b4599aac 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -164,7 +164,7 @@ protected function addPortToDomain($domain) $port = (int) $this->request->getPort(); return ($secure && $port === 443) || (! $secure && $port === 80) - ? $domain : $domain.':'.$port; + ? $domain : $domain.':'.$port; } /** @@ -200,8 +200,8 @@ protected function replaceRouteParameters($path, array &$parameters) $parameters = array_merge($parameters); return (! isset($parameters[0]) && ! str_ends_with($match[0], '?}')) - ? $match[0] - : Arr::pull($parameters, 0); + ? $match[0] + : Arr::pull($parameters, 0); }, $path); return trim(preg_replace('/\{.*?\?\}/', '', $path), '/'); diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 4ea9480961eb..4b69dae224e4 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -630,7 +630,7 @@ protected function prependGroupNamespace($class) $group = end($this->groupStack); return isset($group['namespace']) && ! str_starts_with($class, '\\') && ! str_starts_with($class, $group['namespace']) - ? $group['namespace'].'\\'.$class : $class; + ? $group['namespace'].'\\'.$class : $class; } /** diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 9774b98fd23b..36ffd20c164d 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -541,8 +541,8 @@ public function toRoute($route, $parameters, $absolute) { $parameters = Collection::wrap($parameters)->map(function ($value, $key) use ($route) { return $value instanceof UrlRoutable && $route->bindingFieldFor($key) - ? $value->{$route->bindingFieldFor($key)} - : $value; + ? $value->{$route->bindingFieldFor($key)} + : $value; })->all(); array_walk_recursive($parameters, function (&$item) { diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 859d4604ea43..9f456a3ba577 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -79,8 +79,8 @@ protected function handleRequestWhileBlocking(Request $request, $session, Closur } $lockFor = $request->route() && $request->route()->locksFor() - ? $request->route()->locksFor() - : $this->manager->defaultRouteBlockLockSeconds(); + ? $request->route()->locksFor() + : $this->manager->defaultRouteBlockLockSeconds(); $lock = $this->cache($this->manager->blockDriver()) ->lock('session:'.$session->getId(), $lockFor) @@ -89,8 +89,8 @@ protected function handleRequestWhileBlocking(Request $request, $session, Closur try { $lock->block( ! is_null($request->route()->waitsFor()) - ? $request->route()->waitsFor() - : $this->manager->defaultRouteBlockWaitSeconds() + ? $request->route()->waitsFor() + : $this->manager->defaultRouteBlockWaitSeconds() ); return $this->handleStatefulRequest($request, $session, $next); diff --git a/src/Illuminate/Session/SessionManager.php b/src/Illuminate/Session/SessionManager.php index 6094627e6ef5..578fc2107ab2 100755 --- a/src/Illuminate/Session/SessionManager.php +++ b/src/Illuminate/Session/SessionManager.php @@ -190,13 +190,13 @@ protected function createCacheHandler($driver) protected function buildSession($handler) { return $this->config->get('session.encrypt') - ? $this->buildEncryptedSession($handler) - : new Store( - $this->config->get('session.cookie'), - $handler, - $id = null, - $this->config->get('session.serialization', 'php') - ); + ? $this->buildEncryptedSession($handler) + : new Store( + $this->config->get('session.cookie'), + $handler, + $id = null, + $this->config->get('session.serialization', 'php') + ); } /** diff --git a/src/Illuminate/Support/Facades/Bus.php b/src/Illuminate/Support/Facades/Bus.php index 337108f31d85..90e64ac9cf0e 100644 --- a/src/Illuminate/Support/Facades/Bus.php +++ b/src/Illuminate/Support/Facades/Bus.php @@ -66,8 +66,8 @@ class Bus extends Facade public static function fake($jobsToFake = [], ?BatchRepository $batchRepository = null) { $actualDispatcher = static::isFake() - ? static::getFacadeRoot()->dispatcher - : static::getFacadeRoot(); + ? static::getFacadeRoot()->dispatcher + : static::getFacadeRoot(); return tap(new BusFake($actualDispatcher, $jobsToFake, $batchRepository), function ($fake) { static::swap($fake); diff --git a/src/Illuminate/Support/Facades/Event.php b/src/Illuminate/Support/Facades/Event.php index cbd5e5f8a69d..7200978c3baf 100755 --- a/src/Illuminate/Support/Facades/Event.php +++ b/src/Illuminate/Support/Facades/Event.php @@ -50,8 +50,8 @@ class Event extends Facade public static function fake($eventsToFake = []) { $actualDispatcher = static::isFake() - ? static::getFacadeRoot()->dispatcher - : static::getFacadeRoot(); + ? static::getFacadeRoot()->dispatcher + : static::getFacadeRoot(); return tap(new EventFake($actualDispatcher, $eventsToFake), function ($fake) { static::swap($fake); diff --git a/src/Illuminate/Support/Facades/Mail.php b/src/Illuminate/Support/Facades/Mail.php index fb4019b25aae..8e68581772e5 100755 --- a/src/Illuminate/Support/Facades/Mail.php +++ b/src/Illuminate/Support/Facades/Mail.php @@ -71,8 +71,8 @@ class Mail extends Facade public static function fake() { $actualMailManager = static::isFake() - ? static::getFacadeRoot()->manager - : static::getFacadeRoot(); + ? static::getFacadeRoot()->manager + : static::getFacadeRoot(); return tap(new MailFake($actualMailManager), function ($fake) { static::swap($fake); diff --git a/src/Illuminate/Support/Facades/Queue.php b/src/Illuminate/Support/Facades/Queue.php index 4201b728ab92..0abb5befbe45 100755 --- a/src/Illuminate/Support/Facades/Queue.php +++ b/src/Illuminate/Support/Facades/Queue.php @@ -82,8 +82,8 @@ public static function popUsing($workerName, $callback) public static function fake($jobsToFake = []) { $actualQueueManager = static::isFake() - ? static::getFacadeRoot()->queue - : static::getFacadeRoot(); + ? static::getFacadeRoot()->queue + : static::getFacadeRoot(); return tap(new QueueFake(static::getFacadeApplication(), $jobsToFake, $actualQueueManager), function ($fake) { static::swap($fake); diff --git a/src/Illuminate/Support/InteractsWithTime.php b/src/Illuminate/Support/InteractsWithTime.php index f1fbf27ad49b..6b78be16c9b0 100644 --- a/src/Illuminate/Support/InteractsWithTime.php +++ b/src/Illuminate/Support/InteractsWithTime.php @@ -19,8 +19,8 @@ protected function secondsUntil($delay) $delay = $this->parseDateInterval($delay); return $delay instanceof DateTimeInterface - ? max(0, $delay->getTimestamp() - $this->currentTime()) - : (int) $delay; + ? max(0, $delay->getTimestamp() - $this->currentTime()) + : (int) $delay; } /** @@ -34,8 +34,8 @@ protected function availableAt($delay = 0) $delay = $this->parseDateInterval($delay); return $delay instanceof DateTimeInterface - ? $delay->getTimestamp() - : Carbon::now()->addSeconds($delay)->getTimestamp(); + ? $delay->getTimestamp() + : Carbon::now()->addSeconds($delay)->getTimestamp(); } /** diff --git a/src/Illuminate/Support/NamespacedItemResolver.php b/src/Illuminate/Support/NamespacedItemResolver.php index a059c6daff87..10007be9e30e 100755 --- a/src/Illuminate/Support/NamespacedItemResolver.php +++ b/src/Illuminate/Support/NamespacedItemResolver.php @@ -60,8 +60,8 @@ protected function parseBasicSegments(array $segments) // a specific item out of a group and will need to return this item name // as well as the group so we know which item to pull from the arrays. $item = count($segments) === 1 - ? null - : implode('.', array_slice($segments, 1)); + ? null + : implode('.', array_slice($segments, 1)); return [null, $group, $item]; } diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 51e50caa875b..556479fabb16 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -1232,8 +1232,8 @@ public static function replace($search, $replace, $subject, $caseSensitive = tru } return $caseSensitive - ? str_replace($search, $replace, $subject) - : str_ireplace($search, $replace, $subject); + ? str_replace($search, $replace, $subject) + : str_ireplace($search, $replace, $subject); } /** @@ -1365,8 +1365,8 @@ public static function remove($search, $subject, $caseSensitive = true) } return $caseSensitive - ? str_replace($search, '', $subject) - : str_ireplace($search, '', $subject); + ? str_replace($search, '', $subject) + : str_ireplace($search, '', $subject); } /** @@ -1846,8 +1846,8 @@ public static function wordWrap($string, $characters = 75, $break = "\n", $cutLo public static function uuid() { return static::$uuidFactory - ? call_user_func(static::$uuidFactory) - : Uuid::uuid4(); + ? call_user_func(static::$uuidFactory) + : Uuid::uuid4(); } /** @@ -1859,8 +1859,8 @@ public static function uuid() public static function uuid7($time = null) { return static::$uuidFactory - ? call_user_func(static::$uuidFactory) - : Uuid::uuid7($time); + ? call_user_func(static::$uuidFactory) + : Uuid::uuid7($time); } /** diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index 181fac01b60d..72dcb845eedd 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -785,8 +785,8 @@ protected function shouldFakeJob($command) return (new Collection($this->jobsToFake)) ->filter(function ($job) use ($command) { return $job instanceof Closure - ? $job($command) - : $job === get_class($command); + ? $job($command) + : $job === get_class($command); })->isNotEmpty(); } diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 7f226a786faf..9a4c9ea10024 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -335,8 +335,8 @@ protected function shouldFakeEvent($eventName, $payload) return (new Collection($this->eventsToFake)) ->filter(function ($event) use ($eventName, $payload) { return $event instanceof Closure - ? $event($eventName, $payload) - : $event === $eventName; + ? $event($eventName, $payload) + : $event === $eventName; }) ->isNotEmpty(); } diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index 777266695f3c..75e976583c0d 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -174,8 +174,8 @@ public function assertPushedWithChain($job, $expectedChain = [], $callback = nul ); $this->isChainOfObjects($expectedChain) - ? $this->assertPushedWithChainOfObjects($job, $expectedChain, $callback) - : $this->assertPushedWithChainOfClasses($job, $expectedChain, $callback); + ? $this->assertPushedWithChainOfObjects($job, $expectedChain, $callback) + : $this->assertPushedWithChainOfClasses($job, $expectedChain, $callback); } /** diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index a792bdd298cf..b23e3525f20b 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -941,9 +941,9 @@ public function assertJsonValidationErrors($errors, $responseKey = 'errors') $jsonErrors = Arr::get($this->json(), $responseKey) ?? []; $errorMessage = $jsonErrors - ? 'Response has the following JSON validation errors:'. - PHP_EOL.PHP_EOL.json_encode($jsonErrors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE).PHP_EOL - : 'Response does not have JSON validation errors.'; + ? 'Response has the following JSON validation errors:'. + PHP_EOL.PHP_EOL.json_encode($jsonErrors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE).PHP_EOL + : 'Response does not have JSON validation errors.'; foreach ($errors as $key => $value) { if (is_int($key)) { @@ -1341,9 +1341,9 @@ public function assertInvalid($errors = null, $sessionErrors = $this->session()->get('errors')->getBag($errorBag)->getMessages(); $errorMessage = $sessionErrors - ? 'Response has the following validation errors in the session:'. - PHP_EOL.PHP_EOL.json_encode($sessionErrors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE).PHP_EOL - : 'Response does not have validation errors in the session.'; + ? 'Response has the following validation errors in the session:'. + PHP_EOL.PHP_EOL.json_encode($sessionErrors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE).PHP_EOL + : 'Response does not have validation errors in the session.'; foreach (Arr::wrap($errors) as $key => $value) { PHPUnit::withResponse($this)->assertArrayHasKey( @@ -1816,8 +1816,8 @@ public function __isset($key) public function offsetExists($offset): bool { return $this->responseHasView() - ? isset($this->original->gatherData()[$offset]) - : isset($this->json()[$offset]); + ? isset($this->original->gatherData()[$offset]) + : isset($this->json()[$offset]); } /** @@ -1829,8 +1829,8 @@ public function offsetExists($offset): bool public function offsetGet($offset): mixed { return $this->responseHasView() - ? $this->viewData($offset) - : $this->json()[$offset]; + ? $this->viewData($offset) + : $this->json()[$offset]; } /** diff --git a/src/Illuminate/Validation/Concerns/FilterEmailValidation.php b/src/Illuminate/Validation/Concerns/FilterEmailValidation.php index 84ed212f2755..7bb929ee7e8b 100644 --- a/src/Illuminate/Validation/Concerns/FilterEmailValidation.php +++ b/src/Illuminate/Validation/Concerns/FilterEmailValidation.php @@ -46,8 +46,8 @@ public static function unicode() public function isValid(string $email, EmailLexer $emailLexer): bool { return is_null($this->flags) - ? filter_var($email, FILTER_VALIDATE_EMAIL) !== false - : filter_var($email, FILTER_VALIDATE_EMAIL, $this->flags) !== false; + ? filter_var($email, FILTER_VALIDATE_EMAIL) !== false + : filter_var($email, FILTER_VALIDATE_EMAIL, $this->flags) !== false; } /** diff --git a/src/Illuminate/Validation/Concerns/FormatsMessages.php b/src/Illuminate/Validation/Concerns/FormatsMessages.php index ad1352aa767b..d4e83ea105a4 100644 --- a/src/Illuminate/Validation/Concerns/FormatsMessages.php +++ b/src/Illuminate/Validation/Concerns/FormatsMessages.php @@ -84,8 +84,8 @@ protected function getInlineMessage($attribute, $rule) $inlineEntry = $this->getFromLocalArray($attribute, Str::snake($rule)); return is_array($inlineEntry) && in_array($rule, $this->sizeRules) - ? $inlineEntry[$this->getAttributeType($attribute)] - : $inlineEntry; + ? $inlineEntry[$this->getAttributeType($attribute)] + : $inlineEntry; } /** @@ -267,7 +267,7 @@ public function getDisplayableAttribute($attribute) $primaryAttribute = $this->getPrimaryAttribute($attribute); $expectedAttributes = $attribute != $primaryAttribute - ? [$attribute, $primaryAttribute] : [$attribute]; + ? [$attribute, $primaryAttribute] : [$attribute]; foreach ($expectedAttributes as $name) { // The developer may dynamically specify the array of custom attributes on this @@ -290,8 +290,8 @@ public function getDisplayableAttribute($attribute) // modify it with any of these replacements before we display the name. if (isset($this->implicitAttributes[$primaryAttribute])) { return ($formatter = $this->implicitAttributesFormatter) - ? $formatter($attribute) - : $attribute; + ? $formatter($attribute) + : $attribute; } return str_replace('_', ' ', Str::snake($attribute)); diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index a98aa59c57ef..5e6cd45c9f31 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -731,8 +731,8 @@ public function validateDimensions($attribute, $value, $parameters) } $dimensions = method_exists($value, 'dimensions') - ? $value->dimensions() - : @getimagesize($value->getRealPath()); + ? $value->dimensions() + : @getimagesize($value->getRealPath()); if (! $dimensions) { return false; @@ -980,8 +980,8 @@ protected function getExistCount($connection, $table, $column, $value, $paramete } return is_array($value) - ? $verifier->getMultiCount($table, $column, $value, $extra) - : $verifier->getCount($table, $column, $value, null, null, $extra); + ? $verifier->getMultiCount($table, $column, $value, $extra) + : $verifier->getCount($table, $column, $value, null, null, $extra); } /** @@ -1119,7 +1119,7 @@ public function parseTable($table) public function getQueryColumn($parameters, $attribute) { return isset($parameters[1]) && $parameters[1] !== 'NULL' - ? $parameters[1] : $this->guessColumnForQuery($attribute); + ? $parameters[1] : $this->guessColumnForQuery($attribute); } /** @@ -1637,8 +1637,8 @@ protected function shouldBlockPhpUpload($value, $parameters) ]; return ($value instanceof UploadedFile) - ? in_array(trim(strtolower($value->getClientOriginalExtension())), $phpExtensions) - : in_array(trim(strtolower($value->getExtension())), $phpExtensions); + ? in_array(trim(strtolower($value->getClientOriginalExtension())), $phpExtensions) + : in_array(trim(strtolower($value->getExtension())), $phpExtensions); } /** diff --git a/src/Illuminate/Validation/ConditionalRules.php b/src/Illuminate/Validation/ConditionalRules.php index fa6022209672..0dae7c1a2fcd 100644 --- a/src/Illuminate/Validation/ConditionalRules.php +++ b/src/Illuminate/Validation/ConditionalRules.php @@ -51,8 +51,8 @@ public function __construct($condition, $rules, $defaultRules = []) public function passes(array $data = []) { return is_callable($this->condition) - ? call_user_func($this->condition, new Fluent($data)) - : $this->condition; + ? call_user_func($this->condition, new Fluent($data)) + : $this->condition; } /** @@ -64,8 +64,8 @@ public function passes(array $data = []) public function rules(array $data = []) { return is_string($this->rules) - ? explode('|', $this->rules) - : value($this->rules, new Fluent($data)); + ? explode('|', $this->rules) + : value($this->rules, new Fluent($data)); } /** @@ -77,7 +77,7 @@ public function rules(array $data = []) public function defaultRules(array $data = []) { return is_string($this->defaultRules) - ? explode('|', $this->defaultRules) - : value($this->defaultRules, new Fluent($data)); + ? explode('|', $this->defaultRules) + : value($this->defaultRules, new Fluent($data)); } } diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index 49451dfbbcd9..c9e43943ef59 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -96,8 +96,8 @@ public function passes($attribute, $value) } $method = $this->invokable instanceof ValidationRule - ? 'validate' - : '__invoke'; + ? 'validate' + : '__invoke'; $this->invokable->{$method}($attribute, $value, function ($attribute, $message = null) { $this->failed = true; diff --git a/src/Illuminate/Validation/Rules/Password.php b/src/Illuminate/Validation/Rules/Password.php index 4f8608c2a206..fe4d55fb5b7a 100644 --- a/src/Illuminate/Validation/Rules/Password.php +++ b/src/Illuminate/Validation/Rules/Password.php @@ -147,8 +147,8 @@ public static function defaults($callback = null) public static function default() { $password = is_callable(static::$defaultCallback) - ? call_user_func(static::$defaultCallback) - : static::$defaultCallback; + ? call_user_func(static::$defaultCallback) + : static::$defaultCallback; return $password instanceof Rule ? $password : static::min(8); } diff --git a/src/Illuminate/Validation/ValidationRuleParser.php b/src/Illuminate/Validation/ValidationRuleParser.php index c54fa2ce4370..27d8d74c03a9 100644 --- a/src/Illuminate/Validation/ValidationRuleParser.php +++ b/src/Illuminate/Validation/ValidationRuleParser.php @@ -342,8 +342,8 @@ public static function filterConditionalRules($rules, array $data = []) if ($attributeRules instanceof ConditionalRules) { return [$attribute => $attributeRules->passes($data) - ? array_filter($attributeRules->rules($data)) - : array_filter($attributeRules->defaultRules($data)), ]; + ? array_filter($attributeRules->rules($data)) + : array_filter($attributeRules->defaultRules($data)), ]; } return [$attribute => (new Collection($attributeRules))->map(function ($rule) use ($data) { diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 2ecb0b1476f6..026b3f34d443 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -396,8 +396,8 @@ protected function replacePlaceholders($data) foreach ($data as $key => $value) { $originalData[$this->replacePlaceholderInString($key)] = is_array($value) - ? $this->replacePlaceholders($value) - : $value; + ? $this->replacePlaceholders($value) + : $value; } return $originalData; @@ -588,8 +588,8 @@ public function validateWithBag(string $errorBag) public function safe(?array $keys = null) { return is_array($keys) - ? (new ValidatedInput($this->validated()))->only($keys) - : new ValidatedInput($this->validated()); + ? (new ValidatedInput($this->validated()))->only($keys) + : new ValidatedInput($this->validated()); } /** @@ -675,8 +675,8 @@ protected function validateAttribute($attribute, $rule) if ($rule instanceof RuleContract) { return $validatable - ? $this->validateUsingCustomRule($attribute, $value, $rule) - : null; + ? $this->validateUsingCustomRule($attribute, $value, $rule) + : null; } $method = "validate{$rule}"; @@ -1291,8 +1291,8 @@ private function dataForSometimesIteration(string $attribute, $removeLastSegment $lastSegmentOfAttribute = strrchr($attribute, '.'); $attribute = $lastSegmentOfAttribute && $removeLastSegmentOfAttribute - ? Str::replaceLast($lastSegmentOfAttribute, '', $attribute) - : $attribute; + ? Str::replaceLast($lastSegmentOfAttribute, '', $attribute) + : $attribute; return is_array($data = data_get($this->data, $attribute)) ? new Fluent($data) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index a866141f1fcb..48e5d734d90f 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -713,8 +713,8 @@ public function if($name, callable $callback) $this->directive($name, function ($expression) use ($name) { return $expression !== '' - ? "" - : ""; + ? "" + : ""; }); $this->directive('unless'.$name, function ($expression) use ($name) { @@ -762,10 +762,10 @@ public function component($class, $alias = null, $prefix = '') if (is_null($alias)) { $alias = str_contains($class, '\\View\\Components\\') - ? (new Collection(explode('\\', Str::after($class, '\\View\\Components\\'))))->map(function ($segment) { - return Str::kebab($segment); - })->implode(':') - : Str::kebab(class_basename($class)); + ? (new Collection(explode('\\', Str::after($class, '\\View\\Components\\'))))->map(function ($segment) { + return Str::kebab($segment); + })->implode(':') + : Str::kebab(class_basename($class)); } if (! empty($prefix)) { @@ -897,8 +897,8 @@ public function aliasComponent($path, $alias = null) $this->directive($alias, function ($expression) use ($path) { return $expression - ? "startComponent('{$path}', {$expression}); ?>" - : "startComponent('{$path}'); ?>"; + ? "startComponent('{$path}', {$expression}); ?>" + : "startComponent('{$path}'); ?>"; }); $this->directive('end'.$alias, function ($expression) { diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 357bcd241f58..06b73c928df6 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -337,8 +337,8 @@ protected function guessAnonymousComponentUsingPaths(Factory $viewFactory, strin } $formattedComponent = str_starts_with($component, $path['prefix'].$delimiter) - ? Str::after($component, $delimiter) - : $component; + ? Str::after($component, $delimiter) + : $component; if (! is_null($guess = match (true) { $viewFactory->exists($guess = $path['prefixHash'].$delimiter.$formattedComponent) => $guess, @@ -485,8 +485,8 @@ public function partitionDataAndAttributes($class, array $attributes) $constructor = (new ReflectionClass($class))->getConstructor(); $parameterNames = $constructor - ? (new Collection($constructor->getParameters()))->map->getName()->all() - : []; + ? (new Collection($constructor->getParameters()))->map->getName()->all() + : []; return (new Collection($attributes)) ->partition(fn ($value, $key) => in_array(Str::camel($key), $parameterNames)) @@ -772,8 +772,8 @@ protected function escapeSingleQuotesOutsideOfPhpBlocks(string $value) } return $token[0] === T_INLINE_HTML - ? str_replace("'", "\\'", $token[1]) - : $token[1]; + ? str_replace("'", "\\'", $token[1]) + : $token[1]; })->implode(''); } @@ -789,8 +789,8 @@ protected function attributesToString(array $attributes, $escapeBound = true) return (new Collection($attributes)) ->map(function (string $value, string $attribute) use ($escapeBound) { return $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value) - ? "'{$attribute}' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute({$value})" - : "'{$attribute}' => {$value}"; + ? "'{$attribute}' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute({$value})" + : "'{$attribute}' => {$value}"; }) ->implode(','); } @@ -804,7 +804,7 @@ protected function attributesToString(array $attributes, $escapeBound = true) public function stripQuotes(string $value) { return Str::startsWith($value, ['"', '\'']) - ? substr($value, 1, -1) - : $value; + ? substr($value, 1, -1) + : $value; } } diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php index 22076c87bfc4..0d8ef22239f5 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php @@ -25,8 +25,8 @@ trait CompilesComponents protected function compileComponent($expression) { [$component, $alias, $data] = str_contains($expression, ',') - ? array_map(trim(...), explode(',', trim($expression, '()'), 3)) + ['', '', ''] - : [trim($expression, '()'), '', '']; + ? array_map(trim(...), explode(',', trim($expression, '()'), 3)) + ['', '', ''] + : [trim($expression, '()'), '', '']; $component = trim($component, '\'"'); @@ -215,8 +215,8 @@ public static function sanitizeComponentAttribute($value) } return is_string($value) || - (is_object($value) && ! $value instanceof ComponentAttributeBag && method_exists($value, '__toString')) - ? e($value) - : $value; + (is_object($value) && ! $value instanceof ComponentAttributeBag && method_exists($value, '__toString')) + ? e($value) + : $value; } } diff --git a/src/Illuminate/View/Component.php b/src/Illuminate/View/Component.php index ae4f760c6637..4e67b9a897bd 100644 --- a/src/Illuminate/View/Component.php +++ b/src/Illuminate/View/Component.php @@ -288,8 +288,8 @@ protected function extractPublicMethods() protected function createVariableFromMethod(ReflectionMethod $method) { return $method->getNumberOfParameters() === 0 - ? $this->createInvokableVariable($method->getName()) - : Closure::fromCallable([$this, $method->getName()]); + ? $this->createInvokableVariable($method->getName()) + : Closure::fromCallable([$this, $method->getName()]); } /** diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index 780d93deb51d..b7ea097b9527 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -269,8 +269,8 @@ public function merge(array $attributeDefaults = [], $escape = true) { $attributeDefaults = array_map(function ($value) use ($escape) { return $this->shouldEscapeAttributeValue($escape, $value) - ? e($value) - : $value; + ? e($value) + : $value; }, $attributeDefaults); [$appendableAttributes, $nonAppendableAttributes] = (new Collection($this->attributes)) @@ -283,8 +283,8 @@ public function merge(array $attributeDefaults = [], $escape = true) $attributes = $appendableAttributes->mapWithKeys(function ($value, $key) use ($attributeDefaults, $escape) { $defaultsValue = isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue - ? $this->resolveAppendableAttributeDefault($attributeDefaults, $key, $escape) - : ($attributeDefaults[$key] ?? ''); + ? $this->resolveAppendableAttributeDefault($attributeDefaults, $key, $escape) + : ($attributeDefaults[$key] ?? ''); if ($key === 'style') { $value = Str::finish($value, ';'); diff --git a/src/Illuminate/View/Concerns/ManagesLoops.php b/src/Illuminate/View/Concerns/ManagesLoops.php index 95f06c825cb4..7098f4a1d27f 100644 --- a/src/Illuminate/View/Concerns/ManagesLoops.php +++ b/src/Illuminate/View/Concerns/ManagesLoops.php @@ -23,8 +23,8 @@ trait ManagesLoops public function addLoop($data) { $length = is_countable($data) && ! $data instanceof LazyCollection - ? count($data) - : null; + ? count($data) + : null; $parent = Arr::last($this->loopsStack); diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php index e5efe067e86e..7fe5c999aee0 100755 --- a/src/Illuminate/View/Factory.php +++ b/src/Illuminate/View/Factory.php @@ -246,8 +246,8 @@ public function renderEach($view, $data, $iterator, $empty = 'raw|') // with "raw|" for convenience and to let this know that it is a string. else { $result = str_starts_with($empty, 'raw|') - ? substr($empty, 4) - : $this->make($empty)->render(); + ? substr($empty, 4) + : $this->make($empty)->render(); } return $result; diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php index ac165842a03c..8442660e6054 100755 --- a/src/Illuminate/View/View.php +++ b/src/Illuminate/View/View.php @@ -295,8 +295,8 @@ public function withErrors($provider, $bag = 'default') protected function formatErrors($provider) { return $provider instanceof MessageProvider - ? $provider->getMessageBag() - : new MessageBag((array) $provider); + ? $provider->getMessageBag() + : new MessageBag((array) $provider); } /** From 2fb06941bc69ea92f28b2888535ab144ee006889 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:38:20 +0000 Subject: [PATCH 173/455] Update version to v12.2.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 9a4f77c49956..38378aa3605d 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.1.1'; + const VERSION = '12.2.0'; /** * The base path for the Laravel installation. From be9dea9a6ad4323514dc25736b0126e5455e17d7 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:40:16 +0000 Subject: [PATCH 174/455] Update CHANGELOG --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a949f3d37af3..f288f24595b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,42 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.1.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.2.0...12.x) + +## [v12.2.0](https://github.com/laravel/framework/compare/v12.1.1...v12.2.0) - 2025-03-12 + +* Add dates to allowed PHPDoc types of Builder::having() by [@miken32](https://github.com/miken32) in https://github.com/laravel/framework/pull/54899 +* [11.x] Fix double negative in `whereNotMorphedTo()` query by [@owenvoke](https://github.com/owenvoke) in https://github.com/laravel/framework/pull/54902 +* Add test for Arr::partition by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/54913 +* [11.x] Expose process checkTimeout method by [@mattmcdev](https://github.com/mattmcdev) in https://github.com/laravel/framework/pull/54912 +* [12.x] Compilable for Validation Contract by [@peterfox](https://github.com/peterfox) in https://github.com/laravel/framework/pull/54882 +* [11.x] Backport "Change `paginate()` method return types to `\Illuminate\Pagination\LengthAwarePaginator`" by [@carestad](https://github.com/carestad) in https://github.com/laravel/framework/pull/54917 +* [11.x] Revert faulty change to `EnumeratesValues::ensure()` doc block by [@axlon](https://github.com/axlon) in https://github.com/laravel/framework/pull/54919 +* Ensure ValidationEmailRuleTest skips tests requiring the intl extension when unavailable by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54918 +* ✅ Ensure Enum validation is case-sensitive by adding a new test case. by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54922 +* [12.x] Feature: Collection chunk without preserving keys by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/54916 +* [12.x] Add test coverage for Uri::withQueryIfMissing method by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54923 +* Fix issue with using RedisCluster with compression or serialization by [@rzv-me](https://github.com/rzv-me) in https://github.com/laravel/framework/pull/54934 +* [12.x] Add test coverage for Str::replaceMatches method by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54930 +* [12.x] Types: Collection chunk without preserving keys by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/54924 +* [12.x] Add `ddBody` method to TestResponse for dumping various response payloads by [@Sammyjo20](https://github.com/Sammyjo20) in https://github.com/laravel/framework/pull/54933 +* [11.x] Backport "Fix issue with using `RedisCluster` with compression or serialization" by [@rzv-me](https://github.com/rzv-me) in https://github.com/laravel/framework/pull/54935 +* [12.x] feat: add `CanBeOneOfMany` support to `HasOneThrough` by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/54759 +* [12.x] Hotfix - Add function_exists check to ddBody in TestResponse by [@Sammyjo20](https://github.com/Sammyjo20) in https://github.com/laravel/framework/pull/54937 +* [12.x] Refactor: Remove unnecessary variables in Str class methods by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54963 +* Add Tests for Str::pluralPascal Method by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54957 +* [12.x] Fix visibility of setUp and tearDown in tests by [@naopusyu](https://github.com/naopusyu) in https://github.com/laravel/framework/pull/54950 +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54944 +* Fix missing return in `assertOnlyInvalid` by [@parth391](https://github.com/parth391) in https://github.com/laravel/framework/pull/54941 +* Handle case when migrate:install command is called and table exists by [@joe-tito](https://github.com/joe-tito) in https://github.com/laravel/framework/pull/54938 +* [11.x] Fix callOnce in Seeder so it handles arrays properly by [@lbovit](https://github.com/lbovit) in https://github.com/laravel/framework/pull/54985 +* Change "exceptoin" spelling mistake to "exception" by [@hvlucas](https://github.com/hvlucas) in https://github.com/laravel/framework/pull/54979 +* [12.x] Add test for after method in LazyCollection by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54978 +* [12.x] Add `increment` and `decrement` methods to `Context` by [@mattmcdev](https://github.com/mattmcdev) in https://github.com/laravel/framework/pull/54976 +* Ensure ExcludeIf correctly rejects a null value as an invalid condition by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54973 +* [12.x] apply Pint rule "no_spaces_around_offset" by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/54970 +* [12.x] apply Pint rule "single_line_comment_style" by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/54969 +* [12.x] do not use mix of newline and inline formatting by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/54967 +* [12.x] use single indent for multiline ternaries by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/54971 ## [v12.1.1](https://github.com/laravel/framework/compare/v12.1.0...v12.1.1) - 2025-03-05 From 39b84dc961ab947b00b88754fc46cb01e14cf6b5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 13 Mar 2025 09:06:26 -0500 Subject: [PATCH 175/455] pass the method to the request when callback --- src/Illuminate/Http/Client/PendingRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 839c6e6debd5..4a142f7f6f1a 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -911,7 +911,7 @@ public function send(string $method, string $url, array $options = []) if (! $response->successful()) { try { - $shouldRetry = $this->retryWhenCallback ? call_user_func($this->retryWhenCallback, $response->toException(), $this) : true; + $shouldRetry = $this->retryWhenCallback ? call_user_func($this->retryWhenCallback, $response->toException(), $this, $this->request->toPsrRequest()->getMethod()) : true; } catch (Exception $exception) { $shouldRetry = false; @@ -948,7 +948,7 @@ public function send(string $method, string $url, array $options = []) throw $exception; } }, $this->retryDelay ?? 100, function ($exception) use (&$shouldRetry) { - $result = $shouldRetry ?? ($this->retryWhenCallback ? call_user_func($this->retryWhenCallback, $exception, $this) : true); + $result = $shouldRetry ?? ($this->retryWhenCallback ? call_user_func($this->retryWhenCallback, $exception, $this, $this->request->toPsrRequest()->getMethod()) : true); $shouldRetry = null; From 0e3897259e7af63dec554ac65934f3ad55cc4619 Mon Sep 17 00:00:00 2001 From: mihaileu <54336101+mihaileu@users.noreply.github.com> Date: Thu, 13 Mar 2025 16:48:33 +0200 Subject: [PATCH 176/455] [12.x] fixes https://github.com/laravel/octane/issues/1010 (#55008) * fixes https://github.com/laravel/octane/issues/1010 * fixing phpstan error * use laravel code style * remove empty line * formatting --------- Co-authored-by: Taylor Otwell --- .../Log/Context/ContextLogProcessor.php | 18 +++++------------- .../Log/Context/ContextServiceProvider.php | 2 +- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Log/Context/ContextLogProcessor.php b/src/Illuminate/Log/Context/ContextLogProcessor.php index 9329eb0706c0..9ac3e97a77dd 100644 --- a/src/Illuminate/Log/Context/ContextLogProcessor.php +++ b/src/Illuminate/Log/Context/ContextLogProcessor.php @@ -2,23 +2,13 @@ namespace Illuminate\Log\Context; -use Illuminate\Contracts\Foundation\Application; +use Illuminate\Container\Container; use Illuminate\Contracts\Log\ContextLogProcessor as ContextLogProcessorContract; use Illuminate\Log\Context\Repository as ContextRepository; use Monolog\LogRecord; class ContextLogProcessor implements ContextLogProcessorContract { - /** - * Create a new ContextLogProcessor instance. - * - * @param \Illuminate\Contracts\Foundation\Application $app - * @return void - */ - public function __construct(protected Application $app) - { - } - /** * Add contextual data to the log's "extra" parameter. * @@ -27,13 +17,15 @@ public function __construct(protected Application $app) */ public function __invoke(LogRecord $record): LogRecord { - if (! $this->app->bound(ContextRepository::class)) { + $app = Container::getInstance(); + + if (! $app->bound(ContextRepository::class)) { return $record; } return $record->with(extra: [ ...$record->extra, - ...$this->app[ContextRepository::class]->all(), + ...$app->get(ContextRepository::class)->all(), ]); } } diff --git a/src/Illuminate/Log/Context/ContextServiceProvider.php b/src/Illuminate/Log/Context/ContextServiceProvider.php index 59f4c6c63fda..7167518a1b19 100644 --- a/src/Illuminate/Log/Context/ContextServiceProvider.php +++ b/src/Illuminate/Log/Context/ContextServiceProvider.php @@ -19,7 +19,7 @@ public function register() { $this->app->scoped(Repository::class); - $this->app->bind(ContextLogProcessorContract::class, fn ($app) => new ContextLogProcessor($app)); + $this->app->bind(ContextLogProcessorContract::class, fn () => new ContextLogProcessor()); } /** From 5db13c772f83fc24993c8355d54e108a9532ca70 Mon Sep 17 00:00:00 2001 From: Petrov Dumitru Date: Thu, 13 Mar 2025 16:50:14 +0200 Subject: [PATCH 177/455] Added the missing 'trashed' event to getObservablesEvents() (#55004) Fixes #54980 Previous pull #54987 but this one is more clear and inline. --- src/Illuminate/Database/Eloquent/Concerns/HasEvents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php index 74561974eb1c..7eda42308be2 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php @@ -134,7 +134,7 @@ public function getObservableEvents() [ 'retrieved', 'creating', 'created', 'updating', 'updated', 'saving', 'saved', 'restoring', 'restored', 'replicating', - 'deleting', 'deleted', 'forceDeleting', 'forceDeleted', + 'trashed', 'deleting', 'deleted', 'forceDeleting', 'forceDeleted', ], $this->observables ); From ae4481f730db69fded30b50f0effd57126cff39f Mon Sep 17 00:00:00 2001 From: "Kay W." Date: Thu, 13 Mar 2025 22:50:33 +0800 Subject: [PATCH 178/455] Enhance PHPDoc for Manager classes with `@param-closure-this` (#55002) --- src/Illuminate/Cache/CacheManager.php | 3 +++ src/Illuminate/Log/LogManager.php | 3 +++ src/Illuminate/Redis/RedisManager.php | 3 +++ src/Illuminate/Support/MultipleInstanceManager.php | 3 +++ types/Managers/CacheManager.php | 13 +++++++++++++ types/Managers/ConcurrencyManager.php | 13 +++++++++++++ types/Managers/LogManager.php | 13 +++++++++++++ types/Managers/RedisManager.php | 13 +++++++++++++ 8 files changed, 64 insertions(+) create mode 100644 types/Managers/CacheManager.php create mode 100644 types/Managers/ConcurrencyManager.php create mode 100644 types/Managers/LogManager.php create mode 100644 types/Managers/RedisManager.php diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index 6f15b122b2a4..a17405c2ab42 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -419,6 +419,9 @@ public function purge($name = null) * * @param string $driver * @param \Closure $callback + * + * @param-closure-this $this $callback + * * @return $this */ public function extend($driver, Closure $callback) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 840cdd65dd5e..d8f48c06b44f 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -587,6 +587,9 @@ public function setDefaultDriver($name) * * @param string $driver * @param \Closure $callback + * + * @param-closure-this $this $callback + * * @return $this */ public function extend($driver, Closure $callback) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index f1c7d4e917c3..4c4f3b876623 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -255,6 +255,9 @@ public function purge($name = null) * * @param string $driver * @param \Closure $callback + * + * @param-closure-this $this $callback + * * @return $this */ public function extend($driver, Closure $callback) diff --git a/src/Illuminate/Support/MultipleInstanceManager.php b/src/Illuminate/Support/MultipleInstanceManager.php index 05a8c23b4135..5706bde1e234 100644 --- a/src/Illuminate/Support/MultipleInstanceManager.php +++ b/src/Illuminate/Support/MultipleInstanceManager.php @@ -192,6 +192,9 @@ public function purge($name = null) * * @param string $name * @param \Closure $callback + * + * @param-closure-this $this $callback + * * @return $this */ public function extend($name, Closure $callback) diff --git a/types/Managers/CacheManager.php b/types/Managers/CacheManager.php new file mode 100644 index 000000000000..47521e110349 --- /dev/null +++ b/types/Managers/CacheManager.php @@ -0,0 +1,13 @@ +extend('redis', function (): void { + assertType('Illuminate\Cache\CacheManager', $this); +}); diff --git a/types/Managers/ConcurrencyManager.php b/types/Managers/ConcurrencyManager.php new file mode 100644 index 000000000000..d745b77ca0f7 --- /dev/null +++ b/types/Managers/ConcurrencyManager.php @@ -0,0 +1,13 @@ +extend('custom', function (): void { + assertType('Illuminate\Concurrency\ConcurrencyManager', $this); +}); diff --git a/types/Managers/LogManager.php b/types/Managers/LogManager.php new file mode 100644 index 000000000000..45da40dfa3dc --- /dev/null +++ b/types/Managers/LogManager.php @@ -0,0 +1,13 @@ +extend('emergency', function (): void { + assertType('Illuminate\Log\LogManager', $this); +}); diff --git a/types/Managers/RedisManager.php b/types/Managers/RedisManager.php new file mode 100644 index 000000000000..8b38200762c0 --- /dev/null +++ b/types/Managers/RedisManager.php @@ -0,0 +1,13 @@ +extend('custom', function (): void { + assertType('Illuminate\Redis\RedisManager', $this); +}); From e6449da8b9e4c8fb0f34445d1f5eadd108bc745c Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Thu, 13 Mar 2025 10:51:07 -0400 Subject: [PATCH 179/455] [12.x] Fix `PendingRequest` typehints for `post`, `patch`, `put`, `delete` (#54998) * Update PendingRequest.php * other methods --- src/Illuminate/Http/Client/PendingRequest.php | 8 +++--- tests/Http/HttpClientTest.php | 26 ++++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 4a142f7f6f1a..2915bc3f367c 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -794,7 +794,7 @@ public function head(string $url, $query = null) * Issue a POST request to the given URL. * * @param string $url - * @param array $data + * @param array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data * @return \Illuminate\Http\Client\Response * * @throws \Illuminate\Http\Client\ConnectionException @@ -810,7 +810,7 @@ public function post(string $url, $data = []) * Issue a PATCH request to the given URL. * * @param string $url - * @param array $data + * @param array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data * @return \Illuminate\Http\Client\Response * * @throws \Illuminate\Http\Client\ConnectionException @@ -826,7 +826,7 @@ public function patch(string $url, $data = []) * Issue a PUT request to the given URL. * * @param string $url - * @param array $data + * @param array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data * @return \Illuminate\Http\Client\Response * * @throws \Illuminate\Http\Client\ConnectionException @@ -842,7 +842,7 @@ public function put(string $url, $data = []) * Issue a DELETE request to the given URL. * * @param string $url - * @param array $data + * @param array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data * @return \Illuminate\Http\Client\Response * * @throws \Illuminate\Http\Client\ConnectionException diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 77570b385254..af4618fb357b 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -33,6 +33,7 @@ use Mockery as m; use OutOfBoundsException; use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -530,11 +531,12 @@ public function testCanSendFormData() }); } - public function testCanSendArrayableFormData() + #[DataProvider('methodsReceivingArrayableDataProvider')] + public function testCanSendArrayableFormData(string $method) { $this->factory->fake(); - $this->factory->asForm()->post('http://foo.com/form', new Fluent([ + $this->factory->asForm()->{$method}('http://foo.com/form', new Fluent([ 'name' => 'Taylor', 'title' => 'Laravel Developer', ])); @@ -546,11 +548,12 @@ public function testCanSendArrayableFormData() }); } - public function testCanSendJsonSerializableData() + #[DataProvider('methodsReceivingArrayableDataProvider')] + public function testCanSendJsonSerializableData(string $method) { $this->factory->fake(); - $this->factory->asJson()->post('http://foo.com/form', new class implements JsonSerializable + $this->factory->asJson()->{$method}('http://foo.com/form', new class implements JsonSerializable { public function jsonSerialize(): mixed { @@ -568,11 +571,12 @@ public function jsonSerialize(): mixed }); } - public function testPrefersJsonSerializableOverArrayableData() + #[DataProvider('methodsReceivingArrayableDataProvider')] + public function testPrefersJsonSerializableOverArrayableData(string $method) { $this->factory->fake(); - $this->factory->asJson()->post('http://foo.com/form', new class implements JsonSerializable, Arrayable + $this->factory->asJson()->{$method}('http://foo.com/form', new class implements JsonSerializable, Arrayable { public function jsonSerialize(): mixed { @@ -3472,6 +3476,16 @@ public function testItCanCreatePendingRequest() $this->assertInstanceOf(PendingRequest::class, $factory->createPendingRequest()); } + + public static function methodsReceivingArrayableDataProvider() + { + return [ + 'patch' => ['patch'], + 'put' => ['put'], + 'post' => ['post'], + 'delete' => ['delete'], + ]; + } } class CustomFactory extends Factory From 4701ef424138ac3ffc48195617da85186842fdb4 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:51:35 +0000 Subject: [PATCH 180/455] Update facade docblocks --- src/Illuminate/Support/Facades/Http.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index 3ba95e38f9f1..dc7843f932e7 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -70,10 +70,10 @@ * @method static \Illuminate\Http\Client\PendingRequest dd() * @method static \Illuminate\Http\Client\Response get(string $url, array|string|null $query = null) * @method static \Illuminate\Http\Client\Response head(string $url, array|string|null $query = null) - * @method static \Illuminate\Http\Client\Response post(string $url, array $data = []) - * @method static \Illuminate\Http\Client\Response patch(string $url, array $data = []) - * @method static \Illuminate\Http\Client\Response put(string $url, array $data = []) - * @method static \Illuminate\Http\Client\Response delete(string $url, array $data = []) + * @method static \Illuminate\Http\Client\Response post(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response patch(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response put(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response delete(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) * @method static array pool(callable $callback) * @method static \Illuminate\Http\Client\Response send(string $method, string $url, array $options = []) * @method static \GuzzleHttp\Client buildClient() From 79fdf0ce4c6c2450464f765f134cb9c953900106 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Thu, 13 Mar 2025 18:21:47 +0330 Subject: [PATCH 181/455] [12.x] Add test for untested methods in LazyCollection (#54996) * test: Implement comprehensive test cases for before() method This commit adds test coverage for the before() method including: - Non-strict comparison - Strict comparison - Callback function usage * test: Implement comprehensive test cases for shuffle() method This commit adds test coverage for the shuffle() method including: --- tests/Support/SupportLazyCollectionTest.php | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index e422a79e9f91..a199de262330 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -312,4 +312,47 @@ public function testAfter() $this->assertSame(['name' => 'Mohamed', 'age' => 35], $result); } + + public function testBefore() + { + // Test finding item before value with non-strict comparison + $data = new LazyCollection([1, 2, '3', 4]); + $result = $data->before(2); + $this->assertSame(1, $result); + + // Test finding item before value with strict comparison + $result = $data->before(4, true); + $this->assertSame('3', $result); + + // Test finding item before the one that matches a callback condition + $users = new LazyCollection([ + ['name' => 'Taylor', 'age' => 35], + ['name' => 'Jeffrey', 'age' => 45], + ['name' => 'Mohamed', 'age' => 35], + ]); + $result = $users->before(function ($user) { + return $user['name'] === 'Jeffrey'; + }); + $this->assertSame(['name' => 'Taylor', 'age' => 35], $result); + } + + public function testShuffle() + { + $data = new LazyCollection([1, 2, 3, 4, 5]); + $shuffled = $data->shuffle(); + + $this->assertCount(5, $shuffled); + $this->assertEquals([1, 2, 3, 4, 5], $shuffled->sort()->values()->all()); + + // Test shuffling associative array maintains key-value pairs + $users = new LazyCollection([ + 'first' => ['name' => 'Taylor'], + 'second' => ['name' => 'Jeffrey'], + ]); + $shuffled = $users->shuffle(); + + $this->assertCount(2, $shuffled); + $this->assertTrue($shuffled->contains('name', 'Taylor')); + $this->assertTrue($shuffled->contains('name', 'Jeffrey')); + } } From 76a20d3c93ba09dcf43cb82957cb68d5d78e1e8f Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 13 Mar 2025 09:52:04 -0500 Subject: [PATCH 182/455] fix indentation (#54995) per Pint rule "method_chaining_indentation" --- .../Database/Eloquent/Concerns/QueriesRelationships.php | 2 +- src/Illuminate/Http/Request.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 00292416f727..2a8fc0a35ebb 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -281,7 +281,7 @@ public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boole }); } }, null, null, $boolean) - ->when($checkMorphNull, fn (self $query) => $query->orWhereMorphedTo($relation, null)); + ->when($checkMorphNull, fn (self $query) => $query->orWhereMorphedTo($relation, null)); } /** diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 4614911560bf..8695535899e8 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -363,10 +363,10 @@ public function merge(array $input) { return tap($this, function (Request $request) use ($input) { $request->getInputSource() - ->replace(collect($input)->reduce( - fn ($requestInput, $value, $key) => data_set($requestInput, $key, $value), - $this->getInputSource()->all() - )); + ->replace(collect($input)->reduce( + fn ($requestInput, $value, $key) => data_set($requestInput, $key, $value), + $this->getInputSource()->all() + )); }); } From 9a5b5704e0811c5d911d5a415b82aec1e6d38cf4 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 13 Mar 2025 10:08:17 -0500 Subject: [PATCH 183/455] apply final Pint fixes (#55014) these changes apply the final Pint changes to make it pass. the majority of them are "braces_position" rule changes. --- .../Validation/InvokableValidationRule.php | 3 ++- tests/Bus/BusPendingBatchTest.php | 12 +++++++++--- tests/Database/DatabaseAbstractSchemaGrammarTest.php | 8 ++++++-- .../Database/DatabaseEloquentInverseRelationTest.php | 4 +++- tests/Encryption/EncrypterTest.php | 8 ++++++-- tests/Http/JsonResourceTest.php | 8 ++++++-- .../Pagination/CursorPaginatorLoadMorphCountTest.php | 4 +++- tests/Pagination/CursorPaginatorLoadMorphTest.php | 4 +++- tests/Pagination/PaginatorLoadMorphCountTest.php | 4 +++- tests/Pagination/PaginatorLoadMorphTest.php | 4 +++- tests/Support/SupportCollectionTest.php | 8 ++++++-- tests/Validation/ValidationValidatorTest.php | 4 +++- tests/View/Blade/BladeComponentTagCompilerTest.php | 4 +++- 13 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index c9e43943ef59..e8aaf55af17b 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -69,7 +69,8 @@ protected function __construct(ValidationRule|InvokableRule $invokable) public static function make($invokable) { if ($invokable->implicit ?? false) { - return new class($invokable) extends InvokableValidationRule implements ImplicitRule { + return new class($invokable) extends InvokableValidationRule implements ImplicitRule + { }; } diff --git a/tests/Bus/BusPendingBatchTest.php b/tests/Bus/BusPendingBatchTest.php index b9cc08066103..4133054577c7 100644 --- a/tests/Bus/BusPendingBatchTest.php +++ b/tests/Bus/BusPendingBatchTest.php @@ -71,7 +71,9 @@ public function test_batch_is_deleted_from_storage_if_exception_thrown_during_ba $container = new Container; - $job = new class {}; + $job = new class + { + }; $pendingBatch = new PendingBatch($container, new Collection([$job])); @@ -225,7 +227,9 @@ public function test_batch_before_event_is_called() public function test_it_throws_exception_if_batched_job_is_not_batchable(): void { - $nonBatchableJob = new class {}; + $nonBatchableJob = new class + { + }; $this->expectException(RuntimeException::class); @@ -240,7 +244,9 @@ public function test_it_throws_an_exception_if_batched_job_contains_batch_with_n new PendingBatch( $container, new Collection( - [new PendingBatch($container, new Collection([new BatchableJob, new class {}]))] + [new PendingBatch($container, new Collection([new BatchableJob, new class + { + }]))] ) ); } diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php index 3eeee6beb228..47f89631865e 100755 --- a/tests/Database/DatabaseAbstractSchemaGrammarTest.php +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -17,7 +17,9 @@ protected function tearDown(): void public function testCreateDatabase() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar {}; + $grammar = new class($connection) extends Grammar + { + }; $this->assertSame('create database "foo"', $grammar->compileCreateDatabase('foo')); } @@ -25,7 +27,9 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar {}; + $grammar = new class($connection) extends Grammar + { + }; $this->assertSame('drop database if exists "foo"', $grammar->compileDropDatabaseIfExists('foo')); } diff --git a/tests/Database/DatabaseEloquentInverseRelationTest.php b/tests/Database/DatabaseEloquentInverseRelationTest.php index f860e297a410..49cbfc4f304b 100755 --- a/tests/Database/DatabaseEloquentInverseRelationTest.php +++ b/tests/Database/DatabaseEloquentInverseRelationTest.php @@ -288,7 +288,9 @@ public function testOnlyHydratesInverseRelationOnModels() [], new HasInverseRelationRelatedStub(), 'foo', - new class() {}, + new class() + { + }, new HasInverseRelationRelatedStub(), ]); } diff --git a/tests/Encryption/EncrypterTest.php b/tests/Encryption/EncrypterTest.php index fa55d068a663..54d2e74530ff 100755 --- a/tests/Encryption/EncrypterTest.php +++ b/tests/Encryption/EncrypterTest.php @@ -248,9 +248,13 @@ public static function provideTamperedData() return [ [['iv' => ['value_in_array'], 'value' => '', 'mac' => '']], - [['iv' => new class() {}, 'value' => '', 'mac' => '']], + [['iv' => new class() + { + }, 'value' => '', 'mac' => '']], [['iv' => $validIv, 'value' => ['value_in_array'], 'mac' => '']], - [['iv' => $validIv, 'value' => new class() {}, 'mac' => '']], + [['iv' => $validIv, 'value' => new class() + { + }, 'mac' => '']], [['iv' => $validIv, 'value' => '', 'mac' => ['value_in_array']]], [['iv' => $validIv, 'value' => '', 'mac' => null]], [['iv' => $validIv, 'value' => '', 'mac' => '', 'tag' => ['value_in_array']]], diff --git a/tests/Http/JsonResourceTest.php b/tests/Http/JsonResourceTest.php index a39b3e402b52..f74a7303dbb8 100644 --- a/tests/Http/JsonResourceTest.php +++ b/tests/Http/JsonResourceTest.php @@ -12,7 +12,9 @@ class JsonResourceTest extends TestCase { public function testJsonResourceNullAttributes() { - $model = new class extends Model {}; + $model = new class extends Model + { + }; $model->setAttribute('relation_sum_column', null); $model->setAttribute('relation_count', null); @@ -31,7 +33,9 @@ public function testJsonResourceNullAttributes() public function testJsonResourceToJsonSucceedsWithPriorErrors(): void { - $model = new class extends Model {}; + $model = new class extends Model + { + }; $resource = m::mock(JsonResource::class, ['resource' => $model]) ->makePartial() diff --git a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php index 4756ceb26662..d23682982dce 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php @@ -19,7 +19,9 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator {})->setCollection($items); + $p = (new class extends AbstractCursorPaginator + { + })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); } diff --git a/tests/Pagination/CursorPaginatorLoadMorphTest.php b/tests/Pagination/CursorPaginatorLoadMorphTest.php index 217a8ccf93ed..807c1b319a04 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphTest.php @@ -19,7 +19,9 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator {})->setCollection($items); + $p = (new class extends AbstractCursorPaginator + { + })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); } diff --git a/tests/Pagination/PaginatorLoadMorphCountTest.php b/tests/Pagination/PaginatorLoadMorphCountTest.php index f0e09d230b1a..7929ffabf56e 100644 --- a/tests/Pagination/PaginatorLoadMorphCountTest.php +++ b/tests/Pagination/PaginatorLoadMorphCountTest.php @@ -19,7 +19,9 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator {})->setCollection($items); + $p = (new class extends AbstractPaginator + { + })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); } diff --git a/tests/Pagination/PaginatorLoadMorphTest.php b/tests/Pagination/PaginatorLoadMorphTest.php index c7b4c1287ad0..b4ed7b759558 100644 --- a/tests/Pagination/PaginatorLoadMorphTest.php +++ b/tests/Pagination/PaginatorLoadMorphTest.php @@ -19,7 +19,9 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator {})->setCollection($items); + $p = (new class extends AbstractPaginator + { + })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 41b5f06f629f..a0f411dc2bc2 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2371,9 +2371,13 @@ public function testImplode($collection) #[DataProvider('collectionClassProvider')] public function testImplodeModels($collection) { - $model = new class extends Model {}; + $model = new class extends Model + { + }; $model->setAttribute('email', 'foo'); - $modelTwo = new class extends Model {}; + $modelTwo = new class extends Model + { + }; $modelTwo->setAttribute('email', 'bar'); $data = new $collection([$model, $modelTwo]); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 0ce3b601a9d6..1054c8694005 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -925,7 +925,9 @@ public function testCustomException() $v = new Validator($trans, ['name' => ''], ['name' => 'required']); - $exception = new class($v) extends ValidationException {}; + $exception = new class($v) extends ValidationException + { + }; $v->setException($exception); try { diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index bc181d1e57a0..e28a168cda33 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -796,7 +796,9 @@ public function __toString() } }; - $model = new class extends Model {}; + $model = new class extends Model + { + }; $this->assertEquals(e(''), BladeCompiler::sanitizeComponentAttribute('')); $this->assertEquals(e('1'), BladeCompiler::sanitizeComponentAttribute('1')); From de9daa4c75e808dd8dd830729da46ecccdcc7c31 Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Thu, 13 Mar 2025 18:38:42 +0330 Subject: [PATCH 184/455] Add test to verify connection name detection in Unique rule. (#54993) --- tests/Validation/ValidationUniqueRuleTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Validation/ValidationUniqueRuleTest.php b/tests/Validation/ValidationUniqueRuleTest.php index 8e7ae62c5582..740d829927a3 100644 --- a/tests/Validation/ValidationUniqueRuleTest.php +++ b/tests/Validation/ValidationUniqueRuleTest.php @@ -80,6 +80,10 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $rule = new Unique('table'); $rule->where('foo', '"bar"'); $this->assertSame('unique:table,NULL,NULL,id,foo,"""bar"""', (string) $rule); + + $rule = new Unique(EloquentModelWithConnection::class, 'column'); + $rule->where('foo', 'bar'); + $this->assertSame('unique:mysql.table,column,NULL,id,foo,"bar"', (string) $rule); } public function testItIgnoresSoftDeletes() @@ -170,3 +174,8 @@ public function __construct($bar, $baz) $this->baz = $baz; } } + +class EloquentModelWithConnection extends EloquentModelStub +{ + protected $connection = 'mysql'; +} From 3ba180a9f1b8c09948ba41570a6c9af79a00a13d Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Thu, 13 Mar 2025 15:09:20 +0000 Subject: [PATCH 185/455] Apply fixes from StyleCI --- src/Illuminate/Validation/InvokableValidationRule.php | 3 +-- tests/Bus/BusPendingBatchTest.php | 9 +++------ tests/Database/DatabaseAbstractSchemaGrammarTest.php | 6 ++---- tests/Database/DatabaseEloquentInverseRelationTest.php | 3 +-- tests/Encryption/EncrypterTest.php | 6 ++---- tests/Http/JsonResourceTest.php | 6 ++---- tests/Pagination/CursorPaginatorLoadMorphCountTest.php | 3 +-- tests/Pagination/CursorPaginatorLoadMorphTest.php | 3 +-- tests/Pagination/PaginatorLoadMorphCountTest.php | 3 +-- tests/Pagination/PaginatorLoadMorphTest.php | 3 +-- tests/Support/SupportCollectionTest.php | 6 ++---- tests/Validation/ValidationValidatorTest.php | 3 +-- tests/View/Blade/BladeComponentTagCompilerTest.php | 3 +-- 13 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index e8aaf55af17b..c9e43943ef59 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -69,8 +69,7 @@ protected function __construct(ValidationRule|InvokableRule $invokable) public static function make($invokable) { if ($invokable->implicit ?? false) { - return new class($invokable) extends InvokableValidationRule implements ImplicitRule - { + return new class($invokable) extends InvokableValidationRule implements ImplicitRule { }; } diff --git a/tests/Bus/BusPendingBatchTest.php b/tests/Bus/BusPendingBatchTest.php index 4133054577c7..baed6e2726b6 100644 --- a/tests/Bus/BusPendingBatchTest.php +++ b/tests/Bus/BusPendingBatchTest.php @@ -71,8 +71,7 @@ public function test_batch_is_deleted_from_storage_if_exception_thrown_during_ba $container = new Container; - $job = new class - { + $job = new class { }; $pendingBatch = new PendingBatch($container, new Collection([$job])); @@ -227,8 +226,7 @@ public function test_batch_before_event_is_called() public function test_it_throws_exception_if_batched_job_is_not_batchable(): void { - $nonBatchableJob = new class - { + $nonBatchableJob = new class { }; $this->expectException(RuntimeException::class); @@ -244,8 +242,7 @@ public function test_it_throws_an_exception_if_batched_job_contains_batch_with_n new PendingBatch( $container, new Collection( - [new PendingBatch($container, new Collection([new BatchableJob, new class - { + [new PendingBatch($container, new Collection([new BatchableJob, new class { }]))] ) ); diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php index 47f89631865e..87340615e399 100755 --- a/tests/Database/DatabaseAbstractSchemaGrammarTest.php +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -17,8 +17,7 @@ protected function tearDown(): void public function testCreateDatabase() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar - { + $grammar = new class($connection) extends Grammar { }; $this->assertSame('create database "foo"', $grammar->compileCreateDatabase('foo')); @@ -27,8 +26,7 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar - { + $grammar = new class($connection) extends Grammar { }; $this->assertSame('drop database if exists "foo"', $grammar->compileDropDatabaseIfExists('foo')); diff --git a/tests/Database/DatabaseEloquentInverseRelationTest.php b/tests/Database/DatabaseEloquentInverseRelationTest.php index 49cbfc4f304b..7f6c9d1e9366 100755 --- a/tests/Database/DatabaseEloquentInverseRelationTest.php +++ b/tests/Database/DatabaseEloquentInverseRelationTest.php @@ -288,8 +288,7 @@ public function testOnlyHydratesInverseRelationOnModels() [], new HasInverseRelationRelatedStub(), 'foo', - new class() - { + new class() { }, new HasInverseRelationRelatedStub(), ]); diff --git a/tests/Encryption/EncrypterTest.php b/tests/Encryption/EncrypterTest.php index 54d2e74530ff..78c45723105d 100755 --- a/tests/Encryption/EncrypterTest.php +++ b/tests/Encryption/EncrypterTest.php @@ -248,12 +248,10 @@ public static function provideTamperedData() return [ [['iv' => ['value_in_array'], 'value' => '', 'mac' => '']], - [['iv' => new class() - { + [['iv' => new class() { }, 'value' => '', 'mac' => '']], [['iv' => $validIv, 'value' => ['value_in_array'], 'mac' => '']], - [['iv' => $validIv, 'value' => new class() - { + [['iv' => $validIv, 'value' => new class() { }, 'mac' => '']], [['iv' => $validIv, 'value' => '', 'mac' => ['value_in_array']]], [['iv' => $validIv, 'value' => '', 'mac' => null]], diff --git a/tests/Http/JsonResourceTest.php b/tests/Http/JsonResourceTest.php index f74a7303dbb8..5e1e0d029ae7 100644 --- a/tests/Http/JsonResourceTest.php +++ b/tests/Http/JsonResourceTest.php @@ -12,8 +12,7 @@ class JsonResourceTest extends TestCase { public function testJsonResourceNullAttributes() { - $model = new class extends Model - { + $model = new class extends Model { }; $model->setAttribute('relation_sum_column', null); @@ -33,8 +32,7 @@ public function testJsonResourceNullAttributes() public function testJsonResourceToJsonSucceedsWithPriorErrors(): void { - $model = new class extends Model - { + $model = new class extends Model { }; $resource = m::mock(JsonResource::class, ['resource' => $model]) diff --git a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php index d23682982dce..71fbc565e444 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator - { + $p = (new class extends AbstractCursorPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); diff --git a/tests/Pagination/CursorPaginatorLoadMorphTest.php b/tests/Pagination/CursorPaginatorLoadMorphTest.php index 807c1b319a04..fe1aa8faa5f7 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator - { + $p = (new class extends AbstractCursorPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); diff --git a/tests/Pagination/PaginatorLoadMorphCountTest.php b/tests/Pagination/PaginatorLoadMorphCountTest.php index 7929ffabf56e..8221c6da7dfb 100644 --- a/tests/Pagination/PaginatorLoadMorphCountTest.php +++ b/tests/Pagination/PaginatorLoadMorphCountTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator - { + $p = (new class extends AbstractPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); diff --git a/tests/Pagination/PaginatorLoadMorphTest.php b/tests/Pagination/PaginatorLoadMorphTest.php index b4ed7b759558..c3ab5a5bf902 100644 --- a/tests/Pagination/PaginatorLoadMorphTest.php +++ b/tests/Pagination/PaginatorLoadMorphTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator - { + $p = (new class extends AbstractPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index a0f411dc2bc2..0e246dc8f3d5 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2371,12 +2371,10 @@ public function testImplode($collection) #[DataProvider('collectionClassProvider')] public function testImplodeModels($collection) { - $model = new class extends Model - { + $model = new class extends Model { }; $model->setAttribute('email', 'foo'); - $modelTwo = new class extends Model - { + $modelTwo = new class extends Model { }; $modelTwo->setAttribute('email', 'bar'); $data = new $collection([$model, $modelTwo]); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 1054c8694005..167711851fab 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -925,8 +925,7 @@ public function testCustomException() $v = new Validator($trans, ['name' => ''], ['name' => 'required']); - $exception = new class($v) extends ValidationException - { + $exception = new class($v) extends ValidationException { }; $v->setException($exception); diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index e28a168cda33..da1fffbd63c5 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -796,8 +796,7 @@ public function __toString() } }; - $model = new class extends Model - { + $model = new class extends Model { }; $this->assertEquals(e(''), BladeCompiler::sanitizeComponentAttribute('')); From b7ab1c74948af1c3b3eaeb2d3ee640f25a4d6ecc Mon Sep 17 00:00:00 2001 From: Fuwasegu <52437973+fuwasegu@users.noreply.github.com> Date: Fri, 14 Mar 2025 00:21:09 +0900 Subject: [PATCH 186/455] [12.x] Add json:unicode cast to support JSON_UNESCAPED_UNICODE encoding (#54992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 add json:unicode cast type * test: 💍 add tests * feat: 🎸 add getJsonCastFlags method * Update HasAttributes.php --------- Co-authored-by: Taylor Otwell --- .../Database/Eloquent/Casts/Json.php | 4 +- .../Eloquent/Concerns/HasAttributes.php | 30 ++++++++-- tests/Database/DatabaseEloquentModelTest.php | 58 +++++++++++++++++++ 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Casts/Json.php b/src/Illuminate/Database/Eloquent/Casts/Json.php index 11bd16a6d8b8..970b309dbb94 100644 --- a/src/Illuminate/Database/Eloquent/Casts/Json.php +++ b/src/Illuminate/Database/Eloquent/Casts/Json.php @@ -21,9 +21,9 @@ class Json /** * Encode the given value. */ - public static function encode(mixed $value): mixed + public static function encode(mixed $value, int $flags = 0): mixed { - return isset(static::$encoder) ? (static::$encoder)($value) : json_encode($value); + return isset(static::$encoder) ? (static::$encoder)($value) : json_encode($value, $flags); } /** diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index c79f3483a4e6..6947a9e023ba 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -117,6 +117,7 @@ trait HasAttributes 'int', 'integer', 'json', + 'json:unicode', 'object', 'real', 'string', @@ -837,6 +838,7 @@ protected function castAttribute($key, $value) return $this->fromJson($value, true); case 'array': case 'json': + case 'json:unicode': return $this->fromJson($value); case 'collection': return new BaseCollection($this->fromJson($value)); @@ -1178,7 +1180,7 @@ public function fillJsonAttribute($key, $value) $value = $this->asJson($this->getArrayAttributeWithValue( $path, $key, $value - )); + ), $this->hasCast($key, ['json:unicode'])); $this->attributes[$key] = $this->isEncryptedCastable($key) ? $this->castAttributeAsEncryptedString($key, $value) @@ -1313,7 +1315,7 @@ protected function getArrayAttributeByKey($key) */ protected function castAttributeAsJson($key, $value) { - $value = $this->asJson($value); + $value = $this->asJson($value, $this->getJsonCastFlags($key)); if ($value === false) { throw JsonEncodingException::forAttribute( @@ -1324,15 +1326,33 @@ protected function castAttributeAsJson($key, $value) return $value; } + /** + * Get the JSON casting flags for the given attribute. + * + * @param string $key + * @return int + */ + protected function getJsonCastFlags($key) + { + $flags = 0; + + if ($this->hasCast($key, ['json:unicode'])) { + $flags |= JSON_UNESCAPED_UNICODE; + } + + return $flags; + } + /** * Encode the given value as JSON. * * @param mixed $value + * @param int $flags * @return string */ - protected function asJson($value) + protected function asJson($value, $flags = 0) { - return Json::encode($value); + return Json::encode($value, $flags); } /** @@ -1669,7 +1689,7 @@ protected function isDateCastableWithCustomFormat($key) */ protected function isJsonCastable($key) { - return $this->hasCast($key, ['array', 'json', 'object', 'collection', 'encrypted:array', 'encrypted:collection', 'encrypted:json', 'encrypted:object']); + return $this->hasCast($key, ['array', 'json', 'json:unicode', 'object', 'collection', 'encrypted:array', 'encrypted:collection', 'encrypted:json', 'encrypted:object']); } /** diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 470164cfeec8..2095f267a2a6 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -2472,6 +2472,7 @@ public function testModelAttributesAreCastedWhenPresentInCastsPropertyOrCastsMet $obj->foo = 'bar'; $model->arrayAttribute = $obj; $model->jsonAttribute = ['foo' => 'bar']; + $model->jsonAttributeWithUnicode = ['こんにちは' => '世界']; $model->dateAttribute = '1969-07-20'; $model->datetimeAttribute = '1969-07-20 22:56:00'; $model->timestampAttribute = '1969-07-20 22:56:00'; @@ -2486,12 +2487,15 @@ public function testModelAttributesAreCastedWhenPresentInCastsPropertyOrCastsMet $this->assertIsObject($model->objectAttribute); $this->assertIsArray($model->arrayAttribute); $this->assertIsArray($model->jsonAttribute); + $this->assertIsArray($model->jsonAttributeWithUnicode); $this->assertTrue($model->boolAttribute); $this->assertFalse($model->booleanAttribute); $this->assertEquals($obj, $model->objectAttribute); $this->assertEquals(['foo' => 'bar'], $model->arrayAttribute); $this->assertEquals(['foo' => 'bar'], $model->jsonAttribute); $this->assertSame('{"foo":"bar"}', $model->jsonAttributeValue()); + $this->assertEquals(['こんにちは' => '世界'], $model->jsonAttributeWithUnicode); + $this->assertSame('{"こんにちは":"世界"}', $model->jsonAttributeWithUnicodeValue()); $this->assertInstanceOf(Carbon::class, $model->dateAttribute); $this->assertInstanceOf(Carbon::class, $model->datetimeAttribute); $this->assertInstanceOf(BaseCollection::class, $model->collectionAttribute); @@ -2510,12 +2514,14 @@ public function testModelAttributesAreCastedWhenPresentInCastsPropertyOrCastsMet $this->assertIsObject($arr['objectAttribute']); $this->assertIsArray($arr['arrayAttribute']); $this->assertIsArray($arr['jsonAttribute']); + $this->assertIsArray($arr['jsonAttributeWithUnicode']); $this->assertIsArray($arr['collectionAttribute']); $this->assertTrue($arr['boolAttribute']); $this->assertFalse($arr['booleanAttribute']); $this->assertEquals($obj, $arr['objectAttribute']); $this->assertEquals(['foo' => 'bar'], $arr['arrayAttribute']); $this->assertEquals(['foo' => 'bar'], $arr['jsonAttribute']); + $this->assertEquals(['こんにちは' => '世界'], $arr['jsonAttributeWithUnicode']); $this->assertSame('1969-07-20 00:00:00', $arr['dateAttribute']); $this->assertSame('1969-07-20 22:56:00', $arr['datetimeAttribute']); $this->assertEquals(-14173440, $arr['timestampAttribute']); @@ -2544,6 +2550,7 @@ public function testModelAttributeCastingPreservesNull() $model->objectAttribute = null; $model->arrayAttribute = null; $model->jsonAttribute = null; + $model->jsonAttributeWithUnicode = null; $model->dateAttribute = null; $model->datetimeAttribute = null; $model->timestampAttribute = null; @@ -2559,6 +2566,7 @@ public function testModelAttributeCastingPreservesNull() $this->assertNull($attributes['objectAttribute']); $this->assertNull($attributes['arrayAttribute']); $this->assertNull($attributes['jsonAttribute']); + $this->assertNull($attributes['jsonAttributeWithUnicode']); $this->assertNull($attributes['dateAttribute']); $this->assertNull($attributes['datetimeAttribute']); $this->assertNull($attributes['timestampAttribute']); @@ -2572,6 +2580,7 @@ public function testModelAttributeCastingPreservesNull() $this->assertNull($model->objectAttribute); $this->assertNull($model->arrayAttribute); $this->assertNull($model->jsonAttribute); + $this->assertNull($model->jsonAttributeWithUnicode); $this->assertNull($model->dateAttribute); $this->assertNull($model->datetimeAttribute); $this->assertNull($model->timestampAttribute); @@ -2587,6 +2596,7 @@ public function testModelAttributeCastingPreservesNull() $this->assertNull($array['objectAttribute']); $this->assertNull($array['arrayAttribute']); $this->assertNull($array['jsonAttribute']); + $this->assertNull($array['jsonAttributeWithUnicode']); $this->assertNull($array['dateAttribute']); $this->assertNull($array['datetimeAttribute']); $this->assertNull($array['timestampAttribute']); @@ -2603,11 +2613,45 @@ public function testModelAttributeCastingFailsOnUnencodableData() $obj = new stdClass; $obj->foo = "b\xF8r"; $model->arrayAttribute = $obj; + + $model->getAttributes(); + } + + public function testModelJsonCastingFailsOnUnencodableData() + { + $this->expectException(JsonEncodingException::class); + $this->expectExceptionMessage('Unable to encode attribute [jsonAttribute] for model [Illuminate\Tests\Database\EloquentModelCastingStub] to JSON: Malformed UTF-8 characters, possibly incorrectly encoded.'); + + $model = new EloquentModelCastingStub; $model->jsonAttribute = ['foo' => "b\xF8r"]; $model->getAttributes(); } + public function testModelAttributeCastingFailsOnUnencodableDataWithUnicode() + { + $this->expectException(JsonEncodingException::class); + $this->expectExceptionMessage('Unable to encode attribute [jsonAttributeWithUnicode] for model [Illuminate\Tests\Database\EloquentModelCastingStub] to JSON: Malformed UTF-8 characters, possibly incorrectly encoded.'); + + $model = new EloquentModelCastingStub; + $model->jsonAttributeWithUnicode = ['foo' => "b\xF8r"]; + + $model->getAttributes(); + } + + public function testJsonCastingRespectsUnicodeOption() + { + $data = ['こんにちは' => '世界']; + $model = new EloquentModelCastingStub; + $model->jsonAttribute = $data; + $model->jsonAttributeWithUnicode = $data; + + $this->assertSame('{"\u3053\u3093\u306b\u3061\u306f":"\u4e16\u754c"}', $model->jsonAttributeValue()); + $this->assertSame('{"こんにちは":"世界"}', $model->jsonAttributeWithUnicodeValue()); + $this->assertSame(['こんにちは' => '世界'], $model->jsonAttribute); + $this->assertSame(['こんにちは' => '世界'], $model->jsonAttributeWithUnicode); + } + public function testModelAttributeCastingWithFloats() { $model = new EloquentModelCastingStub; @@ -3028,6 +3072,7 @@ public function testGetOriginalCastsAttributes() $collection = collect($array); $model->arrayAttribute = $array; $model->jsonAttribute = $array; + $model->jsonAttributeWithUnicode = $array; $model->collectionAttribute = $collection; $model->syncOriginal(); @@ -3044,6 +3089,9 @@ public function testGetOriginalCastsAttributes() $model->jsonAttribute = [ 'foo' => 'bar2', ]; + $model->jsonAttributeWithUnicode = [ + 'foo' => 'bar2', + ]; $model->collectionAttribute = collect([ 'foo' => 'bar2', ]); @@ -3080,6 +3128,10 @@ public function testGetOriginalCastsAttributes() $this->assertEquals(['foo' => 'bar'], $model->getOriginal('jsonAttribute')); $this->assertEquals(['foo' => 'bar2'], $model->getAttribute('jsonAttribute')); + $this->assertEquals($array, $model->getOriginal('jsonAttributeWithUnicode')); + $this->assertEquals(['foo' => 'bar'], $model->getOriginal('jsonAttributeWithUnicode')); + $this->assertEquals(['foo' => 'bar2'], $model->getAttribute('jsonAttributeWithUnicode')); + $this->assertEquals(['foo' => 'bar'], $model->getOriginal('collectionAttribute')->toArray()); $this->assertEquals(['foo' => 'bar2'], $model->getAttribute('collectionAttribute')->toArray()); } @@ -3596,6 +3648,7 @@ class EloquentModelCastingStub extends Model 'boolAttribute' => 'bool', 'objectAttribute' => 'object', 'jsonAttribute' => 'json', + 'jsonAttributeWithUnicode' => 'json:unicode', 'dateAttribute' => 'date', 'timestampAttribute' => 'timestamp', 'ascollectionAttribute' => AsCollection::class, @@ -3633,6 +3686,11 @@ public function jsonAttributeValue() return $this->attributes['jsonAttribute']; } + public function jsonAttributeWithUnicodeValue() + { + return $this->attributes['jsonAttributeWithUnicode']; + } + protected function serializeDate(DateTimeInterface $date) { return $date->format('Y-m-d H:i:s'); From 8f635746ffc37c0caf27ac4d21d4f0598dd03a34 Mon Sep 17 00:00:00 2001 From: Adam Patterson Date: Thu, 13 Mar 2025 09:31:01 -0600 Subject: [PATCH 187/455] =?UTF-8?q?[12.x]=20Add=20=E2=80=9CStorage=20Linke?= =?UTF-8?q?d=E2=80=9D=20to=20the=20`about`=20command=20(#54949)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [12.x] Add “Storage Linked” to the `about` command * Style CI fixes * Style CI fix * formatting --------- Co-authored-by: Taylor Otwell --- .../Foundation/Console/AboutCommand.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Illuminate/Foundation/Console/AboutCommand.php b/src/Illuminate/Foundation/Console/AboutCommand.php index b7d39b775c43..26fa04446df9 100644 --- a/src/Illuminate/Foundation/Console/AboutCommand.php +++ b/src/Illuminate/Foundation/Console/AboutCommand.php @@ -165,6 +165,7 @@ protected function gatherApplicationInformation() $formatEnabledStatus = fn ($value) => $value ? 'ENABLED' : 'OFF'; $formatCachedStatus = fn ($value) => $value ? 'CACHED' : 'NOT CACHED'; + $formatStorageLinkedStatus = fn ($value) => $value ? 'LINKED' : 'NOT LINKED'; static::addToSection('Environment', fn () => [ 'Application Name' => config('app.name'), @@ -214,9 +215,30 @@ protected function gatherApplicationInformation() 'Session' => config('session.driver'), ])); + static::addToSection('Storage', fn () => [ + ...$this->determineStoragePathLinkStatus($formatStorageLinkedStatus), + ]); + (new Collection(static::$customDataResolvers))->each->__invoke(); } + /** + * Determine storage symbolic links status. + * + * @param callable $formatStorageLinkedStatus + * @return array + */ + protected function determineStoragePathLinkStatus(callable $formatStorageLinkedStatus): array + { + return collect(config('filesystems.links', [])) + ->mapWithKeys(function ($target, $link) use ($formatStorageLinkedStatus) { + $path = Str::replace(public_path(), '', $link); + + return [public_path($path) => static::format(file_exists($link), console: $formatStorageLinkedStatus)]; + }) + ->toArray(); + } + /** * Determine whether the given directory has PHP files. * From 95a8561b55306d2eae8d1268cfea68170a6ea604 Mon Sep 17 00:00:00 2001 From: Fuwasegu <52437973+fuwasegu@users.noreply.github.com> Date: Fri, 14 Mar 2025 00:37:16 +0900 Subject: [PATCH 188/455] [12.x] Add support for native JSON/JSONB column types in SQLite Schema builder (#54991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 add use_native_json option * test: 💍 add schema tests * fix: 🐛 delete var_dump * formatting --------- Co-authored-by: Taylor Otwell --- .../Schema/Grammars/SQLiteGrammar.php | 4 +- .../DatabaseSQLiteSchemaGrammarTest.php | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 624d98c8b800..a785b0881662 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -891,7 +891,7 @@ protected function typeEnum(Fluent $column) */ protected function typeJson(Fluent $column) { - return 'text'; + return $this->connection->getConfig('use_native_json') ? 'json' : 'text'; } /** @@ -902,7 +902,7 @@ protected function typeJson(Fluent $column) */ protected function typeJsonb(Fluent $column) { - return 'text'; + return $this->connection->getConfig('use_native_jsonb') ? 'jsonb' : 'text'; } /** diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index f061c2a067a8..d9233f548fa9 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -582,6 +582,25 @@ public function testAddingJson() $this->assertSame('alter table "users" add column "foo" text not null', $statements[0]); } + public function testAddingNativeJson() + { + $connection = m::mock(Connection::class); + $connection + ->shouldReceive('getTablePrefix')->andReturn('') + ->shouldReceive('getConfig')->once()->with('use_native_json')->andReturn(true) + ->shouldReceive('getSchemaGrammar')->andReturn($this->getGrammar($connection)) + ->shouldReceive('getSchemaBuilder')->andReturn($this->getBuilder()) + ->shouldReceive('getServerVersion')->andReturn('3.35') + ->getMock(); + + $blueprint = new Blueprint($connection, 'users'); + $blueprint->json('foo'); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "foo" json not null', $statements[0]); + } + public function testAddingJsonb() { $blueprint = new Blueprint($this->getConnection(), 'users'); @@ -592,6 +611,25 @@ public function testAddingJsonb() $this->assertSame('alter table "users" add column "foo" text not null', $statements[0]); } + public function testAddingNativeJsonb() + { + $connection = m::mock(Connection::class); + $connection + ->shouldReceive('getTablePrefix')->andReturn('') + ->shouldReceive('getConfig')->once()->with('use_native_jsonb')->andReturn(true) + ->shouldReceive('getSchemaGrammar')->andReturn($this->getGrammar($connection)) + ->shouldReceive('getSchemaBuilder')->andReturn($this->getBuilder()) + ->shouldReceive('getServerVersion')->andReturn('3.35') + ->getMock(); + + $blueprint = new Blueprint($connection, 'users'); + $blueprint->jsonb('foo'); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add column "foo" jsonb not null', $statements[0]); + } + public function testAddingDate() { $blueprint = new Blueprint($this->getConnection(), 'users'); From 9a5efbcfad3c4680abac22b63413f05a6358cde4 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Thu, 13 Mar 2025 11:51:26 -0400 Subject: [PATCH 189/455] Update LogManager.php (#55016) --- src/Illuminate/Log/LogManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index d8f48c06b44f..de67c44057f8 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -554,7 +554,7 @@ protected function getFallbackChannelName() * Get the log connection configuration. * * @param string $name - * @return array + * @return array|null */ protected function configurationFor($name) { From 2367af38eb26ef59984cb00e0e2328a7365c0bf0 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Fri, 14 Mar 2025 20:51:23 +0330 Subject: [PATCH 190/455] [12.x] Add missing tests for LazyCollection methods (#55022) * Add test for collapseWithKeys method in LazyCollection This commit adds test coverage for the collapseWithKeys method, verifying: - Nested arrays collapse correctly with preserved keys - Mixed arrays and collections are handled properly - Empty items are skipped as expected * Add test for containsOneItem method in LazyCollection * Add test for doesntContain method in LazyCollection This commit adds test coverage for the doesntContain method, verifying it correctly returns the inverse of contains method for: - Direct value comparison - Key-value pair matching - Comparison operators - Callback functions * Add test for dot method in LazyCollection This commit adds test coverage for the dot method, verifying it correctly flattens multi-dimensional arrays with dot notation in keys for: - Nested associative arrays - Empty nested arrays - Arrays with numeric keys --- tests/Support/SupportLazyCollectionTest.php | 92 +++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index a199de262330..5fe161cd9025 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -355,4 +355,96 @@ public function testShuffle() $this->assertTrue($shuffled->contains('name', 'Taylor')); $this->assertTrue($shuffled->contains('name', 'Jeffrey')); } + + public function testCollapseWithKeys() + { + $collection = new LazyCollection([ + ['a' => 1, 'b' => 2], + ['c' => 3, 'd' => 4], + ]); + $collapsed = $collection->collapseWithKeys(); + + $this->assertEquals(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], $collapsed->all()); + + $collection = new LazyCollection([ + ['a' => 1], + new LazyCollection(['b' => 2]), + ]); + $collapsed = $collection->collapseWithKeys(); + + $this->assertEquals(['a' => 1, 'b' => 2], $collapsed->all()); + } + + public function testContainsOneItem() + { + $collection = new LazyCollection([5]); + $this->assertTrue($collection->containsOneItem()); + + $emptyCollection = new LazyCollection([]); + $this->assertFalse($emptyCollection->containsOneItem()); + + $multipleCollection = new LazyCollection([1, 2, 3]); + $this->assertFalse($multipleCollection->containsOneItem()); + } + + public function testDoesntContain() + { + $collection = new LazyCollection([1, 2, 3, 4, 5]); + + $this->assertTrue($collection->doesntContain(10)); + $this->assertFalse($collection->doesntContain(3)); + $this->assertTrue($collection->doesntContain('value', '>', 10)); + $this->assertTrue($collection->doesntContain(function ($value) { + return $value > 10; + })); + + $users = new LazyCollection([ + [ + 'name' => 'Taylor', + 'role' => 'developer', + ], + [ + 'name' => 'Jeffrey', + 'role' => 'designer', + ], + ]); + + $this->assertTrue($users->doesntContain('name', 'Adam')); + $this->assertFalse($users->doesntContain('name', 'Taylor')); + } + + public function testDot() + { + $collection = new LazyCollection([ + 'foo' => [ + 'bar' => 'baz', + ], + 'user' => [ + 'name' => 'Taylor', + 'profile' => [ + 'age' => 30, + ], + ], + 'users' => [ + 0 => [ + 'name' => 'Taylor', + ], + 1 => [ + 'name' => 'Jeffrey', + ], + ], + ]); + + $dotted = $collection->dot(); + + $expected = [ + 'foo.bar' => 'baz', + 'user.name' => 'Taylor', + 'user.profile.age' => 30, + 'users.0.name' => 'Taylor', + 'users.1.name' => 'Jeffrey', + ]; + + $this->assertEquals($expected, $dotted->all()); + } } From d7c898f3953d19206cce9cd10cdd5dda0c20d8ac Mon Sep 17 00:00:00 2001 From: Ahmed Alaa <92916738+AhmedAlaa4611@users.noreply.github.com> Date: Fri, 14 Mar 2025 19:21:43 +0200 Subject: [PATCH 191/455] Refactor: Structural improvement for clarity (#55018) --- config/logging.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/logging.php b/config/logging.php index 8d94292b29f4..1345f6f66c51 100644 --- a/config/logging.php +++ b/config/logging.php @@ -98,10 +98,10 @@ 'driver' => 'monolog', 'level' => env('LOG_LEVEL', 'debug'), 'handler' => StreamHandler::class, - 'formatter' => env('LOG_STDERR_FORMATTER'), - 'with' => [ + 'handler_with' => [ 'stream' => 'php://stderr', ], + 'formatter' => env('LOG_STDERR_FORMATTER'), 'processors' => [PsrLogMessageProcessor::class], ], From c596d6448dc6379251145af7a13b41644c3453da Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Fri, 14 Mar 2025 20:52:52 +0330 Subject: [PATCH 192/455] Improve `toKilobytes` to handle spaces and case-insensitive units (#55019) * Improve `toKilobytes` to handle spaces and case-insensitive units in File rule validation * Update File.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Validation/Rules/File.php | 2 ++ tests/Validation/ValidationFileRuleTest.php | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Illuminate/Validation/Rules/File.php b/src/Illuminate/Validation/Rules/File.php index 0aa0d71ce35f..b7589853e9d2 100644 --- a/src/Illuminate/Validation/Rules/File.php +++ b/src/Illuminate/Validation/Rules/File.php @@ -217,6 +217,8 @@ protected function toKilobytes($size) return $size; } + $size = strtolower(trim($size)); + $value = floatval($size); return round(match (true) { diff --git a/tests/Validation/ValidationFileRuleTest.php b/tests/Validation/ValidationFileRuleTest.php index c70783da69bd..0d95bb2a8e66 100644 --- a/tests/Validation/ValidationFileRuleTest.php +++ b/tests/Validation/ValidationFileRuleTest.php @@ -418,6 +418,27 @@ public function testItCanSetDefaultUsing() ); } + public function testFileSizeConversionWithDifferentUnits() + { + $this->passes( + File::image()->size('5MB'), + UploadedFile::fake()->create('foo.png', 5000) + ); + + $this->passes( + File::image()->size(' 2gb '), + UploadedFile::fake()->create('foo.png', 2 * 1000000) + ); + + $this->passes( + File::image()->size('1Tb'), + UploadedFile::fake()->create('foo.png', 1000000000) + ); + + $this->expectException(\InvalidArgumentException::class); + File::image()->size('10xyz'); + } + protected function setUp(): void { $container = Container::getInstance(); From 3e8baf58bb09bb51d4e94d9546ffcdf07d83270d Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Fri, 14 Mar 2025 12:24:16 -0500 Subject: [PATCH 193/455] Fix `asJson` call (#55017) --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 6947a9e023ba..5f2d6fea5c70 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1180,7 +1180,7 @@ public function fillJsonAttribute($key, $value) $value = $this->asJson($this->getArrayAttributeWithValue( $path, $key, $value - ), $this->hasCast($key, ['json:unicode'])); + ), $this->getJsonCastFlags($key)); $this->attributes[$key] = $this->isEncryptedCastable($key) ? $this->castAttributeAsEncryptedString($key, $value) From 5b661de8c92c7ddd163bd4f2b30c9fd4807ce1ca Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 14 Mar 2025 12:25:17 -0500 Subject: [PATCH 194/455] reapply Pint style changes (#55015) StyleCI reverted all the changes from the previous commit. --- src/Illuminate/Validation/InvokableValidationRule.php | 3 ++- tests/Bus/BusPendingBatchTest.php | 9 ++++++--- tests/Database/DatabaseAbstractSchemaGrammarTest.php | 6 ++++-- tests/Database/DatabaseEloquentInverseRelationTest.php | 3 ++- tests/Encryption/EncrypterTest.php | 6 ++++-- tests/Http/JsonResourceTest.php | 6 ++++-- tests/Pagination/CursorPaginatorLoadMorphCountTest.php | 3 ++- tests/Pagination/CursorPaginatorLoadMorphTest.php | 3 ++- tests/Pagination/PaginatorLoadMorphCountTest.php | 3 ++- tests/Pagination/PaginatorLoadMorphTest.php | 3 ++- tests/Support/SupportCollectionTest.php | 6 ++++-- tests/Validation/ValidationValidatorTest.php | 3 ++- tests/View/Blade/BladeComponentTagCompilerTest.php | 3 ++- 13 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index c9e43943ef59..e8aaf55af17b 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -69,7 +69,8 @@ protected function __construct(ValidationRule|InvokableRule $invokable) public static function make($invokable) { if ($invokable->implicit ?? false) { - return new class($invokable) extends InvokableValidationRule implements ImplicitRule { + return new class($invokable) extends InvokableValidationRule implements ImplicitRule + { }; } diff --git a/tests/Bus/BusPendingBatchTest.php b/tests/Bus/BusPendingBatchTest.php index baed6e2726b6..4133054577c7 100644 --- a/tests/Bus/BusPendingBatchTest.php +++ b/tests/Bus/BusPendingBatchTest.php @@ -71,7 +71,8 @@ public function test_batch_is_deleted_from_storage_if_exception_thrown_during_ba $container = new Container; - $job = new class { + $job = new class + { }; $pendingBatch = new PendingBatch($container, new Collection([$job])); @@ -226,7 +227,8 @@ public function test_batch_before_event_is_called() public function test_it_throws_exception_if_batched_job_is_not_batchable(): void { - $nonBatchableJob = new class { + $nonBatchableJob = new class + { }; $this->expectException(RuntimeException::class); @@ -242,7 +244,8 @@ public function test_it_throws_an_exception_if_batched_job_contains_batch_with_n new PendingBatch( $container, new Collection( - [new PendingBatch($container, new Collection([new BatchableJob, new class { + [new PendingBatch($container, new Collection([new BatchableJob, new class + { }]))] ) ); diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php index 87340615e399..47f89631865e 100755 --- a/tests/Database/DatabaseAbstractSchemaGrammarTest.php +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -17,7 +17,8 @@ protected function tearDown(): void public function testCreateDatabase() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar { + $grammar = new class($connection) extends Grammar + { }; $this->assertSame('create database "foo"', $grammar->compileCreateDatabase('foo')); @@ -26,7 +27,8 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar { + $grammar = new class($connection) extends Grammar + { }; $this->assertSame('drop database if exists "foo"', $grammar->compileDropDatabaseIfExists('foo')); diff --git a/tests/Database/DatabaseEloquentInverseRelationTest.php b/tests/Database/DatabaseEloquentInverseRelationTest.php index 7f6c9d1e9366..49cbfc4f304b 100755 --- a/tests/Database/DatabaseEloquentInverseRelationTest.php +++ b/tests/Database/DatabaseEloquentInverseRelationTest.php @@ -288,7 +288,8 @@ public function testOnlyHydratesInverseRelationOnModels() [], new HasInverseRelationRelatedStub(), 'foo', - new class() { + new class() + { }, new HasInverseRelationRelatedStub(), ]); diff --git a/tests/Encryption/EncrypterTest.php b/tests/Encryption/EncrypterTest.php index 78c45723105d..54d2e74530ff 100755 --- a/tests/Encryption/EncrypterTest.php +++ b/tests/Encryption/EncrypterTest.php @@ -248,10 +248,12 @@ public static function provideTamperedData() return [ [['iv' => ['value_in_array'], 'value' => '', 'mac' => '']], - [['iv' => new class() { + [['iv' => new class() + { }, 'value' => '', 'mac' => '']], [['iv' => $validIv, 'value' => ['value_in_array'], 'mac' => '']], - [['iv' => $validIv, 'value' => new class() { + [['iv' => $validIv, 'value' => new class() + { }, 'mac' => '']], [['iv' => $validIv, 'value' => '', 'mac' => ['value_in_array']]], [['iv' => $validIv, 'value' => '', 'mac' => null]], diff --git a/tests/Http/JsonResourceTest.php b/tests/Http/JsonResourceTest.php index 5e1e0d029ae7..f74a7303dbb8 100644 --- a/tests/Http/JsonResourceTest.php +++ b/tests/Http/JsonResourceTest.php @@ -12,7 +12,8 @@ class JsonResourceTest extends TestCase { public function testJsonResourceNullAttributes() { - $model = new class extends Model { + $model = new class extends Model + { }; $model->setAttribute('relation_sum_column', null); @@ -32,7 +33,8 @@ public function testJsonResourceNullAttributes() public function testJsonResourceToJsonSucceedsWithPriorErrors(): void { - $model = new class extends Model { + $model = new class extends Model + { }; $resource = m::mock(JsonResource::class, ['resource' => $model]) diff --git a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php index 71fbc565e444..d23682982dce 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php @@ -19,7 +19,8 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator { + $p = (new class extends AbstractCursorPaginator + { })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); diff --git a/tests/Pagination/CursorPaginatorLoadMorphTest.php b/tests/Pagination/CursorPaginatorLoadMorphTest.php index fe1aa8faa5f7..807c1b319a04 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphTest.php @@ -19,7 +19,8 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator { + $p = (new class extends AbstractCursorPaginator + { })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); diff --git a/tests/Pagination/PaginatorLoadMorphCountTest.php b/tests/Pagination/PaginatorLoadMorphCountTest.php index 8221c6da7dfb..7929ffabf56e 100644 --- a/tests/Pagination/PaginatorLoadMorphCountTest.php +++ b/tests/Pagination/PaginatorLoadMorphCountTest.php @@ -19,7 +19,8 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator { + $p = (new class extends AbstractPaginator + { })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); diff --git a/tests/Pagination/PaginatorLoadMorphTest.php b/tests/Pagination/PaginatorLoadMorphTest.php index c3ab5a5bf902..b4ed7b759558 100644 --- a/tests/Pagination/PaginatorLoadMorphTest.php +++ b/tests/Pagination/PaginatorLoadMorphTest.php @@ -19,7 +19,8 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator { + $p = (new class extends AbstractPaginator + { })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 0e246dc8f3d5..a0f411dc2bc2 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2371,10 +2371,12 @@ public function testImplode($collection) #[DataProvider('collectionClassProvider')] public function testImplodeModels($collection) { - $model = new class extends Model { + $model = new class extends Model + { }; $model->setAttribute('email', 'foo'); - $modelTwo = new class extends Model { + $modelTwo = new class extends Model + { }; $modelTwo->setAttribute('email', 'bar'); $data = new $collection([$model, $modelTwo]); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 167711851fab..1054c8694005 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -925,7 +925,8 @@ public function testCustomException() $v = new Validator($trans, ['name' => ''], ['name' => 'required']); - $exception = new class($v) extends ValidationException { + $exception = new class($v) extends ValidationException + { }; $v->setException($exception); diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index da1fffbd63c5..e28a168cda33 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -796,7 +796,8 @@ public function __toString() } }; - $model = new class extends Model { + $model = new class extends Model + { }; $this->assertEquals(e(''), BladeCompiler::sanitizeComponentAttribute('')); From 8f3f0fdaa5e20c40633d008cf61318ae4c13efc6 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 14 Mar 2025 17:25:55 +0000 Subject: [PATCH 195/455] Apply fixes from StyleCI --- src/Illuminate/Validation/InvokableValidationRule.php | 3 +-- tests/Bus/BusPendingBatchTest.php | 9 +++------ tests/Database/DatabaseAbstractSchemaGrammarTest.php | 6 ++---- tests/Database/DatabaseEloquentInverseRelationTest.php | 3 +-- tests/Encryption/EncrypterTest.php | 6 ++---- tests/Http/JsonResourceTest.php | 6 ++---- tests/Pagination/CursorPaginatorLoadMorphCountTest.php | 3 +-- tests/Pagination/CursorPaginatorLoadMorphTest.php | 3 +-- tests/Pagination/PaginatorLoadMorphCountTest.php | 3 +-- tests/Pagination/PaginatorLoadMorphTest.php | 3 +-- tests/Support/SupportCollectionTest.php | 6 ++---- tests/Validation/ValidationValidatorTest.php | 3 +-- tests/View/Blade/BladeComponentTagCompilerTest.php | 3 +-- 13 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index e8aaf55af17b..c9e43943ef59 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -69,8 +69,7 @@ protected function __construct(ValidationRule|InvokableRule $invokable) public static function make($invokable) { if ($invokable->implicit ?? false) { - return new class($invokable) extends InvokableValidationRule implements ImplicitRule - { + return new class($invokable) extends InvokableValidationRule implements ImplicitRule { }; } diff --git a/tests/Bus/BusPendingBatchTest.php b/tests/Bus/BusPendingBatchTest.php index 4133054577c7..baed6e2726b6 100644 --- a/tests/Bus/BusPendingBatchTest.php +++ b/tests/Bus/BusPendingBatchTest.php @@ -71,8 +71,7 @@ public function test_batch_is_deleted_from_storage_if_exception_thrown_during_ba $container = new Container; - $job = new class - { + $job = new class { }; $pendingBatch = new PendingBatch($container, new Collection([$job])); @@ -227,8 +226,7 @@ public function test_batch_before_event_is_called() public function test_it_throws_exception_if_batched_job_is_not_batchable(): void { - $nonBatchableJob = new class - { + $nonBatchableJob = new class { }; $this->expectException(RuntimeException::class); @@ -244,8 +242,7 @@ public function test_it_throws_an_exception_if_batched_job_contains_batch_with_n new PendingBatch( $container, new Collection( - [new PendingBatch($container, new Collection([new BatchableJob, new class - { + [new PendingBatch($container, new Collection([new BatchableJob, new class { }]))] ) ); diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php index 47f89631865e..87340615e399 100755 --- a/tests/Database/DatabaseAbstractSchemaGrammarTest.php +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -17,8 +17,7 @@ protected function tearDown(): void public function testCreateDatabase() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar - { + $grammar = new class($connection) extends Grammar { }; $this->assertSame('create database "foo"', $grammar->compileCreateDatabase('foo')); @@ -27,8 +26,7 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { $connection = m::mock(Connection::class); - $grammar = new class($connection) extends Grammar - { + $grammar = new class($connection) extends Grammar { }; $this->assertSame('drop database if exists "foo"', $grammar->compileDropDatabaseIfExists('foo')); diff --git a/tests/Database/DatabaseEloquentInverseRelationTest.php b/tests/Database/DatabaseEloquentInverseRelationTest.php index 49cbfc4f304b..7f6c9d1e9366 100755 --- a/tests/Database/DatabaseEloquentInverseRelationTest.php +++ b/tests/Database/DatabaseEloquentInverseRelationTest.php @@ -288,8 +288,7 @@ public function testOnlyHydratesInverseRelationOnModels() [], new HasInverseRelationRelatedStub(), 'foo', - new class() - { + new class() { }, new HasInverseRelationRelatedStub(), ]); diff --git a/tests/Encryption/EncrypterTest.php b/tests/Encryption/EncrypterTest.php index 54d2e74530ff..78c45723105d 100755 --- a/tests/Encryption/EncrypterTest.php +++ b/tests/Encryption/EncrypterTest.php @@ -248,12 +248,10 @@ public static function provideTamperedData() return [ [['iv' => ['value_in_array'], 'value' => '', 'mac' => '']], - [['iv' => new class() - { + [['iv' => new class() { }, 'value' => '', 'mac' => '']], [['iv' => $validIv, 'value' => ['value_in_array'], 'mac' => '']], - [['iv' => $validIv, 'value' => new class() - { + [['iv' => $validIv, 'value' => new class() { }, 'mac' => '']], [['iv' => $validIv, 'value' => '', 'mac' => ['value_in_array']]], [['iv' => $validIv, 'value' => '', 'mac' => null]], diff --git a/tests/Http/JsonResourceTest.php b/tests/Http/JsonResourceTest.php index f74a7303dbb8..5e1e0d029ae7 100644 --- a/tests/Http/JsonResourceTest.php +++ b/tests/Http/JsonResourceTest.php @@ -12,8 +12,7 @@ class JsonResourceTest extends TestCase { public function testJsonResourceNullAttributes() { - $model = new class extends Model - { + $model = new class extends Model { }; $model->setAttribute('relation_sum_column', null); @@ -33,8 +32,7 @@ public function testJsonResourceNullAttributes() public function testJsonResourceToJsonSucceedsWithPriorErrors(): void { - $model = new class extends Model - { + $model = new class extends Model { }; $resource = m::mock(JsonResource::class, ['resource' => $model]) diff --git a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php index d23682982dce..71fbc565e444 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphCountTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphCountTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator - { + $p = (new class extends AbstractCursorPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); diff --git a/tests/Pagination/CursorPaginatorLoadMorphTest.php b/tests/Pagination/CursorPaginatorLoadMorphTest.php index 807c1b319a04..fe1aa8faa5f7 100644 --- a/tests/Pagination/CursorPaginatorLoadMorphTest.php +++ b/tests/Pagination/CursorPaginatorLoadMorphTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractCursorPaginator - { + $p = (new class extends AbstractCursorPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); diff --git a/tests/Pagination/PaginatorLoadMorphCountTest.php b/tests/Pagination/PaginatorLoadMorphCountTest.php index 7929ffabf56e..8221c6da7dfb 100644 --- a/tests/Pagination/PaginatorLoadMorphCountTest.php +++ b/tests/Pagination/PaginatorLoadMorphCountTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCountCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorphCount')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator - { + $p = (new class extends AbstractPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorphCount('parentable', $relations)); diff --git a/tests/Pagination/PaginatorLoadMorphTest.php b/tests/Pagination/PaginatorLoadMorphTest.php index b4ed7b759558..c3ab5a5bf902 100644 --- a/tests/Pagination/PaginatorLoadMorphTest.php +++ b/tests/Pagination/PaginatorLoadMorphTest.php @@ -19,8 +19,7 @@ public function testCollectionLoadMorphCanChainOnThePaginator() $items = m::mock(Collection::class); $items->shouldReceive('loadMorph')->once()->with('parentable', $relations); - $p = (new class extends AbstractPaginator - { + $p = (new class extends AbstractPaginator { })->setCollection($items); $this->assertSame($p, $p->loadMorph('parentable', $relations)); diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index a0f411dc2bc2..0e246dc8f3d5 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2371,12 +2371,10 @@ public function testImplode($collection) #[DataProvider('collectionClassProvider')] public function testImplodeModels($collection) { - $model = new class extends Model - { + $model = new class extends Model { }; $model->setAttribute('email', 'foo'); - $modelTwo = new class extends Model - { + $modelTwo = new class extends Model { }; $modelTwo->setAttribute('email', 'bar'); $data = new $collection([$model, $modelTwo]); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 1054c8694005..167711851fab 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -925,8 +925,7 @@ public function testCustomException() $v = new Validator($trans, ['name' => ''], ['name' => 'required']); - $exception = new class($v) extends ValidationException - { + $exception = new class($v) extends ValidationException { }; $v->setException($exception); diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index e28a168cda33..da1fffbd63c5 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -796,8 +796,7 @@ public function __toString() } }; - $model = new class extends Model - { + $model = new class extends Model { }; $this->assertEquals(e(''), BladeCompiler::sanitizeComponentAttribute('')); From 84c60553fc4e575829a3f826a0bcce25d264eb8a Mon Sep 17 00:00:00 2001 From: Ali Khosravi Date: Mon, 17 Mar 2025 03:17:42 +0330 Subject: [PATCH 196/455] Add validation test for forEach with null and empty array values (#55047) --- tests/Validation/ValidationForEachTest.php | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Validation/ValidationForEachTest.php b/tests/Validation/ValidationForEachTest.php index b4b6bde450e5..1f68abe883f0 100644 --- a/tests/Validation/ValidationForEachTest.php +++ b/tests/Validation/ValidationForEachTest.php @@ -319,6 +319,37 @@ public function testConditionalRulesCanBeAddedToForEachWithObject() ], $v->getMessageBag()->toArray()); } + public function testForEachWithEmptyAndNullValues() + { + $data = [ + 'items' => [ + ['discounts' => null], + ['discounts' => []], + ['discounts' => [null]], + ], + ]; + + $rules = [ + 'items.*' => Rule::forEach(function () { + return [ + 'discounts' => 'required|array', + 'discounts.*' => 'required|array', + ]; + }), + ]; + + $v = new Validator($this->getIlluminateArrayTranslator(), $data, $rules); + $this->assertFalse($v->passes()); + $this->assertEquals( + [ + 'items.0.discounts' => ['validation.required'], + 'items.1.discounts' => ['validation.required'], + 'items.2.discounts.0' => ['validation.required'], + ], + $v->getMessageBag()->toArray() + ); + } + public function getIlluminateArrayTranslator() { return new Translator( From ae347cbc1e42a0632260f1b3c93319e2822a4eaf Mon Sep 17 00:00:00 2001 From: Liam Duckett Date: Sun, 16 Mar 2025 23:50:18 +0000 Subject: [PATCH 197/455] [12.x] Types: EnumeratesValues Sum (#55044) * add failing type test * add failing type test for lazy collection * add conditional return type * make tests more specific --- src/Illuminate/Collections/Traits/EnumeratesValues.php | 6 ++++-- types/Support/Collection.php | 4 ++-- types/Support/LazyCollection.php | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 9fa86d5bac05..aee186f0c209 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -535,8 +535,10 @@ public function percentage(callable $callback, int $precision = 2) /** * Get the sum of the given values. * - * @param (callable(TValue): mixed)|string|null $callback - * @return mixed + * @template TReturnType + * + * @param (callable(TValue): TReturnType)|string|null $callback + * @return ($callback is callable ? TReturnType : mixed) */ public function sum($callback = null) { diff --git a/types/Support/Collection.php b/types/Support/Collection.php index 05a5b79fcd46..c6733fa5d331 100644 --- a/types/Support/Collection.php +++ b/types/Support/Collection.php @@ -873,10 +873,10 @@ function ($collection, $count) { 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('int<1, 2>', $collection->make(['string'])->sum(function ($string) { assertType('string', $string); - return 1; + return rand(1, 2); })); assertType('Illuminate\Support\Collection', $collection->make([1])->take(1)); diff --git a/types/Support/LazyCollection.php b/types/Support/LazyCollection.php index 7c1359f58a40..4e96ba431f70 100644 --- a/types/Support/LazyCollection.php +++ b/types/Support/LazyCollection.php @@ -732,10 +732,10 @@ public function toArray(): array assertType('Illuminate\Support\LazyCollection', $collection->make(['string' => 'string'])->sortKeysDesc(1)); assertType('mixed', $collection->make([1])->sum('string')); -assertType('mixed', $collection->make(['string'])->sum(function ($string) { +assertType('int<1, 2>', $collection->make(['string'])->sum(function ($string) { assertType('string', $string); - return 1; + return rand(1, 2); })); assertType('Illuminate\Support\LazyCollection', $collection->make([1])->take(1)); From 171cb602e96c921c283d5452d97c567d85b3ec22 Mon Sep 17 00:00:00 2001 From: Ahmed Alaa <92916738+AhmedAlaa4611@users.noreply.github.com> Date: Mon, 17 Mar 2025 01:54:26 +0200 Subject: [PATCH 198/455] Ensure Consistent Formatting in Generated Invokable Classes (#55034) --- src/Illuminate/Foundation/Console/stubs/class.invokable.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/stubs/class.invokable.stub b/src/Illuminate/Foundation/Console/stubs/class.invokable.stub index c55610cfe4a6..b1e93cb728d7 100644 --- a/src/Illuminate/Foundation/Console/stubs/class.invokable.stub +++ b/src/Illuminate/Foundation/Console/stubs/class.invokable.stub @@ -17,6 +17,6 @@ class {{ class }} */ public function __invoke(): void { - + // } } From a4435a0f124823197249c0fe2caa38b107d6ea95 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Mon, 17 Mar 2025 00:56:53 +0100 Subject: [PATCH 199/455] Add elelemnt type to return array in Filesystem (#55031) --- src/Illuminate/Contracts/Filesystem/Filesystem.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Contracts/Filesystem/Filesystem.php b/src/Illuminate/Contracts/Filesystem/Filesystem.php index 43cdaf81cda5..00488a2c2367 100644 --- a/src/Illuminate/Contracts/Filesystem/Filesystem.php +++ b/src/Illuminate/Contracts/Filesystem/Filesystem.php @@ -173,7 +173,7 @@ public function lastModified($path); * * @param string|null $directory * @param bool $recursive - * @return array + * @return array */ public function files($directory = null, $recursive = false); @@ -181,7 +181,7 @@ public function files($directory = null, $recursive = false); * Get all of the files from the given directory (recursive). * * @param string|null $directory - * @return array + * @return array */ public function allFiles($directory = null); @@ -190,7 +190,7 @@ public function allFiles($directory = null); * * @param string|null $directory * @param bool $recursive - * @return array + * @return array */ public function directories($directory = null, $recursive = false); @@ -198,7 +198,7 @@ public function directories($directory = null, $recursive = false); * Get all (recursive) of the directories within a given directory. * * @param string|null $directory - * @return array + * @return array */ public function allDirectories($directory = null); From 2416981b24be8c9a99bd8d10e7d15725c65db7a8 Mon Sep 17 00:00:00 2001 From: Thierry Parent Date: Sun, 16 Mar 2025 19:58:57 -0400 Subject: [PATCH 200/455] Add support for PostgreSQL "unique nulls not distinct" (#55025) Co-authored-by: Thierry Parent --- .../Schema/Grammars/PostgresGrammar.php | 9 ++++++++- .../Database/Schema/IndexDefinition.php | 1 + .../DatabasePostgresSchemaGrammarTest.php | 20 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 1eae481a8df9..0d7a82dc2353 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -333,9 +333,16 @@ public function compilePrimary(Blueprint $blueprint, Fluent $command) */ public function compileUnique(Blueprint $blueprint, Fluent $command) { - $sql = sprintf('alter table %s add constraint %s unique (%s)', + $uniqueStatement = 'unique'; + + if (! is_null($command->nullsNotDistinct)) { + $uniqueStatement .= ' nulls '.($command->nullsNotDistinct ? 'not distinct' : 'distinct'); + } + + $sql = sprintf('alter table %s add constraint %s %s (%s)', $this->wrapTable($blueprint), $this->wrap($command->index), + $uniqueStatement, $this->columnize($command->columns) ); diff --git a/src/Illuminate/Database/Schema/IndexDefinition.php b/src/Illuminate/Database/Schema/IndexDefinition.php index fc5d78e5b92f..d11a3c8daeed 100644 --- a/src/Illuminate/Database/Schema/IndexDefinition.php +++ b/src/Illuminate/Database/Schema/IndexDefinition.php @@ -9,6 +9,7 @@ * @method $this language(string $language) Specify a language for the full text index (PostgreSQL) * @method $this deferrable(bool $value = true) Specify that the unique index is deferrable (PostgreSQL) * @method $this initiallyImmediate(bool $value = true) Specify the default time to check the unique index constraint (PostgreSQL) + * @method $this nullsNotDistinct(bool $value = true) Specify that the null values should not be treated as distinct (PostgreSQL) */ class IndexDefinition extends Fluent { diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 220cdf9c5fc9..0c31a6d2d06a 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -286,6 +286,26 @@ public function testAddingUniqueKey() $this->assertSame('alter table "users" add constraint "bar" unique ("foo")', $statements[0]); } + public function testAddingUniqueKeyWithNullsNotDistinct() + { + $blueprint = new Blueprint($this->getConnection(), 'users'); + $blueprint->unique('foo', 'bar')->nullsNotDistinct(); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add constraint "bar" unique nulls not distinct ("foo")', $statements[0]); + } + + public function testAddingUniqueKeyWithNullsDistinct() + { + $blueprint = new Blueprint($this->getConnection(), 'users'); + $blueprint->unique('foo', 'bar')->nullsNotDistinct(false); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('alter table "users" add constraint "bar" unique nulls distinct ("foo")', $statements[0]); + } + public function testAddingIndex() { $blueprint = new Blueprint($this->getConnection(), 'users'); From 472ea91efe70ce0298856617db709aae6a4e8511 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 17 Mar 2025 15:11:07 -0500 Subject: [PATCH 201/455] standardize multiline ternaries (#55056) if either the truthy or falsy expression is on a newline, make them both on a new line, and indent exactly once. I don't think we have to go so far as to say ALL ternaries need to be multi-line, but I would say if one expression is, they both should be. will make for easy readability and better diffs. unable to found an automation rule for this yet, but will keep looking. --- src/Illuminate/Broadcasting/BroadcastEvent.php | 3 ++- .../Database/Eloquent/Concerns/HasRelationships.php | 5 +++-- src/Illuminate/Database/Eloquent/Model.php | 3 ++- src/Illuminate/Database/Eloquent/Relations/MorphToMany.php | 5 +++-- src/Illuminate/Database/Query/Builder.php | 6 ++++-- src/Illuminate/Database/Schema/BlueprintState.php | 6 ++++-- src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php | 6 ++++-- src/Illuminate/Events/Dispatcher.php | 3 ++- src/Illuminate/Foundation/Testing/DatabaseTruncation.php | 3 ++- src/Illuminate/Routing/Route.php | 3 ++- src/Illuminate/Routing/RouteUrlGenerator.php | 3 ++- src/Illuminate/Routing/Router.php | 3 ++- src/Illuminate/Validation/Concerns/FormatsMessages.php | 3 ++- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 3 ++- 14 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Broadcasting/BroadcastEvent.php b/src/Illuminate/Broadcasting/BroadcastEvent.php index 3eb1c856db96..a13b7ff42128 100644 --- a/src/Illuminate/Broadcasting/BroadcastEvent.php +++ b/src/Illuminate/Broadcasting/BroadcastEvent.php @@ -75,7 +75,8 @@ public function __construct($event) public function handle(BroadcastingFactory $manager) { $name = method_exists($this->event, 'broadcastAs') - ? $this->event->broadcastAs() : get_class($this->event); + ? $this->event->broadcastAs() + : get_class($this->event); $channels = Arr::wrap($this->event->broadcastOn()); diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index a9a307db549c..eff6d46f2cee 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -821,8 +821,9 @@ public function joiningTable($related, $instance = null) // sorted alphabetically and concatenated with an underscore, so we can // just sort the models and join them together to get the table name. $segments = [ - $instance ? $instance->joiningTableSegment() - : Str::snake(class_basename($related)), + $instance + ? $instance->joiningTableSegment() + : Str::snake(class_basename($related)), $this->joiningTableSegment(), ]; diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 44878f7bf880..2994e8f256e9 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1095,7 +1095,8 @@ public function push() // us to recurse into all of these nested relations for the model instance. foreach ($this->relations as $models) { $models = $models instanceof Collection - ? $models->all() : [$models]; + ? $models->all() + : [$models]; foreach (array_filter($models) as $model) { if (! $model->push()) { diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 66f3f8e4792d..25d6fcd8e6b3 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -157,8 +157,9 @@ public function newPivot(array $attributes = [], $exists = false) $attributes = array_merge([$this->morphType => $this->morphClass], $attributes); - $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) - : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); + $pivot = $using + ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) + : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) ->setRelatedModel($this->related) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 03e78cd3bd61..f824f1c90b13 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3306,7 +3306,8 @@ protected function withoutSelectAliases(array $columns) { return array_map(function ($column) { return is_string($column) && ($aliasPosition = stripos($column, ' as ')) !== false - ? substr($column, 0, $aliasPosition) : $column; + ? substr($column, 0, $aliasPosition) + : $column; }, $columns); } @@ -3634,7 +3635,8 @@ public function numericAggregate($function, $columns = ['*']) // cast it to one. When it does we will cast it to a float since it needs to be // cast to the expected data type for the developers out of pure convenience. return ! str_contains((string) $result, '.') - ? (int) $result : (float) $result; + ? (int) $result + : (float) $result; } /** diff --git a/src/Illuminate/Database/Schema/BlueprintState.php b/src/Illuminate/Database/Schema/BlueprintState.php index c804e778fd81..a43ad20b241f 100644 --- a/src/Illuminate/Database/Schema/BlueprintState.php +++ b/src/Illuminate/Database/Schema/BlueprintState.php @@ -77,9 +77,11 @@ public function __construct(Blueprint $blueprint, Connection $connection) 'collation' => $column['collation'], 'comment' => $column['comment'], 'virtualAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'virtual' - ? $column['generation']['expression'] : null, + ? $column['generation']['expression'] + : null, 'storedAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'stored' - ? $column['generation']['expression'] : null, + ? $column['generation']['expression'] + : null, ]))->all(); [$primary, $indexes] = (new Collection($schema->getIndexes($table)))->map(fn ($index) => new IndexDefinition([ diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 693fc78a3659..56ff7583c07a 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -381,9 +381,11 @@ protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $comma 'collation' => $column['collation'], 'comment' => $column['comment'], 'virtualAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'virtual' - ? $column['generation']['expression'] : null, + ? $column['generation']['expression'] + : null, 'storedAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'stored' - ? $column['generation']['expression'] : null, + ? $column['generation']['expression'] + : null, ])); return sprintf('alter table %s change %s %s %s', diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 181ed211b461..a039965b08e9 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -344,7 +344,8 @@ protected function shouldBroadcast(array $payload) protected function broadcastWhen($event) { return method_exists($event, 'broadcastWhen') - ? $event->broadcastWhen() : true; + ? $event->broadcastWhen() + : true; } /** diff --git a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php index b679466f4eba..9ed063241a8f 100644 --- a/src/Illuminate/Foundation/Testing/DatabaseTruncation.php +++ b/src/Illuminate/Foundation/Testing/DatabaseTruncation.php @@ -141,7 +141,8 @@ protected function tableExistsIn(array $table, array $tables): bool protected function connectionsToTruncate(): array { return property_exists($this, 'connectionsToTruncate') - ? $this->connectionsToTruncate : [null]; + ? $this->connectionsToTruncate + : [null]; } /** diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 2542cb2859cb..d877268d1ffb 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -792,7 +792,8 @@ public function domain($domain = null) public function getDomain() { return isset($this->action['domain']) - ? str_replace(['http://', 'https://'], '', $this->action['domain']) : null; + ? str_replace(['http://', 'https://'], '', $this->action['domain']) + : null; } /** diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index 4cb4b4599aac..5f38c13e4cee 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -164,7 +164,8 @@ protected function addPortToDomain($domain) $port = (int) $this->request->getPort(); return ($secure && $port === 443) || (! $secure && $port === 80) - ? $domain : $domain.':'.$port; + ? $domain + : $domain.':'.$port; } /** diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 4b69dae224e4..d29050277ca5 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -630,7 +630,8 @@ protected function prependGroupNamespace($class) $group = end($this->groupStack); return isset($group['namespace']) && ! str_starts_with($class, '\\') && ! str_starts_with($class, $group['namespace']) - ? $group['namespace'].'\\'.$class : $class; + ? $group['namespace'].'\\'.$class + : $class; } /** diff --git a/src/Illuminate/Validation/Concerns/FormatsMessages.php b/src/Illuminate/Validation/Concerns/FormatsMessages.php index d4e83ea105a4..5e36ad881920 100644 --- a/src/Illuminate/Validation/Concerns/FormatsMessages.php +++ b/src/Illuminate/Validation/Concerns/FormatsMessages.php @@ -267,7 +267,8 @@ public function getDisplayableAttribute($attribute) $primaryAttribute = $this->getPrimaryAttribute($attribute); $expectedAttributes = $attribute != $primaryAttribute - ? [$attribute, $primaryAttribute] : [$attribute]; + ? [$attribute, $primaryAttribute] + : [$attribute]; foreach ($expectedAttributes as $name) { // The developer may dynamically specify the array of custom attributes on this diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 5e6cd45c9f31..21577ce4eb87 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1119,7 +1119,8 @@ public function parseTable($table) public function getQueryColumn($parameters, $attribute) { return isset($parameters[1]) && $parameters[1] !== 'NULL' - ? $parameters[1] : $this->guessColumnForQuery($attribute); + ? $parameters[1] + : $this->guessColumnForQuery($attribute); } /** From c86bb43aac9fb4bc93c605835e46bcac4c1bfe4f Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 17 Mar 2025 15:11:23 -0500 Subject: [PATCH 202/455] improved readability for `aliasedPivotColumns` (#55055) - use a new line for all chained Collection methods. easier to grok and much better diffs - use short closure for simple `map` call - utilize array unpacking to instantiate the Collection and avoid temporary variables --- .../Database/Eloquent/Relations/BelongsToMany.php | 13 ++++++++----- .../Database/Eloquent/Relations/MorphToMany.php | 14 +++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 4ff65b02a9d0..47d010ba49b6 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -924,11 +924,14 @@ protected function shouldSelect(array $columns = ['*']) */ protected function aliasedPivotColumns() { - $defaults = [$this->foreignPivotKey, $this->relatedPivotKey]; - - return (new BaseCollection(array_merge($defaults, $this->pivotColumns)))->map(function ($column) { - return $this->qualifyPivotColumn($column).' as pivot_'.$column; - })->unique()->all(); + return (new BaseCollection([ + $this->foreignPivotKey, + $this->relatedPivotKey, + ...$this->pivotColumns, + ])) + ->map(fn ($column) => $this->qualifyPivotColumn($column).' as pivot_'.$column) + ->unique() + ->all(); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 25d6fcd8e6b3..7659a3b9bc3c 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -178,11 +178,15 @@ public function newPivot(array $attributes = [], $exists = false) */ protected function aliasedPivotColumns() { - $defaults = [$this->foreignPivotKey, $this->relatedPivotKey, $this->morphType]; - - return (new Collection(array_merge($defaults, $this->pivotColumns)))->map(function ($column) { - return $this->qualifyPivotColumn($column).' as pivot_'.$column; - })->unique()->all(); + return (new Collection([ + $this->foreignPivotKey, + $this->relatedPivotKey, + $this->morphType, + ...$this->pivotColumns, + ])) + ->map(fn ($column) => $this->qualifyPivotColumn($column).' as pivot_'.$column) + ->unique() + ->all(); } /** From 3503a48a70f4f084a2708b309f142efb1a12ac11 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 17 Mar 2025 15:11:39 -0500 Subject: [PATCH 203/455] [12.x] remove progress bar from PHPStan output (#55054) * remove progress bar from PHPStan output the progress bar is unnecessary when running in a pipeline and just clutters things up. the same as we do for composer installs and updates * oops --- .github/workflows/static-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 49d197648f40..da698e647f91 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -40,4 +40,4 @@ jobs: command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress - name: Execute type checking - run: vendor/bin/phpstan --configuration="phpstan.${{ matrix.directory }}.neon.dist" + run: vendor/bin/phpstan --configuration="phpstan.${{ matrix.directory }}.neon.dist" --no-progress From 726434c6d8b3a34a66a73c7fe2322f6f632a2339 Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Mon, 17 Mar 2025 15:32:44 -0500 Subject: [PATCH 204/455] [12.x] Fixes how the fluent Date rule builder handles `date_format` (#55052) * Fixed adding a format to the fluent date rule builder * Conformed to StyleCI * Take initial rules from previous PR * Added tests for specific dates with custom date format * Update Date.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Validation/Rules/Date.php | 18 ++++++++++++---- tests/Validation/ValidationDateRuleTest.php | 21 ++++++++++++++++--- tests/Validation/ValidationRuleParserTest.php | 4 ++-- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Validation/Rules/Date.php b/src/Illuminate/Validation/Rules/Date.php index 6b6140fbd8f8..cec8894f630c 100644 --- a/src/Illuminate/Validation/Rules/Date.php +++ b/src/Illuminate/Validation/Rules/Date.php @@ -12,17 +12,24 @@ class Date implements Stringable { use Conditionable, Macroable; + /** + * The format of the date. + */ + protected ?string $format = null; + /** * The constraints for the date rule. */ - protected array $constraints = ['date']; + protected array $constraints = []; /** * Ensure the date has the given format. */ public function format(string $format): static { - return $this->addRule('date_format:'.$format); + $this->format = $format; + + return $this; } /** @@ -121,7 +128,7 @@ protected function addRule(array|string $rules): static protected function formatDate(DateTimeInterface|string $date): string { return $date instanceof DateTimeInterface - ? $date->format('Y-m-d') + ? $date->format($this->format ?? 'Y-m-d') : $date; } @@ -130,6 +137,9 @@ protected function formatDate(DateTimeInterface|string $date): string */ public function __toString(): string { - return implode('|', $this->constraints); + return implode('|', [ + $this->format === null ? 'date' : 'date_format:'.$this->format, + ...$this->constraints, + ]); } } diff --git a/tests/Validation/ValidationDateRuleTest.php b/tests/Validation/ValidationDateRuleTest.php index 1db535b0da5d..04f99784839c 100644 --- a/tests/Validation/ValidationDateRuleTest.php +++ b/tests/Validation/ValidationDateRuleTest.php @@ -24,7 +24,7 @@ public function testDefaultDateRule() public function testDateFormatRule() { $rule = Rule::date()->format('d/m/Y'); - $this->assertEquals('date|date_format:d/m/Y', (string) $rule); + $this->assertEquals('date_format:d/m/Y', (string) $rule); } public function testAfterTodayRule() @@ -49,30 +49,45 @@ public function testAfterSpecificDateRule() { $rule = Rule::date()->after(Carbon::parse('2024-01-01')); $this->assertEquals('date|after:2024-01-01', (string) $rule); + + $rule = Rule::date()->format('d/m/Y')->after(Carbon::parse('2024-01-01')); + $this->assertEquals('date_format:d/m/Y|after:01/01/2024', (string) $rule); } public function testBeforeSpecificDateRule() { $rule = Rule::date()->before(Carbon::parse('2024-01-01')); $this->assertEquals('date|before:2024-01-01', (string) $rule); + + $rule = Rule::date()->format('d/m/Y')->before(Carbon::parse('2024-01-01')); + $this->assertEquals('date_format:d/m/Y|before:01/01/2024', (string) $rule); } public function testAfterOrEqualSpecificDateRule() { $rule = Rule::date()->afterOrEqual(Carbon::parse('2024-01-01')); $this->assertEquals('date|after_or_equal:2024-01-01', (string) $rule); + + $rule = Rule::date()->format('d/m/Y')->afterOrEqual(Carbon::parse('2024-01-01')); + $this->assertEquals('date_format:d/m/Y|after_or_equal:01/01/2024', (string) $rule); } public function testBeforeOrEqualSpecificDateRule() { $rule = Rule::date()->beforeOrEqual(Carbon::parse('2024-01-01')); $this->assertEquals('date|before_or_equal:2024-01-01', (string) $rule); + + $rule = Rule::date()->format('d/m/Y')->beforeOrEqual(Carbon::parse('2024-01-01')); + $this->assertEquals('date_format:d/m/Y|before_or_equal:01/01/2024', (string) $rule); } public function testBetweenDatesRule() { $rule = Rule::date()->between(Carbon::parse('2024-01-01'), Carbon::parse('2024-02-01')); $this->assertEquals('date|after:2024-01-01|before:2024-02-01', (string) $rule); + + $rule = Rule::date()->format('d/m/Y')->between(Carbon::parse('2024-01-01'), Carbon::parse('2024-02-01')); + $this->assertEquals('date_format:d/m/Y|after:01/01/2024|before:01/02/2024', (string) $rule); } public function testBetweenOrEqualDatesRule() @@ -87,7 +102,7 @@ public function testChainedRules() ->format('Y-m-d') ->after('2024-01-01 00:00:00') ->before('2025-01-01 00:00:00'); - $this->assertEquals('date|date_format:Y-m-d|after:2024-01-01 00:00:00|before:2025-01-01 00:00:00', (string) $rule); + $this->assertEquals('date_format:Y-m-d|after:2024-01-01 00:00:00|before:2025-01-01 00:00:00', (string) $rule); $rule = Rule::date() ->format('Y-m-d') @@ -97,7 +112,7 @@ public function testChainedRules() ->unless(true, function ($rule) { $rule->before('2025-01-01'); }); - $this->assertSame('date|date_format:Y-m-d|after:2024-01-01', (string) $rule); + $this->assertSame('date_format:Y-m-d|after:2024-01-01', (string) $rule); } public function testDateValidation() diff --git a/tests/Validation/ValidationRuleParserTest.php b/tests/Validation/ValidationRuleParserTest.php index 8fbb48ef86ed..8da3e84afdd3 100644 --- a/tests/Validation/ValidationRuleParserTest.php +++ b/tests/Validation/ValidationRuleParserTest.php @@ -398,7 +398,7 @@ public function testExplodeHandlesDateRuleWithAdditionalRules() ])); $rules = [ - 'date' => Rule::date()->format('Y-m-d'), + 'date' => Rule::date()->after('today'), ]; $results = $parser->explode($rules); @@ -406,7 +406,7 @@ public function testExplodeHandlesDateRuleWithAdditionalRules() $this->assertEquals([ 'date' => [ 'date', - 'date_format:Y-m-d', + 'after:today', ], ], $results->rules); } From b44eeb9fd10b82cd961e26d28584ef5ae6d10d4f Mon Sep 17 00:00:00 2001 From: "Md. Imrul Kayes" <48817876+mdiktushar@users.noreply.github.com> Date: Tue, 18 Mar 2025 02:43:53 +0600 Subject: [PATCH 205/455] Adding SSL encryption and support for MySQL connection (#55048) Added `MYSQL_ATTR_SSL_CERT`, `MYSQL_ATTR_SSL_KEY`, and `MYSQL_ATTR_SSL_VERIFY_SERVER_CERT --- config/database.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/database.php b/config/database.php index 3e827c359b04..fcb85bf4387b 100644 --- a/config/database.php +++ b/config/database.php @@ -60,6 +60,9 @@ 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + PDO::MYSQL_ATTR_SSL_CERT => env('MYSQL_ATTR_SSL_CERT'), + PDO::MYSQL_ATTR_SSL_KEY => env('MYSQL_ATTR_SSL_KEY'), + PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => env('MYSQL_ATTR_SSL_VERIFY_SERVER_CERT', false), ]) : [], ], From e1af08a033c38395223f2e85fa6cfbe3cfae0e1b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 17 Mar 2025 15:49:27 -0500 Subject: [PATCH 206/455] Revert "Adding SSL encryption and support for MySQL connection (#55048)" (#55057) This reverts commit b44eeb9fd10b82cd961e26d28584ef5ae6d10d4f. --- config/database.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/database.php b/config/database.php index fcb85bf4387b..3e827c359b04 100644 --- a/config/database.php +++ b/config/database.php @@ -60,9 +60,6 @@ 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), - PDO::MYSQL_ATTR_SSL_CERT => env('MYSQL_ATTR_SSL_CERT'), - PDO::MYSQL_ATTR_SSL_KEY => env('MYSQL_ATTR_SSL_KEY'), - PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => env('MYSQL_ATTR_SSL_VERIFY_SERVER_CERT', false), ]) : [], ], From 65dfe282ec4d3f1eb988e80561f98ecdc9f94599 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Tue, 18 Mar 2025 09:20:35 +1100 Subject: [PATCH 207/455] Ensure queue property is nullable (#55058) --- src/Illuminate/Queue/Events/JobQueued.php | 2 +- src/Illuminate/Queue/Events/JobQueueing.php | 2 +- .../Integration/Queue/JobDispatchingTest.php | 35 +++++++++++++++++++ types/Queue/Events/JobQueued.php | 19 ++++++++++ types/Queue/Events/JobQueueing.php | 18 ++++++++++ 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 types/Queue/Events/JobQueued.php create mode 100644 types/Queue/Events/JobQueueing.php diff --git a/src/Illuminate/Queue/Events/JobQueued.php b/src/Illuminate/Queue/Events/JobQueued.php index 68667876bfe3..599b9da7a18e 100644 --- a/src/Illuminate/Queue/Events/JobQueued.php +++ b/src/Illuminate/Queue/Events/JobQueued.php @@ -8,7 +8,7 @@ class JobQueued * Create a new event instance. * * @param string $connectionName The connection name. - * @param string $queue The queue name. + * @param string|null $queue The queue name. * @param string|int|null $id The job ID. * @param \Closure|string|object $job The job instance. * @param string $payload The job payload. diff --git a/src/Illuminate/Queue/Events/JobQueueing.php b/src/Illuminate/Queue/Events/JobQueueing.php index ef97e1e71395..ed6815a34d30 100644 --- a/src/Illuminate/Queue/Events/JobQueueing.php +++ b/src/Illuminate/Queue/Events/JobQueueing.php @@ -8,7 +8,7 @@ class JobQueueing * Create a new event instance. * * @param string $connectionName The connection name. - * @param string $queue The queue name. + * @param string|null $queue The queue name. * @param \Closure|string|object $job The job instance. * @param string $payload The job payload. * @param int|null $delay The number of seconds the job was delayed. diff --git a/tests/Integration/Queue/JobDispatchingTest.php b/tests/Integration/Queue/JobDispatchingTest.php index 6b5f4928538f..ebef0f344318 100644 --- a/tests/Integration/Queue/JobDispatchingTest.php +++ b/tests/Integration/Queue/JobDispatchingTest.php @@ -7,7 +7,10 @@ use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\Events\JobQueued; +use Illuminate\Queue\Events\JobQueueing; use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Support\Facades\Config; use Orchestra\Testbench\Attributes\WithMigration; #[WithMigration] @@ -135,6 +138,33 @@ public function testUniqueJobLockIsReleasedForJobDispatchedAfterResponse() $this->assertFalse(UniqueJob::$ran); } + public function testQueueMayBeNullForJobQueueingAndJobQueuedEvent() + { + Config::set('queue.default', 'database'); + $events = []; + $this->app['events']->listen(function (JobQueueing $e) use (&$events) { + $events[] = $e; + }); + $this->app['events']->listen(function (JobQueued $e) use (&$events) { + $events[] = $e; + }); + + MyTestDispatchableJob::dispatch(); + dispatch(function () { + // + }); + + $this->assertCount(4, $events); + $this->assertInstanceOf(JobQueueing::class, $events[0]); + $this->assertNull($events[0]->queue); + $this->assertInstanceOf(JobQueued::class, $events[1]); + $this->assertNull($events[1]->queue); + $this->assertInstanceOf(JobQueueing::class, $events[2]); + $this->assertNull($events[2]->queue); + $this->assertInstanceOf(JobQueued::class, $events[3]); + $this->assertNull($events[3]->queue); + } + /** * Helpers. */ @@ -178,3 +208,8 @@ public function uniqueId() return self::$value; } } + +class MyTestDispatchableJob implements ShouldQueue +{ + use Dispatchable; +} diff --git a/types/Queue/Events/JobQueued.php b/types/Queue/Events/JobQueued.php new file mode 100644 index 000000000000..5733c57bf078 --- /dev/null +++ b/types/Queue/Events/JobQueued.php @@ -0,0 +1,19 @@ + null, + payload: '{}', + delay: null, +); + +/** + * @see testQueueMayBeNullForJobQueueingAndJobQueuedEvent + */ +assertType('string|null', $instance->queue); diff --git a/types/Queue/Events/JobQueueing.php b/types/Queue/Events/JobQueueing.php new file mode 100644 index 000000000000..989cb8432b9f --- /dev/null +++ b/types/Queue/Events/JobQueueing.php @@ -0,0 +1,18 @@ + null, + payload: '{}', + delay: null, +); + +/** + * @see testQueueMayBeNullForJobQueueingAndJobQueuedEvent + */ +assertType('string|null', $instance->queue); From e67365854b00c8c5054283d8ecc2fc39e5a84a29 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 17 Mar 2025 20:08:40 -0500 Subject: [PATCH 208/455] return `$this` for chaining (#55060) looks like a small oversight from #54678 of which part of it was caught in #54941 --- src/Illuminate/Testing/TestResponse.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index b23e3525f20b..ea4d3793148d 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -994,6 +994,8 @@ public function assertOnlyJsonValidationErrors($errors, $responseKey = 'errors') $unexpectedErrorKeys = Arr::except($jsonErrors, $expectedErrorKeys); PHPUnit::withResponse($this)->assertTrue(count($unexpectedErrorKeys) === 0, 'Response has unexpected validation errors: '.collect($unexpectedErrorKeys)->keys()->map(fn ($key) => "'{$key}'")->join(', ')); + + return $this; } /** From eac931d0a5f0d3b4832ae487d8a6af5f2aed8154 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 17 Mar 2025 20:09:32 -0500 Subject: [PATCH 209/455] prefer `new Collection` over `collect()` (#55059) this is a continuation of #53563 Co-authored-by: Taylor Otwell --- .../Foundation/Console/AboutCommand.php | 2 +- src/Illuminate/Http/Request.php | 2 +- src/Illuminate/Testing/TestResponse.php | 16 +++++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Foundation/Console/AboutCommand.php b/src/Illuminate/Foundation/Console/AboutCommand.php index 26fa04446df9..77de686f958f 100644 --- a/src/Illuminate/Foundation/Console/AboutCommand.php +++ b/src/Illuminate/Foundation/Console/AboutCommand.php @@ -230,7 +230,7 @@ protected function gatherApplicationInformation() */ protected function determineStoragePathLinkStatus(callable $formatStorageLinkedStatus): array { - return collect(config('filesystems.links', [])) + return (new Collection(config('filesystems.links', []))) ->mapWithKeys(function ($target, $link) use ($formatStorageLinkedStatus) { $path = Str::replace(public_path(), '', $link); diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 8695535899e8..995ed0865741 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -363,7 +363,7 @@ public function merge(array $input) { return tap($this, function (Request $request) use ($input) { $request->getInputSource() - ->replace(collect($input)->reduce( + ->replace((new Collection($input))->reduce( fn ($requestInput, $value, $key) => data_set($requestInput, $key, $value), $this->getInputSource()->all() )); diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index ea4d3793148d..9ad041a160db 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -989,11 +989,16 @@ public function assertOnlyJsonValidationErrors($errors, $responseKey = 'errors') $jsonErrors = Arr::get($this->json(), $responseKey) ?? []; - $expectedErrorKeys = collect($errors)->map(fn ($value, $key) => is_int($key) ? $value : $key)->all(); + $expectedErrorKeys = (new Collection($errors)) + ->map(fn ($value, $key) => is_int($key) ? $value : $key) + ->all(); $unexpectedErrorKeys = Arr::except($jsonErrors, $expectedErrorKeys); - PHPUnit::withResponse($this)->assertTrue(count($unexpectedErrorKeys) === 0, 'Response has unexpected validation errors: '.collect($unexpectedErrorKeys)->keys()->map(fn ($key) => "'{$key}'")->join(', ')); + PHPUnit::withResponse($this)->assertTrue( + count($unexpectedErrorKeys) === 0, + 'Response has unexpected validation errors: '.(new Collection($unexpectedErrorKeys))->keys()->map(fn ($key) => "'{$key}'")->join(', ') + ); return $this; } @@ -1398,14 +1403,15 @@ public function assertOnlyInvalid($errors = null, $errorBag = 'default', $respon ->getBag($errorBag) ->getMessages(); - $expectedErrorKeys = collect($errors) - ->map(fn ($value, $key) => is_int($key) ? $value : $key)->all(); + $expectedErrorKeys = (new Collection($errors)) + ->map(fn ($value, $key) => is_int($key) ? $value : $key) + ->all(); $unexpectedErrorKeys = Arr::except($sessionErrors, $expectedErrorKeys); PHPUnit::withResponse($this)->assertTrue( count($unexpectedErrorKeys) === 0, - 'Response has unexpected validation errors: '.collect($unexpectedErrorKeys)->keys()->map(fn ($key) => "'{$key}'")->join(', ') + 'Response has unexpected validation errors: '.(new Collection($unexpectedErrorKeys))->keys()->map(fn ($key) => "'{$key}'")->join(', ') ); return $this; From 86f8574410521b1833f0169cf77f0c5c41edc8b6 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 17 Mar 2025 20:10:15 -0500 Subject: [PATCH 210/455] [12.x] use "class-string" type for `using` pivot model (#55053) * use "class-string" type for `using` pivot model the `using` property of the `BelongsToMany` class is not just a string, but specifically a class string, so we'll document it as such. helps in places where [static methods are being called on the string](https://github.com/laravel/framework/blob/12.x/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php#L160) * Update src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php apparently can't use Traits as types Co-authored-by: Jeffrey Angenent <1571879+devfrey@users.noreply.github.com> * fixed docblocks for generic to pass type test --------- Co-authored-by: Jeffrey Angenent <1571879+devfrey@users.noreply.github.com> Co-authored-by: Andrew Mast --- .../Database/Eloquent/Concerns/HasRelationships.php | 4 ++-- .../Database/Eloquent/Relations/BelongsToMany.php | 7 ++++--- src/Illuminate/Database/Eloquent/Relations/MorphToMany.php | 2 +- types/Database/Eloquent/Relations.php | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index eff6d46f2cee..df89155e9382 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -564,7 +564,7 @@ protected function newMorphMany(Builder $query, Model $parent, $type, $id, $loca * @param string|null $parentKey * @param string|null $relatedKey * @param string|null $relation - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function belongsToMany( $related, @@ -624,7 +624,7 @@ public function belongsToMany( * @param string $parentKey * @param string $relatedKey * @param string|null $relationName - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ protected function newBelongsToMany( Builder $query, diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 47d010ba49b6..2e5a071faa2e 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -20,6 +20,7 @@ /** * @template TRelatedModel of \Illuminate\Database\Eloquent\Model * @template TDeclaringModel of \Illuminate\Database\Eloquent\Model + * @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot * * @extends \Illuminate\Database\Eloquent\Relations\Relation> */ @@ -128,7 +129,7 @@ class BelongsToMany extends Relation /** * The class name of the custom pivot model to use for the relationship. * - * @var string + * @var class-string */ protected $using; @@ -316,7 +317,7 @@ protected function buildDictionary(EloquentCollection $results) /** * Get the class being used for pivot models. * - * @return string + * @return class-string */ public function getPivotClass() { @@ -326,7 +327,7 @@ public function getPivotClass() /** * Specify the custom pivot model to use for the relationship. * - * @param string $class + * @param class-string $class * @return $this */ public function using($class) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 7659a3b9bc3c..dd5deb2fc0de 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -11,7 +11,7 @@ * @template TRelatedModel of \Illuminate\Database\Eloquent\Model * @template TDeclaringModel of \Illuminate\Database\Eloquent\Model * - * @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany */ class MorphToMany extends BelongsToMany { diff --git a/types/Database/Eloquent/Relations.php b/types/Database/Eloquent/Relations.php index 123b22d5b359..416c64adbc53 100644 --- a/types/Database/Eloquent/Relations.php +++ b/types/Database/Eloquent/Relations.php @@ -41,7 +41,7 @@ function test(User $user, Post $post, Comment $comment, ChildUser $child): void assertType('Illuminate\Types\Relations\Post|false', $user->posts()->save(new Post())); assertType('Illuminate\Types\Relations\Post|false', $user->posts()->saveQuietly(new Post())); - assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $user->roles()); + assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $user->roles()); assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->getResults()); assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->find([1])); assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findMany([1, 2, 3])); @@ -157,11 +157,11 @@ public function latestPost(): HasOne return $post; } - /** @return BelongsToMany */ + /** @return BelongsToMany */ public function roles(): BelongsToMany { $belongsToMany = $this->belongsToMany(Role::class); - assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $belongsToMany); + assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $belongsToMany); return $belongsToMany; } From d16c1a164d2cade9d016bd4ed03c44accabc72ed Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 18 Mar 2025 08:45:47 -0500 Subject: [PATCH 211/455] [12.x] multiline chaining on Collections (#55061) * multiline chaining on Collections when chaining methods or properties on a `Collection`, place them on a newline for easier readability and clearer diffs. also use short closures for simple bodies. this is a continuation of some of my previous formatting commits. * minor formatting --- .../Broadcasting/Broadcasters/Broadcaster.php | 10 +++---- src/Illuminate/Cache/Repository.php | 8 +++-- .../Database/Console/PruneCommand.php | 14 ++++----- src/Illuminate/Database/Query/Builder.php | 8 ++--- .../Foundation/Console/RouteListCommand.php | 13 ++++---- .../Foundation/Exceptions/Handler.php | 8 +++-- src/Illuminate/Foundation/PackageManifest.php | 7 +++-- src/Illuminate/Http/Client/PendingRequest.php | 14 +++++---- .../Notifications/Channels/MailChannel.php | 12 ++++---- .../Notifications/Messages/MailMessage.php | 7 +++-- .../Process/FakeProcessDescription.php | 14 +++++---- src/Illuminate/Process/Pool.php | 3 +- .../Queue/Failed/FileFailedJobProvider.php | 8 +++-- src/Illuminate/Routing/Route.php | 25 ++++++++++------ src/Illuminate/Routing/Router.php | 10 +++++-- src/Illuminate/Support/Str.php | 6 ++-- .../Support/Testing/Fakes/QueueFake.php | 7 +++-- .../Support/Traits/InteractsWithData.php | 7 +++-- .../Support/Traits/ReflectsClosures.php | 30 +++++++++++-------- src/Illuminate/Validation/Validator.php | 16 ++++++---- 20 files changed, 132 insertions(+), 95 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 6ebde3b7e3af..7340f55181df 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -141,11 +141,11 @@ protected function extractAuthParameters($pattern, $channel, $callback) { $callbackParameters = $this->extractParameters($callback); - return (new Collection($this->extractChannelKeys($pattern, $channel)))->reject(function ($value, $key) { - return is_numeric($key); - })->map(function ($value, $key) use ($callbackParameters) { - return $this->resolveBinding($key, $value, $callbackParameters); - })->values()->all(); + return (new Collection($this->extractChannelKeys($pattern, $channel))) + ->reject(fn ($value, $key) => is_numeric($key)) + ->map(fn ($value, $key) => $this->resolveBinding($key, $value, $callbackParameters)) + ->values() + ->all(); } /** diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index a5f1df9db137..978e2ffbadaf 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -142,9 +142,11 @@ public function many(array $keys) { $this->event(new RetrievingManyKeys($this->getName(), $keys)); - $values = $this->store->many((new Collection($keys))->map(function ($value, $key) { - return is_string($key) ? $key : $value; - })->values()->all()); + $values = $this->store->many((new Collection($keys)) + ->map(fn ($value, $key) => is_string($key) ? $key : $value) + ->values() + ->all() + ); return (new Collection($values)) ->map(fn ($value, $key) => $this->handleManyResult($keys, $key, $value)) diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index db8dead36342..a7b58e560189 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -138,15 +138,11 @@ protected function models() ['\\', ''], Str::after($model->getRealPath(), realpath(app_path()).DIRECTORY_SEPARATOR) ); - })->when(! empty($except), function ($models) use ($except) { - return $models->reject(function ($model) use ($except) { - return in_array($model, $except); - }); - })->filter(function ($model) { - return class_exists($model); - })->filter(function ($model) { - return $this->isPrunable($model); - })->values(); + }) + ->when(! empty($except), fn ($models) => $models->reject(fn ($model) => in_array($model, $except))) + ->filter(fn ($model) => class_exists($model)) + ->filter(fn ($model) => $this->isPrunable($model)) + ->values(); } /** diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index f824f1c90b13..be76e9754fa2 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2850,11 +2850,9 @@ public function reorder($column = null, $direction = 'asc') protected function removeExistingOrdersFor($column) { return (new Collection($this->orders)) - ->reject(function ($order) use ($column) { - return isset($order['column']) - ? $order['column'] === $column - : false; - })->values()->all(); + ->reject(fn ($order) => isset($order['column']) && $order['column'] === $column) + ->values() + ->all(); } /** diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index b6c416b1363b..5f735925ed04 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -114,9 +114,10 @@ public function handle() */ protected function getRoutes() { - $routes = (new Collection($this->router->getRoutes()))->map(function ($route) { - return $this->getRouteInformation($route); - })->filter()->all(); + $routes = (new Collection($this->router->getRoutes())) + ->map(fn ($route) => $this->getRouteInformation($route)) + ->filter() + ->all(); if (($sort = $this->option('sort')) !== null) { $routes = $this->sortRoutes($sort, $routes); @@ -208,9 +209,9 @@ protected function displayRoutes(array $routes) */ protected function getMiddleware($route) { - return (new Collection($this->router->gatherRouteMiddleware($route)))->map(function ($middleware) { - return $middleware instanceof Closure ? 'Closure' : $middleware; - })->implode("\n"); + return (new Collection($this->router->gatherRouteMiddleware($route))) + ->map(fn ($middleware) => $middleware instanceof Closure ? 'Closure' : $middleware) + ->implode("\n"); } /** diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index f79734bdb8e2..a4b773c4a43f 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -483,10 +483,14 @@ public function stopIgnoring(array|string $exceptions) $exceptions = Arr::wrap($exceptions); $this->dontReport = (new Collection($this->dontReport)) - ->reject(fn ($ignored) => in_array($ignored, $exceptions))->values()->all(); + ->reject(fn ($ignored) => in_array($ignored, $exceptions)) + ->values() + ->all(); $this->internalDontReport = (new Collection($this->internalDontReport)) - ->reject(fn ($ignored) => in_array($ignored, $exceptions))->values()->all(); + ->reject(fn ($ignored) => in_array($ignored, $exceptions)) + ->values() + ->all(); return $this; } diff --git a/src/Illuminate/Foundation/PackageManifest.php b/src/Illuminate/Foundation/PackageManifest.php index c569b7740fb4..c3f66ba69ab1 100644 --- a/src/Illuminate/Foundation/PackageManifest.php +++ b/src/Illuminate/Foundation/PackageManifest.php @@ -88,9 +88,10 @@ public function aliases() */ public function config($key) { - return (new Collection($this->getManifest()))->flatMap(function ($configuration) use ($key) { - return (array) ($configuration[$key] ?? []); - })->filter()->all(); + return (new Collection($this->getManifest())) + ->flatMap(fn ($configuration) => (array) ($configuration[$key] ?? [])) + ->filter() + ->all(); } /** diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 2915bc3f367c..cf87583e3264 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -991,13 +991,15 @@ protected function parseHttpOptions(array $options) $options[$this->bodyFormat] = $this->pendingBody; } - return (new Collection($options))->map(function ($value, $key) { - if ($key === 'json' && $value instanceof JsonSerializable) { - return $value; - } + return (new Collection($options)) + ->map(function ($value, $key) { + if ($key === 'json' && $value instanceof JsonSerializable) { + return $value; + } - return $value instanceof Arrayable ? $value->toArray() : $value; - })->all(); + return $value instanceof Arrayable ? $value->toArray() : $value; + }) + ->all(); } /** diff --git a/src/Illuminate/Notifications/Channels/MailChannel.php b/src/Illuminate/Notifications/Channels/MailChannel.php index f11016ddb1c6..81215f3b0348 100644 --- a/src/Illuminate/Notifications/Channels/MailChannel.php +++ b/src/Illuminate/Notifications/Channels/MailChannel.php @@ -263,11 +263,13 @@ protected function getRecipients($notifiable, $notification, $message) $recipients = [$recipients]; } - return (new Collection($recipients))->mapWithKeys(function ($recipient, $email) { - return is_numeric($email) - ? [$email => (is_string($recipient) ? $recipient : $recipient->email)] - : [$email => $recipient]; - })->all(); + return (new Collection($recipients)) + ->mapWithKeys(function ($recipient, $email) { + return is_numeric($email) + ? [$email => (is_string($recipient) ? $recipient : $recipient->email)] + : [$email => $recipient]; + }) + ->all(); } /** diff --git a/src/Illuminate/Notifications/Messages/MailMessage.php b/src/Illuminate/Notifications/Messages/MailMessage.php index a80117a50178..f6eab8ca6798 100644 --- a/src/Illuminate/Notifications/Messages/MailMessage.php +++ b/src/Illuminate/Notifications/Messages/MailMessage.php @@ -372,9 +372,10 @@ public function data() */ protected function parseAddresses($value) { - return (new Collection($value))->map(function ($address, $name) { - return [$address, is_numeric($name) ? null : $name]; - })->values()->all(); + return (new Collection($value)) + ->map(fn ($address, $name) => [$address, is_numeric($name) ? null : $name]) + ->values() + ->all(); } /** diff --git a/src/Illuminate/Process/FakeProcessDescription.php b/src/Illuminate/Process/FakeProcessDescription.php index fdf6dc18cdba..1c397176eafb 100644 --- a/src/Illuminate/Process/FakeProcessDescription.php +++ b/src/Illuminate/Process/FakeProcessDescription.php @@ -94,9 +94,10 @@ public function errorOutput(array|string $output) */ public function replaceOutput(string $output) { - $this->output = (new Collection($this->output))->reject(function ($output) { - return $output['type'] === 'out'; - })->values()->all(); + $this->output = (new Collection($this->output)) + ->reject(fn ($output) => $output['type'] === 'out') + ->values() + ->all(); if (strlen($output) > 0) { $this->output[] = [ @@ -116,9 +117,10 @@ public function replaceOutput(string $output) */ public function replaceErrorOutput(string $output) { - $this->output = (new Collection($this->output))->reject(function ($output) { - return $output['type'] === 'err'; - })->values()->all(); + $this->output = (new Collection($this->output)) + ->reject(fn ($output) => $output['type'] === 'err') + ->values() + ->all(); if (strlen($output) > 0) { $this->output[] = [ diff --git a/src/Illuminate/Process/Pool.php b/src/Illuminate/Process/Pool.php index 1a98a8541a57..3e274d84c783 100644 --- a/src/Illuminate/Process/Pool.php +++ b/src/Illuminate/Process/Pool.php @@ -74,7 +74,8 @@ public function start(?callable $output = null) if (! $pendingProcess instanceof PendingProcess) { throw new InvalidArgumentException('Process pool must only contain pending processes.'); } - })->mapWithKeys(function ($pendingProcess, $key) use ($output) { + }) + ->mapWithKeys(function ($pendingProcess, $key) use ($output) { return [$key => $pendingProcess->start(output: $output ? function ($type, $buffer) use ($key, $output) { $output($type, $buffer, $key); } : null)]; diff --git a/src/Illuminate/Queue/Failed/FileFailedJobProvider.php b/src/Illuminate/Queue/Failed/FileFailedJobProvider.php index dff5f44a6082..61f66657654d 100644 --- a/src/Illuminate/Queue/Failed/FileFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/FileFailedJobProvider.php @@ -155,9 +155,11 @@ public function prune(DateTimeInterface $before) return $this->lock(function () use ($before) { $jobs = $this->read(); - $this->write($prunedJobs = (new Collection($jobs))->reject(function ($job) use ($before) { - return $job->failed_at_timestamp <= $before->getTimestamp(); - })->values()->all()); + $this->write($prunedJobs = (new Collection($jobs)) + ->reject(fn ($job) => $job->failed_at_timestamp <= $before->getTimestamp()) + ->values() + ->all() + ); return count($jobs) - count($prunedJobs); }); diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index d877268d1ffb..a4ccd94cb99b 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -1139,15 +1139,22 @@ public function controllerMiddleware() */ protected function staticallyProvidedControllerMiddleware(string $class, string $method) { - return (new Collection($class::middleware()))->map(function ($middleware) { - return $middleware instanceof Middleware - ? $middleware - : new Middleware($middleware); - })->reject(function ($middleware) use ($method) { - return static::methodExcludedByOptions( - $method, ['only' => $middleware->only, 'except' => $middleware->except] - ); - })->map->middleware->flatten()->values()->all(); + return (new Collection($class::middleware())) + ->map(function ($middleware) { + return $middleware instanceof Middleware + ? $middleware + : new Middleware($middleware); + }) + ->reject(function ($middleware) use ($method) { + return static::methodExcludedByOptions( + $method, ['only' => $middleware->only, 'except' => $middleware->except], + ); + }) + ->map + ->middleware + ->flatten() + ->values() + ->all(); } /** diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index d29050277ca5..4a0c21ccc48b 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -830,9 +830,13 @@ public function gatherRouteMiddleware(Route $route) */ public function resolveMiddleware(array $middleware, array $excluded = []) { - $excluded = $excluded === [] ? $excluded : (new Collection($excluded))->map(function ($name) { - return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups); - })->flatten()->values()->all(); + $excluded = $excluded === [] + ? $excluded + : (new Collection($excluded)) + ->map(fn ($name) => (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups)) + ->flatten() + ->values() + ->all(); $middleware = (new Collection($middleware))->map(function ($name) { return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups); diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 556479fabb16..3bb47011d654 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -1051,8 +1051,10 @@ public static function password($length = 32, $letters = true, $numbers = true, ']', '|', ':', ';', ] : null, 'spaces' => $spaces === true ? [' '] : null, - ]))->filter()->each(fn ($c) => $password->push($c[random_int(0, count($c) - 1)]) - )->flatten(); + ])) + ->filter() + ->each(fn ($c) => $password->push($c[random_int(0, count($c) - 1)])) + ->flatten(); $length = $length - $password->count(); diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index 75e976583c0d..d703ab12fe59 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -379,9 +379,10 @@ public function connection($value = null) */ public function size($queue = null) { - return (new Collection($this->jobs))->flatten(1)->filter( - fn ($job) => $job['queue'] === $queue - )->count(); + return (new Collection($this->jobs)) + ->flatten(1) + ->filter(fn ($job) => $job['queue'] === $queue) + ->count(); } /** diff --git a/src/Illuminate/Support/Traits/InteractsWithData.php b/src/Illuminate/Support/Traits/InteractsWithData.php index 722478ec0a0b..bd39205d942d 100644 --- a/src/Illuminate/Support/Traits/InteractsWithData.php +++ b/src/Illuminate/Support/Traits/InteractsWithData.php @@ -338,9 +338,10 @@ public function enums($key, $enumClass) return []; } - return $this->collect($key)->map(function ($value) use ($enumClass) { - return $enumClass::tryFrom($value); - })->filter()->all(); + return $this->collect($key) + ->map(fn ($value) => $enumClass::tryFrom($value)) + ->filter() + ->all(); } /** diff --git a/src/Illuminate/Support/Traits/ReflectsClosures.php b/src/Illuminate/Support/Traits/ReflectsClosures.php index 34f3ec805e89..9e12285a30a7 100644 --- a/src/Illuminate/Support/Traits/ReflectsClosures.php +++ b/src/Illuminate/Support/Traits/ReflectsClosures.php @@ -47,13 +47,17 @@ protected function firstClosureParameterTypes(Closure $closure) { $reflection = new ReflectionFunction($closure); - $types = (new Collection($reflection->getParameters()))->mapWithKeys(function ($parameter) { - if ($parameter->isVariadic()) { - return [$parameter->getName() => null]; - } + $types = (new Collection($reflection->getParameters())) + ->mapWithKeys(function ($parameter) { + if ($parameter->isVariadic()) { + return [$parameter->getName() => null]; + } - return [$parameter->getName() => Reflector::getParameterClassNames($parameter)]; - })->filter()->values()->all(); + return [$parameter->getName() => Reflector::getParameterClassNames($parameter)]; + }) + ->filter() + ->values() + ->all(); if (empty($types)) { throw new RuntimeException('The given Closure has no parameters.'); @@ -78,12 +82,14 @@ protected function closureParameterTypes(Closure $closure) { $reflection = new ReflectionFunction($closure); - return (new Collection($reflection->getParameters()))->mapWithKeys(function ($parameter) { - if ($parameter->isVariadic()) { - return [$parameter->getName() => null]; - } + return (new Collection($reflection->getParameters())) + ->mapWithKeys(function ($parameter) { + if ($parameter->isVariadic()) { + return [$parameter->getName() => null]; + } - return [$parameter->getName() => Reflector::getParameterClassName($parameter)]; - })->all(); + return [$parameter->getName() => Reflector::getParameterClassName($parameter)]; + }) + ->all(); } } diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 517577dac5d5..0bafe724bb0b 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -1042,9 +1042,11 @@ public function invalid() */ protected function attributesThatHaveMessages() { - return (new Collection($this->messages()->toArray()))->map(function ($message, $key) { - return explode('.', $key)[0]; - })->unique()->flip()->all(); + return (new Collection($this->messages()->toArray())) + ->map(fn ($message, $key) => explode('.', $key)[0]) + ->unique() + ->flip() + ->all(); } /** @@ -1217,9 +1219,11 @@ public function getRulesWithoutPlaceholders() */ public function setRules(array $rules) { - $rules = (new Collection($rules))->mapWithKeys(function ($value, $key) { - return [str_replace('\.', '__dot__'.static::$placeholderHash, $key) => $value]; - })->toArray(); + $rules = (new Collection($rules)) + ->mapWithKeys(function ($value, $key) { + return [str_replace('\.', '__dot__'.static::$placeholderHash, $key) => $value]; + }) + ->toArray(); $this->initialRules = $rules; From ca0412e978f78ecea0cafbe34dd8b18010064f73 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:49:19 +0000 Subject: [PATCH 212/455] Update version to v12.3.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 38378aa3605d..5e2178803d79 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.2.0'; + const VERSION = '12.3.0'; /** * The base path for the Laravel installation. From 704555cbc6f1ad979209a5a410243f88bad4e3e2 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:51:21 +0000 Subject: [PATCH 213/455] Update CHANGELOG --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f288f24595b0..4cd6c6b13a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,42 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.2.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.3.0...12.x) + +## [v12.3.0](https://github.com/laravel/framework/compare/v12.2.0...v12.3.0) - 2025-03-18 + +* [12.x] fixes https://github.com/laravel/octane/issues/1010 by [@mihaileu](https://github.com/mihaileu) in https://github.com/laravel/framework/pull/55008 +* Added the missing 'trashed' event to getObservablesEvents() by [@duemti](https://github.com/duemti) in https://github.com/laravel/framework/pull/55004 +* [12.x] Enhance PHPDoc for Manager classes with `@param-closure-this` by [@kayw-geek](https://github.com/kayw-geek) in https://github.com/laravel/framework/pull/55002 +* [12.x] Fix `PendingRequest` typehints for `post`, `patch`, `put`, `delete` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54998 +* [12.x] Add test for untested methods in LazyCollection by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/54996 +* [12.x] fix indentation by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/54995 +* [12.x] apply final Pint fixes by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55014 +* Enhance validation tests: Add test for connection name detection in Unique rule by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/54993 +* [12.x] Add json:unicode cast to support JSON_UNESCAPED_UNICODE encoding by [@fuwasegu](https://github.com/fuwasegu) in https://github.com/laravel/framework/pull/54992 +* [12.x] Add “Storage Linked” to the `about` command by [@adampatterson](https://github.com/adampatterson) in https://github.com/laravel/framework/pull/54949 +* [12.x] Add support for native JSON/JSONB column types in SQLite Schema builder by [@fuwasegu](https://github.com/fuwasegu) in https://github.com/laravel/framework/pull/54991 +* [12.x] Fix `LogManager::configurationFor()` typehint by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55016 +* [12.x] Add missing tests for LazyCollection methods by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55022 +* [12.x] Refactor: Structural improvement for clarity by [@AhmedAlaa4611](https://github.com/AhmedAlaa4611) in https://github.com/laravel/framework/pull/55018 +* Improve `toKilobytes` to handle spaces and case-insensitive units by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/55019 +* [12.x] Fix mistake in `asJson` call in `HasAttributes.php` that was recently introduced by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/55017 +* [12.x] reapply Pint style changes by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55015 +* Add validation test for forEach with null and empty array values by [@alikhosravidev](https://github.com/alikhosravidev) in https://github.com/laravel/framework/pull/55047 +* [12.x] Types: EnumeratesValues Sum by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/55044 +* [12.x] Ensure Consistent Formatting in Generated Invokable Classes by [@AhmedAlaa4611](https://github.com/AhmedAlaa4611) in https://github.com/laravel/framework/pull/55034 +* Add element type to return array in Filesystem by [@AJenbo](https://github.com/AJenbo) in https://github.com/laravel/framework/pull/55031 +* [12.x] Add support for PostgreSQL "unique nulls not distinct" by [@thierry2015](https://github.com/thierry2015) in https://github.com/laravel/framework/pull/55025 +* [12.x] standardize multiline ternaries by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55056 +* [12.x] improved readability for `aliasedPivotColumns` by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55055 +* [12.x] remove progress bar from PHPStan output by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55054 +* [12.x] Fixes how the fluent Date rule builder handles `date_format` by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/55052 +* Adding SSL encryption and support for MySQL connection by [@mdiktushar](https://github.com/mdiktushar) in https://github.com/laravel/framework/pull/55048 +* Revert "Adding SSL encryption and support for MySQL connection" by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/framework/pull/55057 +* Ensure queue property is nullable by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/55058 +* [12.x] return `$this` for chaining by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55060 +* [12.x] prefer `new Collection` over `collect()` by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55059 +* [12.x] use "class-string" type for `using` pivot model by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55053 +* [12.x] multiline chaining on Collections by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55061 ## [v12.2.0](https://github.com/laravel/framework/compare/v12.1.1...v12.2.0) - 2025-03-12 From c3670c2b1d5e709070266495061a03bb98fe19aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 18 Mar 2025 19:03:55 +0100 Subject: [PATCH 214/455] =?UTF-8?q?Reset=20PHP=E2=80=99s=20peak=20memory?= =?UTF-8?q?=20usage=20when=20resetting=20scope=20for=20queue=20worker=20(#?= =?UTF-8?q?55069)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is similar to the reset of the total query duration that is already happening. PHP’s peak memory usage is another bit of global state is not useful to keep in a long-running process handling individual self-contained jobs. By resetting the peak memory usage for each executed job it becomes possible to measure a given job’s maximum memory usage accurately, allowing to optimize hardware resources, for example by placing individual jobs with a high-memory usage into their own queue that is executed on a larger worker instance. --- src/Illuminate/Queue/QueueServiceProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index c249d3842d7c..3b1d97208da0 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -216,6 +216,8 @@ protected function registerWorker() $app->forgetScopedInstances(); Facade::clearResolvedInstances(); + + memory_reset_peak_usage(); }; return new Worker( From 34f4932d106e6289b2f5c9f550ceeaf2efc668e8 Mon Sep 17 00:00:00 2001 From: "Ralph J. Smit" <59207045+ralphjsmit@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:15:48 +0100 Subject: [PATCH 215/455] [12.x] Add `AsHtmlString` cast (#55071) * Add AsHtmlString cast * Style --- .../Database/Eloquent/Casts/AsHtmlString.php | 32 +++++++++++++++++++ tests/Database/DatabaseEloquentModelTest.php | 21 ++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/Illuminate/Database/Eloquent/Casts/AsHtmlString.php diff --git a/src/Illuminate/Database/Eloquent/Casts/AsHtmlString.php b/src/Illuminate/Database/Eloquent/Casts/AsHtmlString.php new file mode 100644 index 000000000000..d4182d258f79 --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Casts/AsHtmlString.php @@ -0,0 +1,32 @@ + + */ + public static function castUsing(array $arguments) + { + return new class implements CastsAttributes + { + public function get($model, $key, $value, $attributes) + { + return isset($value) ? new HtmlString($value) : null; + } + + public function set($model, $key, $value, $attributes) + { + return isset($value) ? (string) $value : null; + } + }; + } +} diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 2095f267a2a6..1213b3d34849 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -26,6 +26,7 @@ use Illuminate\Database\Eloquent\Casts\AsEncryptedCollection; use Illuminate\Database\Eloquent\Casts\AsEnumArrayObject; use Illuminate\Database\Eloquent\Casts\AsEnumCollection; +use Illuminate\Database\Eloquent\Casts\AsHtmlString; use Illuminate\Database\Eloquent\Casts\AsStringable; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Collection; @@ -45,6 +46,7 @@ use Illuminate\Support\Carbon; use Illuminate\Support\Collection as BaseCollection; use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\HtmlString; use Illuminate\Support\InteractsWithTime; use Illuminate\Support\Stringable; use InvalidArgumentException; @@ -264,6 +266,24 @@ public function testDirtyOnCastedStringable() $this->assertTrue($model->isDirty('asStringableAttribute')); } + public function testDirtyOnCastedHtmlString() + { + $model = new EloquentModelCastingStub; + $model->setRawAttributes([ + 'asHtmlStringAttribute' => '
foo bar
', + ]); + $model->syncOriginal(); + + $this->assertInstanceOf(HtmlString::class, $model->asHtmlStringAttribute); + $this->assertFalse($model->isDirty('asHtmlStringAttribute')); + + $model->asHtmlStringAttribute = new HtmlString('
foo bar
'); + $this->assertFalse($model->isDirty('asHtmlStringAttribute')); + + $model->asHtmlStringAttribute = new Stringable('
foo baz
'); + $this->assertTrue($model->isDirty('asHtmlStringAttribute')); + } + // public function testDirtyOnCastedEncryptedCollection() // { // $this->encrypter = m::mock(Encrypter::class); @@ -3670,6 +3690,7 @@ protected function casts(): array 'datetimeAttribute' => 'datetime', 'asarrayobjectAttribute' => AsArrayObject::class, 'asStringableAttribute' => AsStringable::class, + 'asHtmlStringAttribute' => AsHtmlString::class, 'asCustomCollectionAttribute' => AsCollection::using(CustomCollection::class), 'asEncryptedArrayObjectAttribute' => AsEncryptedArrayObject::class, 'asEncryptedCustomCollectionAttribute' => AsEncryptedCollection::using(CustomCollection::class), From e9ce3765f685991eb71f1d4d4bb723c0fccff22d Mon Sep 17 00:00:00 2001 From: "Ralph J. Smit" <59207045+ralphjsmit@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:16:46 +0100 Subject: [PATCH 216/455] [12.x] Add `Arr::sole()` method (#55070) * Add Arr::sole() * Update Collection.php * Style * Update Arr.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Collections/Arr.php | 28 +++++++++++++++++++++++++++ tests/Support/SupportArrTest.php | 31 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 25e240e693d6..72562305f251 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -807,6 +807,34 @@ public static function shuffle($array) return (new Randomizer)->shuffleArray($array); } + /** + * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. + * + * @param array $array + * @param callable $callback + * + * @throws \Illuminate\Support\ItemNotFoundException + * @throws \Illuminate\Support\MultipleItemsFoundException + */ + public static function sole($array, ?callable $callback = null) + { + if ($callback) { + $array = static::where($array, $callback); + } + + $count = count($array); + + if ($count === 0) { + throw new ItemNotFoundException; + } + + if ($count > 1) { + throw new MultipleItemsFoundException($count); + } + + return static::first($array); + } + /** * Sort the array using the given callback or "dot" notation. * diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index b7805c6127a3..856119824752 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -6,6 +6,8 @@ use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; +use Illuminate\Support\ItemNotFoundException; +use Illuminate\Support\MultipleItemsFoundException; use InvalidArgumentException; use PHPUnit\Framework\TestCase; use stdClass; @@ -1067,6 +1069,35 @@ public function testShuffleKeepsSameValues() $this->assertEquals($input, $shuffled); } + public function testSoleReturnsFirstItemInCollectionIfOnlyOneExists() + { + $this->assertSame('foo', Arr::sole(['foo'])); + + $array = [ + ['name' => 'foo'], + ['name' => 'bar'], + ]; + + $this->assertSame( + ['name' => 'foo'], + Arr::sole($array, fn (array $value) => $value['name'] === 'foo') + ); + } + + public function testSoleThrowsExceptionIfNoItemsExist() + { + $this->expectException(ItemNotFoundException::class); + + Arr::sole(['foo'], fn (string $value) => $value === 'baz'); + } + + public function testSoleThrowsExceptionIfMoreThanOneItemExists() + { + $this->expectExceptionObject(new MultipleItemsFoundException(2)); + + Arr::sole(['baz', 'foo', 'baz'], fn (string $value) => $value === 'baz'); + } + public function testEmptyShuffle() { $this->assertEquals([], Arr::shuffle([])); From d7b5366c3e92e8eb36cb0d2c5e6cceb15123a249 Mon Sep 17 00:00:00 2001 From: Sajjad Hossain Shohag <63788037+sajjadhossainshohag@users.noreply.github.com> Date: Wed, 19 Mar 2025 19:48:45 +0600 Subject: [PATCH 217/455] Improve warning message in `ApiInstallCommand` (#55081) * improved api install command failed message * Update ApiInstallCommand.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Foundation/Console/ApiInstallCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index aeec5c0c2db2..9c460555e80a 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -110,7 +110,7 @@ protected function uncommentApiRoutesFile() $appBootstrapPath, ); } else { - $this->components->warn('Unable to automatically add API route definition to bootstrap file. API route file should be registered manually.'); + $this->components->warn("Unable to automatically add API route definition to [{$appBootstrapPath}]. API route file should be registered manually."); return; } From 8a0625df2edb76e5ef0063d1ffdc2d8cefe8b3a4 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 19 Mar 2025 08:49:46 -0500 Subject: [PATCH 218/455] use already determined `related` property (#55075) we already pull the related model off of the `$query` in the constructor, so we can use it directly. introduced in #43724 --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index f6c64aeac1bc..574560a398ed 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -172,7 +172,7 @@ abstract public function getResults(); public function getEager() { return $this->eagerKeysWereEmpty - ? $this->query->getModel()->newCollection() + ? $this->related->newCollection() : $this->get(); } From b1008affab68a32ba7d622696535eff4d6e2cfcf Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 19 Mar 2025 08:53:01 -0500 Subject: [PATCH 219/455] use "class-string" where appropriate in relations (#55074) we'll use the more accurate "class-string" type for "morphClass" references. also specify the generic type where appropriate --- src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php | 4 ++-- src/Illuminate/Database/Eloquent/Relations/MorphPivot.php | 4 ++-- src/Illuminate/Database/Eloquent/Relations/MorphToMany.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 1e879c1dcef1..9720cc218ed0 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -25,7 +25,7 @@ abstract class MorphOneOrMany extends HasOneOrMany /** * The class name of the parent model. * - * @var string + * @var class-string */ protected $morphClass; @@ -159,7 +159,7 @@ public function getMorphType() /** * Get the class name of the parent model. * - * @return string + * @return class-string */ public function getMorphClass() { diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php index 566e198c9bea..01aea33950fd 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php @@ -18,7 +18,7 @@ class MorphPivot extends Pivot * * Explicitly define this so it's not included in saved attributes. * - * @var string + * @var class-string */ protected $morphClass; @@ -100,7 +100,7 @@ public function setMorphType($morphType) /** * Set the morph class for the pivot. * - * @param string $morphClass + * @param class-string $morphClass * @return \Illuminate\Database\Eloquent\Relations\MorphPivot */ public function setMorphClass($morphClass) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index dd5deb2fc0de..f029fa1e97bc 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -25,7 +25,7 @@ class MorphToMany extends BelongsToMany /** * The class name of the morph type constraint. * - * @var string + * @var class-string */ protected $morphClass; @@ -212,7 +212,7 @@ public function getQualifiedMorphTypeName() /** * Get the class name of the parent model. * - * @return string + * @return class-string */ public function getMorphClass() { From 6d6e4e1900eb143fbc6207cd1f3a38dc62ff517a Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:17:52 -0400 Subject: [PATCH 220/455] [12.x] `QueueFake::listenersPushed()` (#55063) * QueueFake::listenersPushed() * import * payload --- .../Support/Testing/Fakes/QueueFake.php | 24 +++++++++++++++++++ .../Integration/Queue/QueuedListenersTest.php | 19 ++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index d703ab12fe59..5209ed60c9d6 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -5,6 +5,7 @@ use BadMethodCallException; use Closure; use Illuminate\Contracts\Queue\Queue; +use Illuminate\Events\CallQueuedListener; use Illuminate\Queue\CallQueuedClosure; use Illuminate\Queue\QueueManager; use Illuminate\Support\Collection; @@ -349,6 +350,29 @@ public function pushedRaw($callback = null) return (new Collection($this->rawPushes))->filter(fn ($data) => $callback($data['payload'], $data['queue'], $data['options'])); } + /** + * Get all of the jobs by listener class, passing an optional truth-test callback. + * + * @param class-string $listenerClass + * @param (\Closure(mixed, \Illuminate\Events\CallQueuedListener, string|null, mixed): bool)|null $callback + * @return \Illuminate\Support\Collection + */ + public function listenersPushed($listenerClass, $callback = null) + { + if (! $this->hasPushed(CallQueuedListener::class)) { + return new Collection; + } + + $collection = (new Collection($this->jobs[CallQueuedListener::class])) + ->filter(fn ($data) => $data['job']->class === $listenerClass); + + if ($callback) { + $collection = $collection->filter(fn ($data) => $callback($data['job']->data[0] ?? null, $data['job'], $data['queue'], $data['data'])); + } + + return $collection->pluck('job'); + } + /** * Determine if there are any stored jobs for a given class. * diff --git a/tests/Integration/Queue/QueuedListenersTest.php b/tests/Integration/Queue/QueuedListenersTest.php index 6268ac040549..56f242d3a809 100644 --- a/tests/Integration/Queue/QueuedListenersTest.php +++ b/tests/Integration/Queue/QueuedListenersTest.php @@ -25,15 +25,32 @@ public function testListenersCanBeQueuedOptionally() return $job->class == QueuedListenersTestListenerShouldQueue::class; }); + $this->assertCount(1, Queue::listenersPushed(QueuedListenersTestListenerShouldQueue::class)); + $this->assertCount( + 0, + Queue::listenersPushed( + QueuedListenersTestListenerShouldQueue::class, + fn ($event, $handler, $queue, $data) => $queue === 'not-a-real-queue' + ) + ); + $this->assertCount( + 1, + Queue::listenersPushed( + QueuedListenersTestListenerShouldQueue::class, + fn (QueuedListenersTestEvent $event) => $event->value === 100 + ) + ); + Queue::assertNotPushed(CallQueuedListener::class, function ($job) { return $job->class == QueuedListenersTestListenerShouldNotQueue::class; }); + $this->assertCount(0, Queue::listenersPushed(QueuedListenersTestListenerShouldNotQueue::class)); } } class QueuedListenersTestEvent { - // + public int $value = 100; } class QueuedListenersTestListenerShouldQueue implements ShouldQueue From 40373f94ed3bfba7f32480d7cbabb88ecd29e234 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 19 Mar 2025 14:18:28 +0000 Subject: [PATCH 221/455] Update facade docblocks --- src/Illuminate/Support/Facades/Queue.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Queue.php b/src/Illuminate/Support/Facades/Queue.php index 0abb5befbe45..f11c374c8dac 100755 --- a/src/Illuminate/Support/Facades/Queue.php +++ b/src/Illuminate/Support/Facades/Queue.php @@ -49,6 +49,7 @@ * @method static void assertNothingPushed() * @method static \Illuminate\Support\Collection pushed(string $job, callable|null $callback = null) * @method static \Illuminate\Support\Collection pushedRaw(null|\Closure $callback = null) + * @method static \Illuminate\Support\Collection listenersPushed(string $listenerClass, \Closure|null $callback = null) * @method static bool hasPushed(string $job) * @method static bool shouldFakeJob(object $job) * @method static array pushedJobs() From 0026d3ba0d4ed7fc0c2514581cf901abba51b8a8 Mon Sep 17 00:00:00 2001 From: Vishal Chavda <41144797+vishal2931@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:26:18 +0530 Subject: [PATCH 222/455] [12.x] Added except() method to Model class for excluding attributes (#55072) * Added except() method to Model class for excluding attributes * Refactor code * Refactor code * Code formatting --- .../Eloquent/Concerns/HasAttributes.php | 21 +++++++++++++++++++ tests/Database/DatabaseEloquentModelTest.php | 12 +++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 5f2d6fea5c70..fcdb7e35e761 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -2007,6 +2007,27 @@ public function only($attributes) return $results; } + /** + * Get all attributes except the given ones. + * + * @param array|mixed $attributes + * @return array + */ + public function except($attributes) + { + $attributes = is_array($attributes) ? $attributes : func_get_args(); + + $results = []; + + foreach ($this->getAttributes() as $key => $value) { + if (! in_array($key, $attributes)) { + $results[$key] = $value; + } + } + + return $results; + } + /** * Sync the original attributes with the current. * diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 1213b3d34849..4b9a2be34364 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -605,6 +605,18 @@ public function testOnly() $this->assertEquals(['first_name' => 'taylor', 'last_name' => 'otwell'], $model->only(['first_name', 'last_name'])); } + public function testExcept() + { + $model = new EloquentModelStub; + $model->first_name = 'taylor'; + $model->last_name = 'otwell'; + $model->project = 'laravel'; + + $this->assertEquals(['first_name' => 'taylor', 'last_name' => 'otwell'], $model->except('project')); + $this->assertEquals(['project' => 'laravel'], $model->except('first_name', 'last_name')); + $this->assertEquals(['project' => 'laravel'], $model->except(['first_name', 'last_name'])); + } + public function testNewInstanceReturnsNewInstanceWithAttributesSet() { $model = new EloquentModelStub; From 069e86837042bf61c66865b7594623e4e8547403 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Wed, 19 Mar 2025 15:03:18 -0500 Subject: [PATCH 223/455] fix: add TPivotModel default and define pivot property in {Belongs,Morph}ToMany (#55086) --- .../Eloquent/Relations/BelongsToMany.php | 87 ++++++++++++------- .../Eloquent/Relations/MorphToMany.php | 8 +- types/Database/Eloquent/Relations.php | 78 ++++++++--------- 3 files changed, 99 insertions(+), 74 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 2e5a071faa2e..9e8a30c8de95 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -20,9 +20,12 @@ /** * @template TRelatedModel of \Illuminate\Database\Eloquent\Model * @template TDeclaringModel of \Illuminate\Database\Eloquent\Model - * @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot + * @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot = \Illuminate\Database\Eloquent\Relations\Pivot + * @template TAccessor of string = 'pivot' * - * @extends \Illuminate\Database\Eloquent\Relations\Relation> + * @extends \Illuminate\Database\Eloquent\Relations\Relation> + * + * @todo use TAccessor when PHPStan bug is fixed: https://github.com/phpstan/phpstan/issues/12756 */ class BelongsToMany extends Relation { @@ -136,7 +139,7 @@ class BelongsToMany extends Relation /** * The name of the accessor to use for the "pivot" relationship. * - * @var string + * @var TAccessor */ protected $accessor = 'pivot'; @@ -327,8 +330,12 @@ public function getPivotClass() /** * Specify the custom pivot model to use for the relationship. * - * @param class-string $class + * @template TNewPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot + * + * @param class-string $class * @return $this + * + * @phpstan-this-out static */ public function using($class) { @@ -340,8 +347,12 @@ public function using($class) /** * Specify the custom pivot accessor to use for the relationship. * - * @param string $accessor + * @template TNewAccessor of string + * + * @param TNewAccessor $accessor * @return $this + * + * @phpstan-this-out static */ public function as($accessor) { @@ -580,7 +591,11 @@ public function orderByPivot($column, $direction = 'asc') * * @param mixed $id * @param array $columns - * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TRelatedModel) + * @return ( + * $id is (\Illuminate\Contracts\Support\Arrayable|array) + * ? \Illuminate\Database\Eloquent\Collection + * : TRelatedModel&object{pivot: TPivotModel} + * ) */ public function findOrNew($id, $columns = ['*']) { @@ -596,7 +611,7 @@ public function findOrNew($id, $columns = ['*']) * * @param array $attributes * @param array $values - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function firstOrNew(array $attributes = [], array $values = []) { @@ -614,7 +629,7 @@ public function firstOrNew(array $attributes = [], array $values = []) * @param array $values * @param array $joining * @param bool $touch - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function firstOrCreate(array $attributes = [], array $values = [], array $joining = [], $touch = true) { @@ -640,7 +655,7 @@ public function firstOrCreate(array $attributes = [], array $values = [], array * @param array $values * @param array $joining * @param bool $touch - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function createOrFirst(array $attributes = [], array $values = [], array $joining = [], $touch = true) { @@ -666,7 +681,7 @@ public function createOrFirst(array $attributes = [], array $values = [], array * @param array $values * @param array $joining * @param bool $touch - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true) { @@ -684,7 +699,11 @@ public function updateOrCreate(array $attributes, array $values = [], array $joi * * @param mixed $id * @param array $columns - * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TRelatedModel|null) + * @return ( + * $id is (\Illuminate\Contracts\Support\Arrayable|array) + * ? \Illuminate\Database\Eloquent\Collection + * : (TRelatedModel&object{pivot: TPivotModel})|null + * ) */ public function find($id, $columns = ['*']) { @@ -702,7 +721,7 @@ public function find($id, $columns = ['*']) * * @param mixed $id * @param array $columns - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException * @throws \Illuminate\Database\MultipleRecordsFoundException @@ -719,7 +738,7 @@ public function findSole($id, $columns = ['*']) * * @param \Illuminate\Contracts\Support\Arrayable|array $ids * @param array $columns - * @return \Illuminate\Database\Eloquent\Collection + * @return \Illuminate\Database\Eloquent\Collection */ public function findMany($ids, $columns = ['*']) { @@ -739,7 +758,11 @@ public function findMany($ids, $columns = ['*']) * * @param mixed $id * @param array $columns - * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TRelatedModel) + * @return ( + * $id is (\Illuminate\Contracts\Support\Arrayable|array) + * ? \Illuminate\Database\Eloquent\Collection + * : TRelatedModel&object{pivot: TPivotModel} + * ) * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ @@ -770,8 +793,8 @@ public function findOrFail($id, $columns = ['*']) * @param (\Closure(): TValue)|null $callback * @return ( * $id is (\Illuminate\Contracts\Support\Arrayable|array) - * ? \Illuminate\Database\Eloquent\Collection|TValue - * : TRelatedModel|TValue + * ? \Illuminate\Database\Eloquent\Collection|TValue + * : (TRelatedModel&object{pivot: TPivotModel})|TValue * ) */ public function findOr($id, $columns = ['*'], ?Closure $callback = null) @@ -804,7 +827,7 @@ public function findOr($id, $columns = ['*'], ?Closure $callback = null) * @param mixed $operator * @param mixed $value * @param string $boolean - * @return TRelatedModel|null + * @return (TRelatedModel&object{pivot: TPivotModel})|null */ public function firstWhere($column, $operator = null, $value = null, $boolean = 'and') { @@ -815,7 +838,7 @@ public function firstWhere($column, $operator = null, $value = null, $boolean = * Execute the query and get the first result. * * @param array $columns - * @return TRelatedModel|null + * @return (TRelatedModel&object{pivot: TPivotModel})|null */ public function first($columns = ['*']) { @@ -828,7 +851,7 @@ public function first($columns = ['*']) * Execute the query and get the first result or throw an exception. * * @param array $columns - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ @@ -848,7 +871,7 @@ public function firstOrFail($columns = ['*']) * * @param (\Closure(): TValue)|list $columns * @param (\Closure(): TValue)|null $callback - * @return TRelatedModel|TValue + * @return (TRelatedModel&object{pivot: TPivotModel})|TValue */ public function firstOr($columns = ['*'], ?Closure $callback = null) { @@ -942,7 +965,7 @@ protected function aliasedPivotColumns() * @param array $columns * @param string $pageName * @param int|null $page - * @return \Illuminate\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { @@ -960,7 +983,7 @@ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', * @param array $columns * @param string $pageName * @param int|null $page - * @return \Illuminate\Contracts\Pagination\Paginator + * @return \Illuminate\Contracts\Pagination\Paginator */ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { @@ -978,7 +1001,7 @@ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'p * @param array $columns * @param string $cursorName * @param string|null $cursor - * @return \Illuminate\Contracts\Pagination\CursorPaginator + * @return \Illuminate\Contracts\Pagination\CursorPaginator */ public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null) { @@ -1100,7 +1123,7 @@ public function each(callable $callback, $count = 1000) * Query lazily, by chunks of the given size. * * @param int $chunkSize - * @return \Illuminate\Support\LazyCollection + * @return \Illuminate\Support\LazyCollection */ public function lazy($chunkSize = 1000) { @@ -1117,7 +1140,7 @@ public function lazy($chunkSize = 1000) * @param int $chunkSize * @param string|null $column * @param string|null $alias - * @return \Illuminate\Support\LazyCollection + * @return \Illuminate\Support\LazyCollection */ public function lazyById($chunkSize = 1000, $column = null, $alias = null) { @@ -1140,7 +1163,7 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null) * @param int $chunkSize * @param string|null $column * @param string|null $alias - * @return \Illuminate\Support\LazyCollection + * @return \Illuminate\Support\LazyCollection */ public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) { @@ -1160,7 +1183,7 @@ public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) /** * Get a lazy collection for the given query. * - * @return \Illuminate\Support\LazyCollection + * @return \Illuminate\Support\LazyCollection */ public function cursor() { @@ -1300,7 +1323,7 @@ public function allRelatedIds() * @param TRelatedModel $model * @param array $pivotAttributes * @param bool $touch - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function save(Model $model, array $pivotAttributes = [], $touch = true) { @@ -1317,7 +1340,7 @@ public function save(Model $model, array $pivotAttributes = [], $touch = true) * @param TRelatedModel $model * @param array $pivotAttributes * @param bool $touch - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function saveQuietly(Model $model, array $pivotAttributes = [], $touch = true) { @@ -1368,7 +1391,7 @@ public function saveManyQuietly($models, array $pivotAttributes = []) * @param array $attributes * @param array $joining * @param bool $touch - * @return TRelatedModel + * @return TRelatedModel&object{pivot: TPivotModel} */ public function create(array $attributes = [], array $joining = [], $touch = true) { @@ -1391,7 +1414,7 @@ public function create(array $attributes = [], array $joining = [], $touch = tru * * @param iterable $records * @param array $joinings - * @return array + * @return array */ public function createMany(iterable $records, array $joinings = []) { @@ -1625,7 +1648,7 @@ public function getRelationName() /** * Get the name of the pivot accessor for this relationship. * - * @return string + * @return TAccessor */ public function getPivotAccessor() { diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index f029fa1e97bc..21c542de4bc9 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -10,8 +10,10 @@ /** * @template TRelatedModel of \Illuminate\Database\Eloquent\Model * @template TDeclaringModel of \Illuminate\Database\Eloquent\Model + * @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot = \Illuminate\Database\Eloquent\Relations\MorphPivot + * @template TAccessor of string = 'pivot' * - * @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany */ class MorphToMany extends BelongsToMany { @@ -122,7 +124,7 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, /** * Get the pivot models that are currently attached. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ protected function getCurrentlyAttachedPivots() { @@ -149,7 +151,7 @@ public function newPivotQuery() * * @param array $attributes * @param bool $exists - * @return \Illuminate\Database\Eloquent\Relations\Pivot + * @return TPivotModel */ public function newPivot(array $attributes = [], $exists = false) { diff --git a/types/Database/Eloquent/Relations.php b/types/Database/Eloquent/Relations.php index 416c64adbc53..a9d305707c43 100644 --- a/types/Database/Eloquent/Relations.php +++ b/types/Database/Eloquent/Relations.php @@ -41,43 +41,43 @@ function test(User $user, Post $post, Comment $comment, ChildUser $child): void assertType('Illuminate\Types\Relations\Post|false', $user->posts()->save(new Post())); assertType('Illuminate\Types\Relations\Post|false', $user->posts()->saveQuietly(new Post())); - assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $user->roles()); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->getResults()); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->find([1])); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findMany([1, 2, 3])); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOrNew([1])); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOrFail([1])); - assertType('42|Illuminate\Database\Eloquent\Collection', $user->roles()->findOr([1], fn () => 42)); - assertType('42|Illuminate\Database\Eloquent\Collection', $user->roles()->findOr([1], callback: fn () => 42)); - assertType('Illuminate\Types\Relations\Role', $user->roles()->findOrNew(1)); - assertType('Illuminate\Types\Relations\Role', $user->roles()->findOrFail(1)); - assertType('Illuminate\Types\Relations\Role|null', $user->roles()->find(1)); - assertType('42|Illuminate\Types\Relations\Role', $user->roles()->findOr(1, fn () => 42)); - assertType('42|Illuminate\Types\Relations\Role', $user->roles()->findOr(1, callback: fn () => 42)); - assertType('Illuminate\Types\Relations\Role|null', $user->roles()->first()); - assertType('42|Illuminate\Types\Relations\Role', $user->roles()->firstOr(fn () => 42)); - assertType('42|Illuminate\Types\Relations\Role', $user->roles()->firstOr(callback: fn () => 42)); - assertType('Illuminate\Types\Relations\Role|null', $user->roles()->firstWhere('foo')); - assertType('Illuminate\Types\Relations\Role', $user->roles()->firstOrNew()); - assertType('Illuminate\Types\Relations\Role', $user->roles()->firstOrFail()); - assertType('Illuminate\Types\Relations\Role', $user->roles()->firstOrCreate()); - assertType('Illuminate\Types\Relations\Role', $user->roles()->create()); - assertType('Illuminate\Types\Relations\Role', $user->roles()->createOrFirst()); - assertType('Illuminate\Types\Relations\Role', $user->roles()->updateOrCreate([])); - assertType('Illuminate\Types\Relations\Role', $user->roles()->save(new Role())); - assertType('Illuminate\Types\Relations\Role', $user->roles()->saveQuietly(new Role())); + assertType("Illuminate\Database\Eloquent\Relations\BelongsToMany", $user->roles()); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->getResults()); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->find([1])); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findMany([1, 2, 3])); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOrNew([1])); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOrFail([1])); + assertType('42|Illuminate\Database\Eloquent\Collection', $user->roles()->findOr([1], fn () => 42)); + assertType('42|Illuminate\Database\Eloquent\Collection', $user->roles()->findOr([1], callback: fn () => 42)); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->findOrNew(1)); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->findOrFail(1)); + assertType('(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})|null', $user->roles()->find(1)); + assertType('42|(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})', $user->roles()->findOr(1, fn () => 42)); + assertType('42|(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})', $user->roles()->findOr(1, callback: fn () => 42)); + assertType('(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})|null', $user->roles()->first()); + assertType('42|(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})', $user->roles()->firstOr(fn () => 42)); + assertType('42|(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})', $user->roles()->firstOr(callback: fn () => 42)); + assertType('(Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot})|null', $user->roles()->firstWhere('foo')); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->firstOrNew()); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->firstOrFail()); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->firstOrCreate()); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->create()); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->createOrFirst()); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->updateOrCreate([])); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->save(new Role())); + assertType('Illuminate\Types\Relations\Role&object{pivot: Illuminate\Database\Eloquent\Relations\Pivot}', $user->roles()->saveQuietly(new Role())); $roles = $user->roles()->getResults(); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->saveMany($roles)); - assertType('array', $user->roles()->saveMany($roles->all())); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->saveManyQuietly($roles)); - assertType('array', $user->roles()->saveManyQuietly($roles->all())); - assertType('array', $user->roles()->createMany($roles)); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->saveMany($roles)); + assertType('array', $user->roles()->saveMany($roles->all())); + assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->saveManyQuietly($roles)); + assertType('array', $user->roles()->saveManyQuietly($roles->all())); + assertType('array', $user->roles()->createMany($roles)); assertType('array{attached: array, detached: array, updated: array}', $user->roles()->sync($roles)); assertType('array{attached: array, detached: array, updated: array}', $user->roles()->syncWithoutDetaching($roles)); assertType('array{attached: array, detached: array, updated: array}', $user->roles()->syncWithPivotValues($roles, [])); - assertType('Illuminate\Support\LazyCollection', $user->roles()->lazy()); - assertType('Illuminate\Support\LazyCollection', $user->roles()->lazyById()); - assertType('Illuminate\Support\LazyCollection', $user->roles()->cursor()); + assertType('Illuminate\Support\LazyCollection', $user->roles()->lazy()); + assertType('Illuminate\Support\LazyCollection', $user->roles()->lazyById()); + assertType('Illuminate\Support\LazyCollection', $user->roles()->cursor()); assertType('Illuminate\Database\Eloquent\Relations\HasOneThrough', $user->car()); assertType('Illuminate\Types\Relations\Car|null', $user->car()->getResults()); @@ -122,8 +122,8 @@ function test(User $user, Post $post, Comment $comment, ChildUser $child): void assertType('Illuminate\Types\Relations\Comment', $comment->commentable()->associate(new Post())); assertType('Illuminate\Types\Relations\Comment', $comment->commentable()->dissociate()); - assertType('Illuminate\Database\Eloquent\Relations\MorphToMany', $post->tags()); - assertType('Illuminate\Database\Eloquent\Collection', $post->tags()->getResults()); + assertType("Illuminate\Database\Eloquent\Relations\MorphToMany", $post->tags()); + assertType('Illuminate\Database\Eloquent\Collection', $post->tags()->getResults()); assertType('42', Relation::noConstraints(fn () => 42)); } @@ -157,11 +157,11 @@ public function latestPost(): HasOne return $post; } - /** @return BelongsToMany */ + /** @return BelongsToMany */ public function roles(): BelongsToMany { $belongsToMany = $this->belongsToMany(Role::class); - assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $belongsToMany); + assertType('Illuminate\Database\Eloquent\Relations\BelongsToMany', $belongsToMany); return $belongsToMany; } @@ -298,7 +298,7 @@ public function latestComment(): MorphOne public function tags(): MorphToMany { $morphToMany = $this->morphedByMany(Tag::class, 'taggable'); - assertType('Illuminate\Database\Eloquent\Relations\MorphToMany', $morphToMany); + assertType('Illuminate\Database\Eloquent\Relations\MorphToMany', $morphToMany); return $morphToMany; } @@ -322,7 +322,7 @@ class Tag extends Model public function posts(): MorphToMany { $morphToMany = $this->morphToMany(Post::class, 'taggable'); - assertType('Illuminate\Database\Eloquent\Relations\MorphToMany', $morphToMany); + assertType('Illuminate\Database\Eloquent\Relations\MorphToMany', $morphToMany); return $morphToMany; } From 8f0e00b7f7c455b349685025117e02ece7b297dc Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 19 Mar 2025 15:10:05 -0500 Subject: [PATCH 224/455] [12.x] remove `@return` docblocks on constructors (#55076) * remove `@return` docblocks on constructors PHP constructors don't really return anything, so the docblock is kind of unnecessary. this also brings consistency since we have some that use the tag and some that do not. we have a total of 557 constructors in the framework, so we definitely used it more than we didn't, but my personal opinion is this direction makes more sense. https://docs.phpdoc.org/guide/references/phpdoc/tags/return.html#return https://github.com/laravel/framework/issues/702 https://www.php.net/manual/en/language.oop5.decon.php * minor formatting * minor formatting --- src/Illuminate/Auth/Access/AuthorizationException.php | 1 - src/Illuminate/Auth/Access/Events/GateEvaluated.php | 1 - src/Illuminate/Auth/Access/Gate.php | 1 - src/Illuminate/Auth/Access/Response.php | 1 - src/Illuminate/Auth/AuthManager.php | 1 - src/Illuminate/Auth/AuthenticationException.php | 1 - src/Illuminate/Auth/DatabaseUserProvider.php | 1 - src/Illuminate/Auth/EloquentUserProvider.php | 1 - src/Illuminate/Auth/Events/Attempting.php | 1 - src/Illuminate/Auth/Events/Authenticated.php | 1 - src/Illuminate/Auth/Events/CurrentDeviceLogout.php | 1 - src/Illuminate/Auth/Events/Failed.php | 1 - src/Illuminate/Auth/Events/Lockout.php | 1 - src/Illuminate/Auth/Events/Login.php | 1 - src/Illuminate/Auth/Events/Logout.php | 1 - src/Illuminate/Auth/Events/OtherDeviceLogout.php | 1 - src/Illuminate/Auth/Events/PasswordReset.php | 1 - src/Illuminate/Auth/Events/PasswordResetLinkSent.php | 1 - src/Illuminate/Auth/Events/Registered.php | 1 - src/Illuminate/Auth/Events/Validated.php | 1 - src/Illuminate/Auth/Events/Verified.php | 1 - src/Illuminate/Auth/GenericUser.php | 1 - src/Illuminate/Auth/Middleware/Authenticate.php | 1 - src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php | 1 - src/Illuminate/Auth/Middleware/Authorize.php | 1 - src/Illuminate/Auth/Middleware/RequirePassword.php | 1 - src/Illuminate/Auth/Notifications/ResetPassword.php | 1 - src/Illuminate/Auth/Passwords/PasswordBroker.php | 1 - src/Illuminate/Auth/Passwords/PasswordBrokerManager.php | 1 - src/Illuminate/Auth/Recaller.php | 1 - src/Illuminate/Auth/RequestGuard.php | 1 - src/Illuminate/Auth/SessionGuard.php | 1 - src/Illuminate/Auth/TokenGuard.php | 1 - src/Illuminate/Broadcasting/AnonymousEvent.php | 2 -- src/Illuminate/Broadcasting/BroadcastEvent.php | 1 - src/Illuminate/Broadcasting/BroadcastManager.php | 1 - src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php | 1 - src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php | 1 - src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php | 1 - src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php | 1 - src/Illuminate/Broadcasting/Channel.php | 1 - src/Illuminate/Broadcasting/EncryptedPrivateChannel.php | 1 - src/Illuminate/Broadcasting/PendingBroadcast.php | 1 - src/Illuminate/Broadcasting/PresenceChannel.php | 1 - src/Illuminate/Broadcasting/PrivateChannel.php | 1 - src/Illuminate/Broadcasting/UniqueBroadcastEvent.php | 1 - src/Illuminate/Bus/Batch.php | 1 - src/Illuminate/Bus/BatchFactory.php | 1 - src/Illuminate/Bus/ChainedBatch.php | 1 - src/Illuminate/Bus/Dispatcher.php | 1 - src/Illuminate/Bus/Events/BatchDispatched.php | 1 - src/Illuminate/Bus/PendingBatch.php | 1 - src/Illuminate/Bus/UniqueLock.php | 1 - src/Illuminate/Bus/UpdatedBatchJobCounts.php | 1 - src/Illuminate/Cache/ApcStore.php | 1 - src/Illuminate/Cache/ArrayLock.php | 1 - src/Illuminate/Cache/ArrayStore.php | 1 - src/Illuminate/Cache/CacheLock.php | 1 - src/Illuminate/Cache/CacheManager.php | 1 - src/Illuminate/Cache/Console/ClearCommand.php | 1 - src/Illuminate/Cache/Console/ForgetCommand.php | 1 - src/Illuminate/Cache/DatabaseLock.php | 1 - src/Illuminate/Cache/DatabaseStore.php | 1 - src/Illuminate/Cache/DynamoDbLock.php | 1 - src/Illuminate/Cache/DynamoDbStore.php | 1 - src/Illuminate/Cache/Events/CacheEvent.php | 1 - src/Illuminate/Cache/Events/CacheHit.php | 1 - src/Illuminate/Cache/Events/KeyWriteFailed.php | 1 - src/Illuminate/Cache/Events/KeyWritten.php | 1 - src/Illuminate/Cache/Events/RetrievingManyKeys.php | 1 - src/Illuminate/Cache/Events/WritingKey.php | 1 - src/Illuminate/Cache/Events/WritingManyKeys.php | 1 - src/Illuminate/Cache/FileStore.php | 1 - src/Illuminate/Cache/Lock.php | 1 - src/Illuminate/Cache/MemcachedLock.php | 1 - src/Illuminate/Cache/MemcachedStore.php | 1 - src/Illuminate/Cache/PhpRedisLock.php | 1 - src/Illuminate/Cache/RateLimiter.php | 1 - src/Illuminate/Cache/RateLimiting/GlobalLimit.php | 1 - src/Illuminate/Cache/RateLimiting/Limit.php | 1 - src/Illuminate/Cache/RateLimiting/Unlimited.php | 2 -- src/Illuminate/Cache/RedisLock.php | 1 - src/Illuminate/Cache/RedisStore.php | 1 - src/Illuminate/Cache/Repository.php | 1 - src/Illuminate/Cache/TagSet.php | 1 - src/Illuminate/Cache/TaggedCache.php | 1 - src/Illuminate/Collections/Collection.php | 1 - src/Illuminate/Collections/HigherOrderCollectionProxy.php | 1 - src/Illuminate/Collections/LazyCollection.php | 1 - src/Illuminate/Collections/MultipleItemsFoundException.php | 1 - src/Illuminate/Conditionable/HigherOrderWhenProxy.php | 1 - src/Illuminate/Config/Repository.php | 1 - src/Illuminate/Console/Application.php | 1 - src/Illuminate/Console/Command.php | 2 -- src/Illuminate/Console/ContainerCommandLoader.php | 1 - src/Illuminate/Console/Events/ArtisanStarting.php | 1 - src/Illuminate/Console/Events/CommandFinished.php | 1 - src/Illuminate/Console/Events/CommandStarting.php | 1 - .../Console/Events/ScheduledBackgroundTaskFinished.php | 1 - src/Illuminate/Console/Events/ScheduledTaskFailed.php | 1 - src/Illuminate/Console/Events/ScheduledTaskFinished.php | 1 - src/Illuminate/Console/Events/ScheduledTaskSkipped.php | 1 - src/Illuminate/Console/Events/ScheduledTaskStarting.php | 1 - src/Illuminate/Console/GeneratorCommand.php | 1 - src/Illuminate/Console/MigrationGeneratorCommand.php | 1 - src/Illuminate/Console/OutputStyle.php | 1 - src/Illuminate/Console/Scheduling/CacheEventMutex.php | 1 - src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php | 1 - src/Illuminate/Console/Scheduling/Event.php | 1 - src/Illuminate/Console/Scheduling/ScheduleInterruptCommand.php | 1 - src/Illuminate/Console/Scheduling/ScheduleRunCommand.php | 2 -- src/Illuminate/Console/Signals.php | 1 - src/Illuminate/Console/View/Components/Component.php | 1 - src/Illuminate/Console/View/Components/Factory.php | 1 - src/Illuminate/Container/ContextualBindingBuilder.php | 1 - src/Illuminate/Container/RewindableGenerator.php | 1 - src/Illuminate/Contracts/Database/ModelIdentifier.php | 1 - src/Illuminate/Contracts/Queue/EntityNotFoundException.php | 1 - src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php | 1 - src/Illuminate/Cookie/Middleware/EncryptCookies.php | 1 - src/Illuminate/Database/Capsule/Manager.php | 1 - src/Illuminate/Database/Connection.php | 1 - src/Illuminate/Database/ConnectionResolver.php | 1 - src/Illuminate/Database/Connectors/ConnectionFactory.php | 1 - src/Illuminate/Database/Console/Migrations/FreshCommand.php | 1 - src/Illuminate/Database/Console/Migrations/InstallCommand.php | 1 - src/Illuminate/Database/Console/Migrations/MigrateCommand.php | 1 - .../Database/Console/Migrations/MigrateMakeCommand.php | 1 - src/Illuminate/Database/Console/Migrations/ResetCommand.php | 1 - src/Illuminate/Database/Console/Migrations/RollbackCommand.php | 1 - src/Illuminate/Database/Console/Migrations/StatusCommand.php | 1 - src/Illuminate/Database/Console/Seeds/SeedCommand.php | 1 - src/Illuminate/Database/DatabaseManager.php | 1 - src/Illuminate/Database/DatabaseTransactionRecord.php | 1 - src/Illuminate/Database/DatabaseTransactionsManager.php | 2 -- src/Illuminate/Database/Eloquent/Attributes/CollectedBy.php | 1 - src/Illuminate/Database/Eloquent/Attributes/ObservedBy.php | 1 - src/Illuminate/Database/Eloquent/Attributes/ScopedBy.php | 1 - src/Illuminate/Database/Eloquent/Attributes/UseFactory.php | 1 - .../Database/Eloquent/BroadcastableModelEventOccurred.php | 1 - src/Illuminate/Database/Eloquent/Builder.php | 1 - src/Illuminate/Database/Eloquent/Casts/Attribute.php | 1 - .../Database/Eloquent/Factories/BelongsToManyRelationship.php | 1 - .../Database/Eloquent/Factories/BelongsToRelationship.php | 1 - .../Database/Eloquent/Factories/CrossJoinSequence.php | 1 - src/Illuminate/Database/Eloquent/Factories/Factory.php | 1 - src/Illuminate/Database/Eloquent/Factories/Relationship.php | 1 - src/Illuminate/Database/Eloquent/Factories/Sequence.php | 1 - src/Illuminate/Database/Eloquent/HigherOrderBuilderProxy.php | 1 - src/Illuminate/Database/Eloquent/InvalidCastException.php | 1 - src/Illuminate/Database/Eloquent/MissingAttributeException.php | 1 - src/Illuminate/Database/Eloquent/Model.php | 1 - src/Illuminate/Database/Eloquent/ModelInspector.php | 1 - src/Illuminate/Database/Eloquent/Relations/BelongsTo.php | 1 - src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php | 1 - src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php | 1 - .../Database/Eloquent/Relations/HasOneOrManyThrough.php | 1 - src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php | 1 - src/Illuminate/Database/Eloquent/Relations/MorphTo.php | 1 - src/Illuminate/Database/Eloquent/Relations/MorphToMany.php | 1 - src/Illuminate/Database/Eloquent/Relations/Relation.php | 1 - src/Illuminate/Database/Events/ConnectionEvent.php | 1 - src/Illuminate/Database/Events/DatabaseRefreshed.php | 1 - src/Illuminate/Database/Events/MigrationEvent.php | 1 - src/Illuminate/Database/Events/MigrationsEvent.php | 1 - src/Illuminate/Database/Events/MigrationsPruned.php | 1 - src/Illuminate/Database/Events/ModelPruningFinished.php | 1 - src/Illuminate/Database/Events/ModelPruningStarting.php | 1 - src/Illuminate/Database/Events/ModelsPruned.php | 1 - src/Illuminate/Database/Events/NoPendingMigrations.php | 1 - src/Illuminate/Database/Events/QueryExecuted.php | 1 - src/Illuminate/Database/Events/SchemaDumped.php | 1 - src/Illuminate/Database/Events/SchemaLoaded.php | 1 - src/Illuminate/Database/Events/StatementPrepared.php | 1 - src/Illuminate/Database/Grammar.php | 1 - src/Illuminate/Database/LazyLoadingViolationException.php | 1 - .../Database/Migrations/DatabaseMigrationRepository.php | 1 - src/Illuminate/Database/Migrations/MigrationCreator.php | 1 - src/Illuminate/Database/Migrations/Migrator.php | 1 - src/Illuminate/Database/MultipleRecordsFoundException.php | 1 - src/Illuminate/Database/Query/Builder.php | 2 -- src/Illuminate/Database/Query/Expression.php | 1 - src/Illuminate/Database/Query/IndexHint.php | 1 - src/Illuminate/Database/Query/JoinClause.php | 1 - src/Illuminate/Database/QueryException.php | 1 - src/Illuminate/Database/SQLiteDatabaseDoesNotExistException.php | 1 - src/Illuminate/Database/Schema/Blueprint.php | 1 - src/Illuminate/Database/Schema/BlueprintState.php | 1 - src/Illuminate/Database/Schema/Builder.php | 1 - src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php | 1 - src/Illuminate/Database/Schema/SchemaState.php | 1 - src/Illuminate/Encryption/MissingAppKeyException.php | 1 - src/Illuminate/Events/CallQueuedListener.php | 1 - src/Illuminate/Events/Dispatcher.php | 1 - src/Illuminate/Events/NullDispatcher.php | 1 - src/Illuminate/Events/QueuedClosure.php | 1 - src/Illuminate/Filesystem/AwsS3V3Adapter.php | 1 - src/Illuminate/Filesystem/FilesystemAdapter.php | 1 - src/Illuminate/Filesystem/FilesystemManager.php | 1 - src/Illuminate/Filesystem/LockableFile.php | 1 - src/Illuminate/Foundation/AliasLoader.php | 1 - src/Illuminate/Foundation/Application.php | 1 - src/Illuminate/Foundation/Bus/PendingChain.php | 1 - src/Illuminate/Foundation/Bus/PendingDispatch.php | 1 - src/Illuminate/Foundation/CacheBasedMaintenanceMode.php | 1 - src/Illuminate/Foundation/Configuration/Exceptions.php | 1 - src/Illuminate/Foundation/Console/AboutCommand.php | 1 - src/Illuminate/Foundation/Console/CliDumper.php | 1 - src/Illuminate/Foundation/Console/ClosureCommand.php | 1 - src/Illuminate/Foundation/Console/ConfigCacheCommand.php | 1 - src/Illuminate/Foundation/Console/ConfigClearCommand.php | 1 - src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php | 1 - src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php | 1 - src/Illuminate/Foundation/Console/EventClearCommand.php | 1 - src/Illuminate/Foundation/Console/Kernel.php | 1 - src/Illuminate/Foundation/Console/QueuedCommand.php | 1 - src/Illuminate/Foundation/Console/RouteCacheCommand.php | 1 - src/Illuminate/Foundation/Console/RouteClearCommand.php | 1 - src/Illuminate/Foundation/Console/RouteListCommand.php | 1 - src/Illuminate/Foundation/Console/VendorPublishCommand.php | 1 - src/Illuminate/Foundation/Console/ViewClearCommand.php | 1 - src/Illuminate/Foundation/Events/LocaleUpdated.php | 1 - src/Illuminate/Foundation/Events/PublishingStubs.php | 1 - src/Illuminate/Foundation/Events/VendorTagPublished.php | 1 - src/Illuminate/Foundation/Exceptions/Handler.php | 1 - src/Illuminate/Foundation/Exceptions/Renderer/Exception.php | 1 - src/Illuminate/Foundation/Exceptions/Renderer/Frame.php | 1 - .../Foundation/Exceptions/Renderer/Mappers/BladeMapper.php | 1 - src/Illuminate/Foundation/Exceptions/Renderer/Renderer.php | 1 - src/Illuminate/Foundation/Exceptions/ReportableHandler.php | 1 - src/Illuminate/Foundation/Http/Events/RequestHandled.php | 1 - src/Illuminate/Foundation/Http/HtmlDumper.php | 1 - src/Illuminate/Foundation/Http/Kernel.php | 1 - .../Foundation/Http/Middleware/HandlePrecognitiveRequests.php | 1 - .../Http/Middleware/PreventRequestsDuringMaintenance.php | 1 - src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php | 1 - src/Illuminate/Foundation/PackageManifest.php | 1 - src/Illuminate/Foundation/ProviderRepository.php | 1 - .../Foundation/Testing/DatabaseTransactionsManager.php | 1 - src/Illuminate/Foundation/Testing/Wormhole.php | 1 - src/Illuminate/Hashing/ArgonHasher.php | 1 - src/Illuminate/Hashing/BcryptHasher.php | 1 - src/Illuminate/Http/Client/Events/ConnectionFailed.php | 1 - src/Illuminate/Http/Client/Events/RequestSending.php | 1 - src/Illuminate/Http/Client/Events/ResponseReceived.php | 1 - src/Illuminate/Http/Client/Factory.php | 1 - src/Illuminate/Http/Client/PendingRequest.php | 1 - src/Illuminate/Http/Client/Pool.php | 1 - src/Illuminate/Http/Client/Request.php | 1 - src/Illuminate/Http/Client/RequestException.php | 1 - src/Illuminate/Http/Client/Response.php | 1 - src/Illuminate/Http/Client/ResponseSequence.php | 1 - src/Illuminate/Http/Exceptions/HttpResponseException.php | 1 - src/Illuminate/Http/Exceptions/MalformedUrlException.php | 2 -- src/Illuminate/Http/Exceptions/PostTooLargeException.php | 1 - src/Illuminate/Http/Exceptions/ThrottleRequestsException.php | 1 - src/Illuminate/Http/JsonResponse.php | 1 - src/Illuminate/Http/Middleware/HandleCors.php | 1 - src/Illuminate/Http/Middleware/TrustHosts.php | 1 - .../Http/Resources/Json/AnonymousResourceCollection.php | 1 - src/Illuminate/Http/Resources/Json/JsonResource.php | 1 - src/Illuminate/Http/Resources/Json/ResourceCollection.php | 1 - src/Illuminate/Http/Resources/Json/ResourceResponse.php | 1 - src/Illuminate/Http/Resources/MergeValue.php | 1 - src/Illuminate/Http/StreamedEvent.php | 2 -- src/Illuminate/Http/Testing/File.php | 1 - src/Illuminate/Log/Events/MessageLogged.php | 1 - src/Illuminate/Log/LogManager.php | 1 - src/Illuminate/Log/Logger.php | 1 - src/Illuminate/Mail/Attachment.php | 1 - src/Illuminate/Mail/Events/MessageSending.php | 1 - src/Illuminate/Mail/Events/MessageSent.php | 1 - src/Illuminate/Mail/MailManager.php | 1 - src/Illuminate/Mail/Mailables/Address.php | 1 - src/Illuminate/Mail/Mailer.php | 1 - src/Illuminate/Mail/Markdown.php | 1 - src/Illuminate/Mail/Message.php | 1 - src/Illuminate/Mail/PendingMail.php | 1 - src/Illuminate/Mail/SendQueuedMailable.php | 1 - src/Illuminate/Mail/SentMessage.php | 1 - src/Illuminate/Mail/TextMessage.php | 1 - src/Illuminate/Mail/Transport/ArrayTransport.php | 2 -- src/Illuminate/Mail/Transport/LogTransport.php | 1 - src/Illuminate/Mail/Transport/SesTransport.php | 1 - src/Illuminate/Mail/Transport/SesV2Transport.php | 1 - src/Illuminate/Notifications/Action.php | 1 - src/Illuminate/Notifications/Channels/BroadcastChannel.php | 1 - src/Illuminate/Notifications/Channels/MailChannel.php | 1 - .../Notifications/Events/BroadcastNotificationCreated.php | 1 - src/Illuminate/Notifications/Events/NotificationFailed.php | 1 - src/Illuminate/Notifications/Events/NotificationSending.php | 1 - src/Illuminate/Notifications/Events/NotificationSent.php | 1 - src/Illuminate/Notifications/Messages/BroadcastMessage.php | 1 - src/Illuminate/Notifications/Messages/DatabaseMessage.php | 1 - src/Illuminate/Notifications/NotificationSender.php | 1 - src/Illuminate/Notifications/SendQueuedNotifications.php | 1 - src/Illuminate/Pagination/CursorPaginator.php | 1 - src/Illuminate/Pagination/LengthAwarePaginator.php | 1 - src/Illuminate/Pagination/Paginator.php | 1 - src/Illuminate/Pagination/UrlWindow.php | 1 - src/Illuminate/Pipeline/Hub.php | 1 - src/Illuminate/Pipeline/Pipeline.php | 1 - src/Illuminate/Process/Exceptions/ProcessFailedException.php | 1 - src/Illuminate/Process/Exceptions/ProcessTimedOutException.php | 1 - src/Illuminate/Process/FakeInvokedProcess.php | 1 - src/Illuminate/Process/FakeProcessResult.php | 1 - src/Illuminate/Process/FakeProcessSequence.php | 1 - src/Illuminate/Process/InvokedProcess.php | 1 - src/Illuminate/Process/InvokedProcessPool.php | 1 - src/Illuminate/Process/PendingProcess.php | 1 - src/Illuminate/Process/Pipe.php | 1 - src/Illuminate/Process/Pool.php | 1 - src/Illuminate/Process/ProcessPoolResults.php | 1 - src/Illuminate/Process/ProcessResult.php | 1 - src/Illuminate/Queue/BeanstalkdQueue.php | 1 - src/Illuminate/Queue/CallQueuedClosure.php | 1 - src/Illuminate/Queue/CallQueuedHandler.php | 1 - src/Illuminate/Queue/Capsule/Manager.php | 1 - src/Illuminate/Queue/Connectors/DatabaseConnector.php | 1 - src/Illuminate/Queue/Connectors/RedisConnector.php | 1 - src/Illuminate/Queue/Console/ListenCommand.php | 1 - src/Illuminate/Queue/Console/MonitorCommand.php | 1 - src/Illuminate/Queue/Console/RestartCommand.php | 1 - src/Illuminate/Queue/Console/WorkCommand.php | 1 - src/Illuminate/Queue/DatabaseQueue.php | 1 - src/Illuminate/Queue/Events/JobAttempted.php | 1 - src/Illuminate/Queue/Events/JobExceptionOccurred.php | 1 - src/Illuminate/Queue/Events/JobFailed.php | 1 - src/Illuminate/Queue/Events/JobPopped.php | 1 - src/Illuminate/Queue/Events/JobPopping.php | 1 - src/Illuminate/Queue/Events/JobProcessed.php | 1 - src/Illuminate/Queue/Events/JobProcessing.php | 1 - src/Illuminate/Queue/Events/JobQueued.php | 1 - src/Illuminate/Queue/Events/JobQueueing.php | 1 - src/Illuminate/Queue/Events/JobReleasedAfterException.php | 1 - src/Illuminate/Queue/Events/JobRetryRequested.php | 1 - src/Illuminate/Queue/Events/JobTimedOut.php | 1 - src/Illuminate/Queue/Events/Looping.php | 1 - src/Illuminate/Queue/Events/QueueBusy.php | 1 - src/Illuminate/Queue/Events/WorkerStopping.php | 1 - src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php | 1 - src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php | 1 - src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php | 1 - src/Illuminate/Queue/Failed/FileFailedJobProvider.php | 1 - src/Illuminate/Queue/InvalidPayloadException.php | 1 - src/Illuminate/Queue/Jobs/BeanstalkdJob.php | 1 - src/Illuminate/Queue/Jobs/DatabaseJob.php | 1 - src/Illuminate/Queue/Jobs/DatabaseJobRecord.php | 1 - src/Illuminate/Queue/Jobs/RedisJob.php | 1 - src/Illuminate/Queue/Jobs/SqsJob.php | 1 - src/Illuminate/Queue/Jobs/SyncJob.php | 1 - src/Illuminate/Queue/Listener.php | 1 - src/Illuminate/Queue/ListenerOptions.php | 1 - src/Illuminate/Queue/Middleware/RateLimited.php | 1 - src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php | 1 - src/Illuminate/Queue/Middleware/ThrottlesExceptions.php | 1 - src/Illuminate/Queue/Middleware/WithoutOverlapping.php | 1 - src/Illuminate/Queue/QueueManager.php | 1 - src/Illuminate/Queue/RedisQueue.php | 1 - src/Illuminate/Queue/SqsQueue.php | 1 - src/Illuminate/Queue/SyncQueue.php | 1 - src/Illuminate/Queue/Worker.php | 1 - src/Illuminate/Queue/WorkerOptions.php | 1 - src/Illuminate/Redis/Connections/PhpRedisConnection.php | 1 - src/Illuminate/Redis/Connections/PredisConnection.php | 1 - src/Illuminate/Redis/Events/CommandExecuted.php | 1 - src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php | 1 - src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php | 1 - src/Illuminate/Redis/Limiters/DurationLimiter.php | 1 - src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php | 1 - src/Illuminate/Redis/RedisManager.php | 1 - src/Illuminate/Routing/CallableDispatcher.php | 1 - src/Illuminate/Routing/CompiledRouteCollection.php | 1 - src/Illuminate/Routing/ControllerDispatcher.php | 1 - src/Illuminate/Routing/ControllerMiddlewareOptions.php | 1 - src/Illuminate/Routing/Controllers/Middleware.php | 1 - src/Illuminate/Routing/Events/PreparingResponse.php | 1 - src/Illuminate/Routing/Events/ResponsePrepared.php | 1 - src/Illuminate/Routing/Events/RouteMatched.php | 1 - src/Illuminate/Routing/Events/Routing.php | 1 - .../Routing/Exceptions/BackedEnumCaseNotFoundException.php | 1 - src/Illuminate/Routing/Exceptions/InvalidSignatureException.php | 2 -- src/Illuminate/Routing/Exceptions/StreamedResponseException.php | 1 - src/Illuminate/Routing/Middleware/SubstituteBindings.php | 1 - src/Illuminate/Routing/Middleware/ThrottleRequests.php | 1 - src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php | 1 - src/Illuminate/Routing/PendingResourceRegistration.php | 1 - src/Illuminate/Routing/PendingSingletonResourceRegistration.php | 1 - src/Illuminate/Routing/Redirector.php | 1 - src/Illuminate/Routing/ResourceRegistrar.php | 1 - src/Illuminate/Routing/ResponseFactory.php | 1 - src/Illuminate/Routing/Route.php | 1 - src/Illuminate/Routing/RouteFileRegistrar.php | 1 - src/Illuminate/Routing/RouteParameterBinder.php | 1 - src/Illuminate/Routing/RouteRegistrar.php | 1 - src/Illuminate/Routing/RouteUri.php | 1 - src/Illuminate/Routing/RouteUrlGenerator.php | 1 - src/Illuminate/Routing/Router.php | 1 - src/Illuminate/Routing/SortedMiddleware.php | 1 - src/Illuminate/Routing/UrlGenerator.php | 1 - src/Illuminate/Routing/ViewController.php | 1 - src/Illuminate/Session/ArraySessionHandler.php | 1 - src/Illuminate/Session/CacheBasedSessionHandler.php | 1 - src/Illuminate/Session/CookieSessionHandler.php | 1 - src/Illuminate/Session/DatabaseSessionHandler.php | 1 - src/Illuminate/Session/EncryptedStore.php | 1 - src/Illuminate/Session/FileSessionHandler.php | 1 - src/Illuminate/Session/Middleware/AuthenticateSession.php | 1 - src/Illuminate/Session/Middleware/StartSession.php | 1 - src/Illuminate/Session/Store.php | 1 - src/Illuminate/Session/SymfonySessionDecorator.php | 1 - src/Illuminate/Support/Composer.php | 1 - src/Illuminate/Support/DefaultProviders.php | 2 -- src/Illuminate/Support/Defer/DeferredCallback.php | 1 - src/Illuminate/Support/Fluent.php | 1 - src/Illuminate/Support/HigherOrderTapProxy.php | 1 - src/Illuminate/Support/HtmlString.php | 1 - src/Illuminate/Support/Lottery.php | 1 - src/Illuminate/Support/Manager.php | 1 - src/Illuminate/Support/MessageBag.php | 1 - src/Illuminate/Support/MultipleInstanceManager.php | 1 - src/Illuminate/Support/Once.php | 1 - src/Illuminate/Support/Onceable.php | 1 - src/Illuminate/Support/Optional.php | 1 - src/Illuminate/Support/ServiceProvider.php | 1 - src/Illuminate/Support/Sleep.php | 1 - src/Illuminate/Support/Stringable.php | 1 - src/Illuminate/Support/Testing/Fakes/BatchFake.php | 1 - src/Illuminate/Support/Testing/Fakes/BusFake.php | 1 - src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php | 1 - src/Illuminate/Support/Testing/Fakes/EventFake.php | 1 - src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php | 1 - src/Illuminate/Support/Testing/Fakes/MailFake.php | 1 - src/Illuminate/Support/Testing/Fakes/PendingBatchFake.php | 1 - src/Illuminate/Support/Testing/Fakes/PendingChainFake.php | 1 - src/Illuminate/Support/Testing/Fakes/PendingMailFake.php | 1 - src/Illuminate/Support/Testing/Fakes/QueueFake.php | 1 - src/Illuminate/Support/ValidatedInput.php | 1 - src/Illuminate/Testing/AssertableJsonString.php | 1 - src/Illuminate/Testing/Concerns/RunsInParallel.php | 1 - src/Illuminate/Testing/Constraints/ArraySubset.php | 1 - src/Illuminate/Testing/Constraints/CountInDatabase.php | 1 - src/Illuminate/Testing/Constraints/HasInDatabase.php | 1 - src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php | 1 - src/Illuminate/Testing/Constraints/SeeInOrder.php | 1 - src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php | 1 - src/Illuminate/Testing/Fluent/AssertableJson.php | 1 - src/Illuminate/Testing/ParallelConsoleOutput.php | 1 - src/Illuminate/Testing/ParallelTesting.php | 1 - src/Illuminate/Testing/PendingCommand.php | 1 - src/Illuminate/Testing/TestComponent.php | 1 - src/Illuminate/Testing/TestResponse.php | 1 - src/Illuminate/Testing/TestView.php | 1 - src/Illuminate/Translation/FileLoader.php | 1 - src/Illuminate/Translation/Translator.php | 1 - src/Illuminate/Validation/ClosureValidationRule.php | 1 - src/Illuminate/Validation/Concerns/FilterEmailValidation.php | 1 - src/Illuminate/Validation/ConditionalRules.php | 1 - src/Illuminate/Validation/DatabasePresenceVerifier.php | 1 - src/Illuminate/Validation/Factory.php | 1 - src/Illuminate/Validation/InvokableValidationRule.php | 1 - src/Illuminate/Validation/NestedRules.php | 1 - src/Illuminate/Validation/NotPwnedVerifier.php | 1 - src/Illuminate/Validation/Rules/ArrayRule.php | 1 - src/Illuminate/Validation/Rules/DatabaseRule.php | 1 - src/Illuminate/Validation/Rules/Dimensions.php | 1 - src/Illuminate/Validation/Rules/Enum.php | 1 - src/Illuminate/Validation/Rules/ImageFile.php | 1 - src/Illuminate/Validation/Rules/In.php | 1 - src/Illuminate/Validation/Rules/NotIn.php | 1 - src/Illuminate/Validation/Rules/Password.php | 1 - src/Illuminate/Validation/Rules/RequiredIf.php | 1 - src/Illuminate/Validation/ValidationException.php | 1 - src/Illuminate/Validation/ValidationRuleParser.php | 1 - src/Illuminate/Validation/Validator.php | 1 - src/Illuminate/View/AnonymousComponent.php | 1 - src/Illuminate/View/AppendableAttributeValue.php | 1 - src/Illuminate/View/Compilers/ComponentTagCompiler.php | 1 - src/Illuminate/View/ComponentAttributeBag.php | 1 - src/Illuminate/View/ComponentSlot.php | 1 - src/Illuminate/View/DynamicComponent.php | 1 - src/Illuminate/View/Engines/CompilerEngine.php | 1 - src/Illuminate/View/Engines/FileEngine.php | 1 - src/Illuminate/View/Engines/PhpEngine.php | 1 - src/Illuminate/View/Factory.php | 1 - src/Illuminate/View/FileViewFinder.php | 1 - src/Illuminate/View/InvokableComponentVariable.php | 1 - src/Illuminate/View/Middleware/ShareErrorsFromSession.php | 1 - src/Illuminate/View/View.php | 1 - 489 files changed, 500 deletions(-) diff --git a/src/Illuminate/Auth/Access/AuthorizationException.php b/src/Illuminate/Auth/Access/AuthorizationException.php index 1454bde2a01d..1dd157e34e94 100644 --- a/src/Illuminate/Auth/Access/AuthorizationException.php +++ b/src/Illuminate/Auth/Access/AuthorizationException.php @@ -27,7 +27,6 @@ class AuthorizationException extends Exception * @param string|null $message * @param mixed $code * @param \Throwable|null $previous - * @return void */ public function __construct($message = null, $code = null, ?Throwable $previous = null) { diff --git a/src/Illuminate/Auth/Access/Events/GateEvaluated.php b/src/Illuminate/Auth/Access/Events/GateEvaluated.php index f77a9c84c51b..2e75512d5870 100644 --- a/src/Illuminate/Auth/Access/Events/GateEvaluated.php +++ b/src/Illuminate/Auth/Access/Events/GateEvaluated.php @@ -39,7 +39,6 @@ class GateEvaluated * @param string $ability * @param bool|null $result * @param array $arguments - * @return void */ public function __construct($user, $ability, $result, $arguments) { diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 1d0ab89597b4..47dea0ddd26e 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -94,7 +94,6 @@ class Gate implements GateContract * @param array $beforeCallbacks * @param array $afterCallbacks * @param callable|null $guessPolicyNamesUsingCallback - * @return void */ public function __construct( Container $container, diff --git a/src/Illuminate/Auth/Access/Response.php b/src/Illuminate/Auth/Access/Response.php index 6461d0fce128..d35b78ad09ff 100644 --- a/src/Illuminate/Auth/Access/Response.php +++ b/src/Illuminate/Auth/Access/Response.php @@ -41,7 +41,6 @@ class Response implements Arrayable, Stringable * @param bool $allowed * @param string|null $message * @param mixed $code - * @return void */ public function __construct($allowed, $message = '', $code = null) { diff --git a/src/Illuminate/Auth/AuthManager.php b/src/Illuminate/Auth/AuthManager.php index a4bc8e8a4b3f..70723558886e 100755 --- a/src/Illuminate/Auth/AuthManager.php +++ b/src/Illuminate/Auth/AuthManager.php @@ -48,7 +48,6 @@ class AuthManager implements FactoryContract * Create a new Auth manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Auth/AuthenticationException.php b/src/Illuminate/Auth/AuthenticationException.php index c4f835c5e6c0..e3da045bc9a0 100644 --- a/src/Illuminate/Auth/AuthenticationException.php +++ b/src/Illuminate/Auth/AuthenticationException.php @@ -34,7 +34,6 @@ class AuthenticationException extends Exception * @param string $message * @param array $guards * @param string|null $redirectTo - * @return void */ public function __construct($message = 'Unauthenticated.', array $guards = [], $redirectTo = null) { diff --git a/src/Illuminate/Auth/DatabaseUserProvider.php b/src/Illuminate/Auth/DatabaseUserProvider.php index a1332d596a9b..24fae41d4d5f 100755 --- a/src/Illuminate/Auth/DatabaseUserProvider.php +++ b/src/Illuminate/Auth/DatabaseUserProvider.php @@ -38,7 +38,6 @@ class DatabaseUserProvider implements UserProvider * @param \Illuminate\Database\ConnectionInterface $connection * @param \Illuminate\Contracts\Hashing\Hasher $hasher * @param string $table - * @return void */ public function __construct(ConnectionInterface $connection, HasherContract $hasher, $table) { diff --git a/src/Illuminate/Auth/EloquentUserProvider.php b/src/Illuminate/Auth/EloquentUserProvider.php index 8a4a21c788ab..e91f1057b553 100755 --- a/src/Illuminate/Auth/EloquentUserProvider.php +++ b/src/Illuminate/Auth/EloquentUserProvider.php @@ -36,7 +36,6 @@ class EloquentUserProvider implements UserProvider * * @param \Illuminate\Contracts\Hashing\Hasher $hasher * @param string $model - * @return void */ public function __construct(HasherContract $hasher, $model) { diff --git a/src/Illuminate/Auth/Events/Attempting.php b/src/Illuminate/Auth/Events/Attempting.php index ac700c9015e5..567d7e6e9f66 100644 --- a/src/Illuminate/Auth/Events/Attempting.php +++ b/src/Illuminate/Auth/Events/Attempting.php @@ -10,7 +10,6 @@ class Attempting * @param string $guard The authentication guard name. * @param array $credentials The credentials for the user. * @param bool $remember Indicates if the user should be "remembered". - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/Authenticated.php b/src/Illuminate/Auth/Events/Authenticated.php index c0b0db6cba32..33c537a6128c 100644 --- a/src/Illuminate/Auth/Events/Authenticated.php +++ b/src/Illuminate/Auth/Events/Authenticated.php @@ -13,7 +13,6 @@ class Authenticated * * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/CurrentDeviceLogout.php b/src/Illuminate/Auth/Events/CurrentDeviceLogout.php index 8f2e694ffbd5..d7614a1e5afe 100644 --- a/src/Illuminate/Auth/Events/CurrentDeviceLogout.php +++ b/src/Illuminate/Auth/Events/CurrentDeviceLogout.php @@ -13,7 +13,6 @@ class CurrentDeviceLogout * * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/Failed.php b/src/Illuminate/Auth/Events/Failed.php index 32a5610053b7..4b8800762f50 100644 --- a/src/Illuminate/Auth/Events/Failed.php +++ b/src/Illuminate/Auth/Events/Failed.php @@ -10,7 +10,6 @@ class Failed * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable|null $user The user the attempter was trying to authenticate as. * @param array $credentials The credentials provided by the attempter. - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/Lockout.php b/src/Illuminate/Auth/Events/Lockout.php index 347943feb181..d01c274d4de2 100644 --- a/src/Illuminate/Auth/Events/Lockout.php +++ b/src/Illuminate/Auth/Events/Lockout.php @@ -17,7 +17,6 @@ class Lockout * Create a new event instance. * * @param \Illuminate\Http\Request $request - * @return void */ public function __construct(Request $request) { diff --git a/src/Illuminate/Auth/Events/Login.php b/src/Illuminate/Auth/Events/Login.php index c3e2e69e9832..a403e1efad32 100644 --- a/src/Illuminate/Auth/Events/Login.php +++ b/src/Illuminate/Auth/Events/Login.php @@ -14,7 +14,6 @@ class Login * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. * @param bool $remember Indicates if the user should be "remembered". - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/Logout.php b/src/Illuminate/Auth/Events/Logout.php index e13693be67e9..3b7787ed38d5 100644 --- a/src/Illuminate/Auth/Events/Logout.php +++ b/src/Illuminate/Auth/Events/Logout.php @@ -13,7 +13,6 @@ class Logout * * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/OtherDeviceLogout.php b/src/Illuminate/Auth/Events/OtherDeviceLogout.php index 5687086910ba..fe3bd31f50a3 100644 --- a/src/Illuminate/Auth/Events/OtherDeviceLogout.php +++ b/src/Illuminate/Auth/Events/OtherDeviceLogout.php @@ -13,7 +13,6 @@ class OtherDeviceLogout * * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable $user \Illuminate\Contracts\Auth\Authenticatable - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/PasswordReset.php b/src/Illuminate/Auth/Events/PasswordReset.php index cb09d8a92498..813a6e95f4a1 100644 --- a/src/Illuminate/Auth/Events/PasswordReset.php +++ b/src/Illuminate/Auth/Events/PasswordReset.php @@ -12,7 +12,6 @@ class PasswordReset * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user The user. - * @return void */ public function __construct( public $user, diff --git a/src/Illuminate/Auth/Events/PasswordResetLinkSent.php b/src/Illuminate/Auth/Events/PasswordResetLinkSent.php index 2540a2e6ee46..4153ba654b91 100644 --- a/src/Illuminate/Auth/Events/PasswordResetLinkSent.php +++ b/src/Illuminate/Auth/Events/PasswordResetLinkSent.php @@ -12,7 +12,6 @@ class PasswordResetLinkSent * Create a new event instance. * * @param \Illuminate\Contracts\Auth\CanResetPassword $user The user instance. - * @return void */ public function __construct( public $user, diff --git a/src/Illuminate/Auth/Events/Registered.php b/src/Illuminate/Auth/Events/Registered.php index 646cdaf95051..7bd312088f4c 100644 --- a/src/Illuminate/Auth/Events/Registered.php +++ b/src/Illuminate/Auth/Events/Registered.php @@ -12,7 +12,6 @@ class Registered * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. - * @return void */ public function __construct( public $user, diff --git a/src/Illuminate/Auth/Events/Validated.php b/src/Illuminate/Auth/Events/Validated.php index 5cd01a533363..034016161182 100644 --- a/src/Illuminate/Auth/Events/Validated.php +++ b/src/Illuminate/Auth/Events/Validated.php @@ -13,7 +13,6 @@ class Validated * * @param string $guard The authentication guard name. * @param \Illuminate\Contracts\Auth\Authenticatable $user The user retrieved and validated from the User Provider. - * @return void */ public function __construct( public $guard, diff --git a/src/Illuminate/Auth/Events/Verified.php b/src/Illuminate/Auth/Events/Verified.php index 03c2aff12e81..609fc73cc5ce 100644 --- a/src/Illuminate/Auth/Events/Verified.php +++ b/src/Illuminate/Auth/Events/Verified.php @@ -12,7 +12,6 @@ class Verified * Create a new event instance. * * @param \Illuminate\Contracts\Auth\MustVerifyEmail $user The verified user. - * @return void */ public function __construct( public $user, diff --git a/src/Illuminate/Auth/GenericUser.php b/src/Illuminate/Auth/GenericUser.php index d015e5b4b617..99b199a56b8e 100755 --- a/src/Illuminate/Auth/GenericUser.php +++ b/src/Illuminate/Auth/GenericUser.php @@ -17,7 +17,6 @@ class GenericUser implements UserContract * Create a new generic User object. * * @param array $attributes - * @return void */ public function __construct(array $attributes) { diff --git a/src/Illuminate/Auth/Middleware/Authenticate.php b/src/Illuminate/Auth/Middleware/Authenticate.php index 81d4ee455ae3..30cf903610bc 100644 --- a/src/Illuminate/Auth/Middleware/Authenticate.php +++ b/src/Illuminate/Auth/Middleware/Authenticate.php @@ -28,7 +28,6 @@ class Authenticate implements AuthenticatesRequests * Create a new middleware instance. * * @param \Illuminate\Contracts\Auth\Factory $auth - * @return void */ public function __construct(Auth $auth) { diff --git a/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php b/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php index 0b4510c0fb66..00230191fc49 100644 --- a/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php +++ b/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php @@ -18,7 +18,6 @@ class AuthenticateWithBasicAuth * Create a new middleware instance. * * @param \Illuminate\Contracts\Auth\Factory $auth - * @return void */ public function __construct(AuthFactory $auth) { diff --git a/src/Illuminate/Auth/Middleware/Authorize.php b/src/Illuminate/Auth/Middleware/Authorize.php index e2ccbaf02ea3..a5a11ec796d5 100644 --- a/src/Illuminate/Auth/Middleware/Authorize.php +++ b/src/Illuminate/Auth/Middleware/Authorize.php @@ -22,7 +22,6 @@ class Authorize * Create a new middleware instance. * * @param \Illuminate\Contracts\Auth\Access\Gate $gate - * @return void */ public function __construct(Gate $gate) { diff --git a/src/Illuminate/Auth/Middleware/RequirePassword.php b/src/Illuminate/Auth/Middleware/RequirePassword.php index fa62b8420c1a..8ac6f8af66d4 100644 --- a/src/Illuminate/Auth/Middleware/RequirePassword.php +++ b/src/Illuminate/Auth/Middleware/RequirePassword.php @@ -35,7 +35,6 @@ class RequirePassword * @param \Illuminate\Contracts\Routing\ResponseFactory $responseFactory * @param \Illuminate\Contracts\Routing\UrlGenerator $urlGenerator * @param int|null $passwordTimeout - * @return void */ public function __construct(ResponseFactory $responseFactory, UrlGenerator $urlGenerator, $passwordTimeout = null) { diff --git a/src/Illuminate/Auth/Notifications/ResetPassword.php b/src/Illuminate/Auth/Notifications/ResetPassword.php index d31ae210c943..3689cf027dac 100644 --- a/src/Illuminate/Auth/Notifications/ResetPassword.php +++ b/src/Illuminate/Auth/Notifications/ResetPassword.php @@ -33,7 +33,6 @@ class ResetPassword extends Notification * Create a notification instance. * * @param string $token - * @return void */ public function __construct(#[\SensitiveParameter] $token) { diff --git a/src/Illuminate/Auth/Passwords/PasswordBroker.php b/src/Illuminate/Auth/Passwords/PasswordBroker.php index 29ef2f9cbce6..91b3d29fab7c 100755 --- a/src/Illuminate/Auth/Passwords/PasswordBroker.php +++ b/src/Illuminate/Auth/Passwords/PasswordBroker.php @@ -40,7 +40,6 @@ class PasswordBroker implements PasswordBrokerContract * @param \Illuminate\Auth\Passwords\TokenRepositoryInterface $tokens * @param \Illuminate\Contracts\Auth\UserProvider $users * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher - * @return void */ public function __construct(#[\SensitiveParameter] TokenRepositoryInterface $tokens, UserProvider $users, ?Dispatcher $dispatcher = null) { diff --git a/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php b/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php index ea2020022971..516638b17f5f 100644 --- a/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php +++ b/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php @@ -28,7 +28,6 @@ class PasswordBrokerManager implements FactoryContract * Create a new PasswordBroker manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Auth/Recaller.php b/src/Illuminate/Auth/Recaller.php index 4d96c82bc97a..222a98d655db 100644 --- a/src/Illuminate/Auth/Recaller.php +++ b/src/Illuminate/Auth/Recaller.php @@ -15,7 +15,6 @@ class Recaller * Create a new recaller instance. * * @param string $recaller - * @return void */ public function __construct($recaller) { diff --git a/src/Illuminate/Auth/RequestGuard.php b/src/Illuminate/Auth/RequestGuard.php index 9b8fd10a36b6..e9f4bc74a3c8 100644 --- a/src/Illuminate/Auth/RequestGuard.php +++ b/src/Illuminate/Auth/RequestGuard.php @@ -31,7 +31,6 @@ class RequestGuard implements Guard * @param callable $callback * @param \Illuminate\Http\Request $request * @param \Illuminate\Contracts\Auth\UserProvider|null $provider - * @return void */ public function __construct(callable $callback, Request $request, ?UserProvider $provider = null) { diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 928c970643f7..13bd15f46c5a 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -126,7 +126,6 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth * @param \Symfony\Component\HttpFoundation\Request|null $request * @param \Illuminate\Support\Timebox|null $timebox * @param bool $rehashOnLogin - * @return void */ public function __construct( $name, diff --git a/src/Illuminate/Auth/TokenGuard.php b/src/Illuminate/Auth/TokenGuard.php index 1e002a0a0845..b6e7f187ce04 100644 --- a/src/Illuminate/Auth/TokenGuard.php +++ b/src/Illuminate/Auth/TokenGuard.php @@ -47,7 +47,6 @@ class TokenGuard implements Guard * @param string $inputKey * @param string $storageKey * @param bool $hash - * @return void */ public function __construct( UserProvider $provider, diff --git a/src/Illuminate/Broadcasting/AnonymousEvent.php b/src/Illuminate/Broadcasting/AnonymousEvent.php index 51e47f158531..c53e2f1c2c2e 100644 --- a/src/Illuminate/Broadcasting/AnonymousEvent.php +++ b/src/Illuminate/Broadcasting/AnonymousEvent.php @@ -39,8 +39,6 @@ class AnonymousEvent implements ShouldBroadcast /** * Create a new anonymous broadcastable event instance. - * - * @return void */ public function __construct(protected Channel|array|string $channels) { diff --git a/src/Illuminate/Broadcasting/BroadcastEvent.php b/src/Illuminate/Broadcasting/BroadcastEvent.php index a13b7ff42128..c4da0faab220 100644 --- a/src/Illuminate/Broadcasting/BroadcastEvent.php +++ b/src/Illuminate/Broadcasting/BroadcastEvent.php @@ -54,7 +54,6 @@ class BroadcastEvent implements ShouldQueue * Create a new job handler instance. * * @param mixed $event - * @return void */ public function __construct($event) { diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 4df00526aa3b..790e096bbaa2 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -51,7 +51,6 @@ class BroadcastManager implements FactoryContract * Create a new manager instance. * * @param \Illuminate\Contracts\Container\Container $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php index e2b70cead0dd..5fc73a2d9902 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php @@ -26,7 +26,6 @@ class AblyBroadcaster extends Broadcaster * Create a new broadcaster instance. * * @param \Ably\AblyRest $ably - * @return void */ public function __construct(AblyRest $ably) { diff --git a/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php index 50877dc976fe..5479361559a5 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php @@ -17,7 +17,6 @@ class LogBroadcaster extends Broadcaster * Create a new broadcaster instance. * * @param \Psr\Log\LoggerInterface $logger - * @return void */ public function __construct(LoggerInterface $logger) { diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index cc3b80accb31..e68a73c1f3de 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -24,7 +24,6 @@ class PusherBroadcaster extends Broadcaster * Create a new broadcaster instance. * * @param \Pusher\Pusher $pusher - * @return void */ public function __construct(Pusher $pusher) { diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index d7ff8f5de76e..9cb81c85af1d 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -40,7 +40,6 @@ class RedisBroadcaster extends Broadcaster * @param \Illuminate\Contracts\Redis\Factory $redis * @param string|null $connection * @param string $prefix - * @return void */ public function __construct(Redis $redis, $connection = null, $prefix = '') { diff --git a/src/Illuminate/Broadcasting/Channel.php b/src/Illuminate/Broadcasting/Channel.php index 53094227f559..ebbfa9b24564 100644 --- a/src/Illuminate/Broadcasting/Channel.php +++ b/src/Illuminate/Broadcasting/Channel.php @@ -18,7 +18,6 @@ class Channel implements Stringable * Create a new channel instance. * * @param \Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $name - * @return void */ public function __construct($name) { diff --git a/src/Illuminate/Broadcasting/EncryptedPrivateChannel.php b/src/Illuminate/Broadcasting/EncryptedPrivateChannel.php index 76977c158e49..e6a9597167d5 100644 --- a/src/Illuminate/Broadcasting/EncryptedPrivateChannel.php +++ b/src/Illuminate/Broadcasting/EncryptedPrivateChannel.php @@ -8,7 +8,6 @@ class EncryptedPrivateChannel extends Channel * Create a new channel instance. * * @param string $name - * @return void */ public function __construct($name) { diff --git a/src/Illuminate/Broadcasting/PendingBroadcast.php b/src/Illuminate/Broadcasting/PendingBroadcast.php index 191b905f5938..0d1298e07111 100644 --- a/src/Illuminate/Broadcasting/PendingBroadcast.php +++ b/src/Illuminate/Broadcasting/PendingBroadcast.php @@ -25,7 +25,6 @@ class PendingBroadcast * * @param \Illuminate\Contracts\Events\Dispatcher $events * @param mixed $event - * @return void */ public function __construct(Dispatcher $events, $event) { diff --git a/src/Illuminate/Broadcasting/PresenceChannel.php b/src/Illuminate/Broadcasting/PresenceChannel.php index 22de12d37f16..50c1ced8f8ae 100644 --- a/src/Illuminate/Broadcasting/PresenceChannel.php +++ b/src/Illuminate/Broadcasting/PresenceChannel.php @@ -8,7 +8,6 @@ class PresenceChannel extends Channel * Create a new channel instance. * * @param string $name - * @return void */ public function __construct($name) { diff --git a/src/Illuminate/Broadcasting/PrivateChannel.php b/src/Illuminate/Broadcasting/PrivateChannel.php index e53094b25c3f..c02e6ac9e5b5 100644 --- a/src/Illuminate/Broadcasting/PrivateChannel.php +++ b/src/Illuminate/Broadcasting/PrivateChannel.php @@ -10,7 +10,6 @@ class PrivateChannel extends Channel * Create a new channel instance. * * @param \Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $name - * @return void */ public function __construct($name) { diff --git a/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php b/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php index 098d4eaf5359..b99af6f843d5 100644 --- a/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php +++ b/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php @@ -26,7 +26,6 @@ class UniqueBroadcastEvent extends BroadcastEvent implements ShouldBeUnique * Create a new event instance. * * @param mixed $event - * @return void */ public function __construct($event) { diff --git a/src/Illuminate/Bus/Batch.php b/src/Illuminate/Bus/Batch.php index 6b11dd1ff60d..717d1c4ab11d 100644 --- a/src/Illuminate/Bus/Batch.php +++ b/src/Illuminate/Bus/Batch.php @@ -113,7 +113,6 @@ class Batch implements Arrayable, JsonSerializable * @param \Carbon\CarbonImmutable $createdAt * @param \Carbon\CarbonImmutable|null $cancelledAt * @param \Carbon\CarbonImmutable|null $finishedAt - * @return void */ public function __construct( QueueFactory $queue, diff --git a/src/Illuminate/Bus/BatchFactory.php b/src/Illuminate/Bus/BatchFactory.php index 2c3a4e96ce57..9a3ed600aff6 100644 --- a/src/Illuminate/Bus/BatchFactory.php +++ b/src/Illuminate/Bus/BatchFactory.php @@ -18,7 +18,6 @@ class BatchFactory * Create a new batch factory instance. * * @param \Illuminate\Contracts\Queue\Factory $queue - * @return void */ public function __construct(QueueFactory $queue) { diff --git a/src/Illuminate/Bus/ChainedBatch.php b/src/Illuminate/Bus/ChainedBatch.php index 4a02601a2375..d88aa0e7377e 100644 --- a/src/Illuminate/Bus/ChainedBatch.php +++ b/src/Illuminate/Bus/ChainedBatch.php @@ -39,7 +39,6 @@ class ChainedBatch implements ShouldQueue * Create a new chained batch instance. * * @param \Illuminate\Bus\PendingBatch $batch - * @return void */ public function __construct(PendingBatch $batch) { diff --git a/src/Illuminate/Bus/Dispatcher.php b/src/Illuminate/Bus/Dispatcher.php index d239646190ef..32f917d796a6 100644 --- a/src/Illuminate/Bus/Dispatcher.php +++ b/src/Illuminate/Bus/Dispatcher.php @@ -56,7 +56,6 @@ class Dispatcher implements QueueingDispatcher * * @param \Illuminate\Contracts\Container\Container $container * @param \Closure|null $queueResolver - * @return void */ public function __construct(Container $container, ?Closure $queueResolver = null) { diff --git a/src/Illuminate/Bus/Events/BatchDispatched.php b/src/Illuminate/Bus/Events/BatchDispatched.php index 2f654ad365b5..57acae64cc5c 100644 --- a/src/Illuminate/Bus/Events/BatchDispatched.php +++ b/src/Illuminate/Bus/Events/BatchDispatched.php @@ -10,7 +10,6 @@ class BatchDispatched * Create a new event instance. * * @param \Illuminate\Bus\Batch $batch The batch instance. - * @return void */ public function __construct( public Batch $batch, diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 356d3d9468e2..9538074d7be4 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -59,7 +59,6 @@ class PendingBatch * * @param \Illuminate\Contracts\Container\Container $container * @param \Illuminate\Support\Collection $jobs - * @return void */ public function __construct(Container $container, Collection $jobs) { diff --git a/src/Illuminate/Bus/UniqueLock.php b/src/Illuminate/Bus/UniqueLock.php index 5e207d550941..c1d74c636f1e 100644 --- a/src/Illuminate/Bus/UniqueLock.php +++ b/src/Illuminate/Bus/UniqueLock.php @@ -17,7 +17,6 @@ class UniqueLock * Create a new unique lock manager instance. * * @param \Illuminate\Contracts\Cache\Repository $cache - * @return void */ public function __construct(Cache $cache) { diff --git a/src/Illuminate/Bus/UpdatedBatchJobCounts.php b/src/Illuminate/Bus/UpdatedBatchJobCounts.php index 83d33a44f2f7..f68de3bba614 100644 --- a/src/Illuminate/Bus/UpdatedBatchJobCounts.php +++ b/src/Illuminate/Bus/UpdatedBatchJobCounts.php @@ -23,7 +23,6 @@ class UpdatedBatchJobCounts * * @param int $pendingJobs * @param int $failedJobs - * @return void */ public function __construct(int $pendingJobs = 0, int $failedJobs = 0) { diff --git a/src/Illuminate/Cache/ApcStore.php b/src/Illuminate/Cache/ApcStore.php index 8bba88b50708..89c31a3f7f0c 100755 --- a/src/Illuminate/Cache/ApcStore.php +++ b/src/Illuminate/Cache/ApcStore.php @@ -25,7 +25,6 @@ class ApcStore extends TaggableStore * * @param \Illuminate\Cache\ApcWrapper $apc * @param string $prefix - * @return void */ public function __construct(ApcWrapper $apc, $prefix = '') { diff --git a/src/Illuminate/Cache/ArrayLock.php b/src/Illuminate/Cache/ArrayLock.php index 8e1ebe203eea..2eb5054dd544 100644 --- a/src/Illuminate/Cache/ArrayLock.php +++ b/src/Illuminate/Cache/ArrayLock.php @@ -20,7 +20,6 @@ class ArrayLock extends Lock * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct($store, $name, $seconds, $owner = null) { diff --git a/src/Illuminate/Cache/ArrayStore.php b/src/Illuminate/Cache/ArrayStore.php index 353552777462..112501831822 100644 --- a/src/Illuminate/Cache/ArrayStore.php +++ b/src/Illuminate/Cache/ArrayStore.php @@ -35,7 +35,6 @@ class ArrayStore extends TaggableStore implements LockProvider * Create a new Array store. * * @param bool $serializesValues - * @return void */ public function __construct($serializesValues = false) { diff --git a/src/Illuminate/Cache/CacheLock.php b/src/Illuminate/Cache/CacheLock.php index cb60da867e33..e043b9373b55 100644 --- a/src/Illuminate/Cache/CacheLock.php +++ b/src/Illuminate/Cache/CacheLock.php @@ -18,7 +18,6 @@ class CacheLock extends Lock * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct($store, $name, $seconds, $owner = null) { diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index a17405c2ab42..c4973da748eb 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -41,7 +41,6 @@ class CacheManager implements FactoryContract * Create a new Cache manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index 23870d4db6be..e84cefae8d6c 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -45,7 +45,6 @@ class ClearCommand extends Command * * @param \Illuminate\Cache\CacheManager $cache * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(CacheManager $cache, Filesystem $files) { diff --git a/src/Illuminate/Cache/Console/ForgetCommand.php b/src/Illuminate/Cache/Console/ForgetCommand.php index 7f418afbfaac..bb34e039eb85 100755 --- a/src/Illuminate/Cache/Console/ForgetCommand.php +++ b/src/Illuminate/Cache/Console/ForgetCommand.php @@ -34,7 +34,6 @@ class ForgetCommand extends Command * Create a new cache clear command instance. * * @param \Illuminate\Cache\CacheManager $cache - * @return void */ public function __construct(CacheManager $cache) { diff --git a/src/Illuminate/Cache/DatabaseLock.php b/src/Illuminate/Cache/DatabaseLock.php index 506696fdbd16..8e63374cb988 100644 --- a/src/Illuminate/Cache/DatabaseLock.php +++ b/src/Illuminate/Cache/DatabaseLock.php @@ -44,7 +44,6 @@ class DatabaseLock extends Lock * @param int $seconds * @param string|null $owner * @param array $lottery - * @return void */ public function __construct(Connection $connection, $table, $name, $seconds, $owner = null, $lottery = [2, 100], $defaultTimeoutInSeconds = 86400) { diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index 56564c2988e3..04c52e45922d 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -76,7 +76,6 @@ class DatabaseStore implements LockProvider, Store * @param string $prefix * @param string $lockTable * @param array $lockLottery - * @return void */ public function __construct( ConnectionInterface $connection, diff --git a/src/Illuminate/Cache/DynamoDbLock.php b/src/Illuminate/Cache/DynamoDbLock.php index 284b77a5bf77..b60e382c00aa 100644 --- a/src/Illuminate/Cache/DynamoDbLock.php +++ b/src/Illuminate/Cache/DynamoDbLock.php @@ -18,7 +18,6 @@ class DynamoDbLock extends Lock * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct(DynamoDbStore $dynamo, $name, $seconds, $owner = null) { diff --git a/src/Illuminate/Cache/DynamoDbStore.php b/src/Illuminate/Cache/DynamoDbStore.php index e970d0d85738..1bc7aa879865 100644 --- a/src/Illuminate/Cache/DynamoDbStore.php +++ b/src/Illuminate/Cache/DynamoDbStore.php @@ -67,7 +67,6 @@ class DynamoDbStore implements LockProvider, Store * @param string $valueAttribute * @param string $expirationAttribute * @param string $prefix - * @return void */ public function __construct( DynamoDbClient $dynamo, diff --git a/src/Illuminate/Cache/Events/CacheEvent.php b/src/Illuminate/Cache/Events/CacheEvent.php index b6bc49b15c96..6325a4494d9a 100644 --- a/src/Illuminate/Cache/Events/CacheEvent.php +++ b/src/Illuminate/Cache/Events/CacheEvent.php @@ -31,7 +31,6 @@ abstract class CacheEvent * @param string|null $storeName * @param string $key * @param array $tags - * @return void */ public function __construct($storeName, $key, array $tags = []) { diff --git a/src/Illuminate/Cache/Events/CacheHit.php b/src/Illuminate/Cache/Events/CacheHit.php index 9802980e3cbe..57a5c53472cd 100644 --- a/src/Illuminate/Cache/Events/CacheHit.php +++ b/src/Illuminate/Cache/Events/CacheHit.php @@ -18,7 +18,6 @@ class CacheHit extends CacheEvent * @param string $key * @param mixed $value * @param array $tags - * @return void */ public function __construct($storeName, $key, $value, array $tags = []) { diff --git a/src/Illuminate/Cache/Events/KeyWriteFailed.php b/src/Illuminate/Cache/Events/KeyWriteFailed.php index e74284d512b2..ecefbfe06dd7 100644 --- a/src/Illuminate/Cache/Events/KeyWriteFailed.php +++ b/src/Illuminate/Cache/Events/KeyWriteFailed.php @@ -26,7 +26,6 @@ class KeyWriteFailed extends CacheEvent * @param mixed $value * @param int|null $seconds * @param array $tags - * @return void */ public function __construct($storeName, $key, $value, $seconds = null, $tags = []) { diff --git a/src/Illuminate/Cache/Events/KeyWritten.php b/src/Illuminate/Cache/Events/KeyWritten.php index 49334882cb10..cfb42532c233 100644 --- a/src/Illuminate/Cache/Events/KeyWritten.php +++ b/src/Illuminate/Cache/Events/KeyWritten.php @@ -26,7 +26,6 @@ class KeyWritten extends CacheEvent * @param mixed $value * @param int|null $seconds * @param array $tags - * @return void */ public function __construct($storeName, $key, $value, $seconds = null, $tags = []) { diff --git a/src/Illuminate/Cache/Events/RetrievingManyKeys.php b/src/Illuminate/Cache/Events/RetrievingManyKeys.php index 9647c686aa8b..3722ad352beb 100644 --- a/src/Illuminate/Cache/Events/RetrievingManyKeys.php +++ b/src/Illuminate/Cache/Events/RetrievingManyKeys.php @@ -17,7 +17,6 @@ class RetrievingManyKeys extends CacheEvent * @param string|null $storeName * @param array $keys * @param array $tags - * @return void */ public function __construct($storeName, $keys, array $tags = []) { diff --git a/src/Illuminate/Cache/Events/WritingKey.php b/src/Illuminate/Cache/Events/WritingKey.php index ac874eb13a82..27dc8a87437c 100644 --- a/src/Illuminate/Cache/Events/WritingKey.php +++ b/src/Illuminate/Cache/Events/WritingKey.php @@ -26,7 +26,6 @@ class WritingKey extends CacheEvent * @param mixed $value * @param int|null $seconds * @param array $tags - * @return void */ public function __construct($storeName, $key, $value, $seconds = null, $tags = []) { diff --git a/src/Illuminate/Cache/Events/WritingManyKeys.php b/src/Illuminate/Cache/Events/WritingManyKeys.php index e180e6884d11..a4d077187d3a 100644 --- a/src/Illuminate/Cache/Events/WritingManyKeys.php +++ b/src/Illuminate/Cache/Events/WritingManyKeys.php @@ -33,7 +33,6 @@ class WritingManyKeys extends CacheEvent * @param array $values * @param int|null $seconds * @param array $tags - * @return void */ public function __construct($storeName, $keys, $values, $seconds = null, $tags = []) { diff --git a/src/Illuminate/Cache/FileStore.php b/src/Illuminate/Cache/FileStore.php index 4105582d44c6..d445f5fc7c23 100755 --- a/src/Illuminate/Cache/FileStore.php +++ b/src/Illuminate/Cache/FileStore.php @@ -48,7 +48,6 @@ class FileStore implements Store, LockProvider * @param \Illuminate\Filesystem\Filesystem $files * @param string $directory * @param int|null $filePermission - * @return void */ public function __construct(Filesystem $files, $directory, $filePermission = null) { diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 18cd86a5690e..7913f1628a22 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -46,7 +46,6 @@ abstract class Lock implements LockContract * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct($name, $seconds, $owner = null) { diff --git a/src/Illuminate/Cache/MemcachedLock.php b/src/Illuminate/Cache/MemcachedLock.php index 0078a09e6974..8fdb2fc1427b 100644 --- a/src/Illuminate/Cache/MemcachedLock.php +++ b/src/Illuminate/Cache/MemcachedLock.php @@ -18,7 +18,6 @@ class MemcachedLock extends Lock * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct($memcached, $name, $seconds, $owner = null) { diff --git a/src/Illuminate/Cache/MemcachedStore.php b/src/Illuminate/Cache/MemcachedStore.php index 5197c2df71f5..b05560e1a986 100755 --- a/src/Illuminate/Cache/MemcachedStore.php +++ b/src/Illuminate/Cache/MemcachedStore.php @@ -37,7 +37,6 @@ class MemcachedStore extends TaggableStore implements LockProvider * * @param \Memcached $memcached * @param string $prefix - * @return void */ public function __construct($memcached, $prefix = '') { diff --git a/src/Illuminate/Cache/PhpRedisLock.php b/src/Illuminate/Cache/PhpRedisLock.php index 6cfce7938a37..2cc29710c172 100644 --- a/src/Illuminate/Cache/PhpRedisLock.php +++ b/src/Illuminate/Cache/PhpRedisLock.php @@ -13,7 +13,6 @@ class PhpRedisLock extends RedisLock * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct(PhpRedisConnection $redis, string $name, int $seconds, ?string $owner = null) { diff --git a/src/Illuminate/Cache/RateLimiter.php b/src/Illuminate/Cache/RateLimiter.php index 12f76fee6e2a..c3598e364ebf 100644 --- a/src/Illuminate/Cache/RateLimiter.php +++ b/src/Illuminate/Cache/RateLimiter.php @@ -32,7 +32,6 @@ class RateLimiter * Create a new rate limiter instance. * * @param \Illuminate\Contracts\Cache\Repository $cache - * @return void */ public function __construct(Cache $cache) { diff --git a/src/Illuminate/Cache/RateLimiting/GlobalLimit.php b/src/Illuminate/Cache/RateLimiting/GlobalLimit.php index 965352ba78d9..e068ce5da12f 100644 --- a/src/Illuminate/Cache/RateLimiting/GlobalLimit.php +++ b/src/Illuminate/Cache/RateLimiting/GlobalLimit.php @@ -9,7 +9,6 @@ class GlobalLimit extends Limit * * @param int $maxAttempts * @param int $decaySeconds - * @return void */ public function __construct(int $maxAttempts, int $decaySeconds = 60) { diff --git a/src/Illuminate/Cache/RateLimiting/Limit.php b/src/Illuminate/Cache/RateLimiting/Limit.php index ed4c20258fe2..1a14009640e8 100644 --- a/src/Illuminate/Cache/RateLimiting/Limit.php +++ b/src/Illuminate/Cache/RateLimiting/Limit.php @@ -38,7 +38,6 @@ class Limit * @param mixed $key * @param int $maxAttempts * @param int $decaySeconds - * @return void */ public function __construct($key = '', int $maxAttempts = 60, int $decaySeconds = 60) { diff --git a/src/Illuminate/Cache/RateLimiting/Unlimited.php b/src/Illuminate/Cache/RateLimiting/Unlimited.php index fcfaa3178f0c..7597570fc6d9 100644 --- a/src/Illuminate/Cache/RateLimiting/Unlimited.php +++ b/src/Illuminate/Cache/RateLimiting/Unlimited.php @@ -6,8 +6,6 @@ class Unlimited extends GlobalLimit { /** * Create a new limit instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Cache/RedisLock.php b/src/Illuminate/Cache/RedisLock.php index 67e3e0ac03aa..d28490fac737 100644 --- a/src/Illuminate/Cache/RedisLock.php +++ b/src/Illuminate/Cache/RedisLock.php @@ -18,7 +18,6 @@ class RedisLock extends Lock * @param string $name * @param int $seconds * @param string|null $owner - * @return void */ public function __construct($redis, $name, $seconds, $owner = null) { diff --git a/src/Illuminate/Cache/RedisStore.php b/src/Illuminate/Cache/RedisStore.php index 39f1a0777ea0..33cdf87307c7 100755 --- a/src/Illuminate/Cache/RedisStore.php +++ b/src/Illuminate/Cache/RedisStore.php @@ -51,7 +51,6 @@ class RedisStore extends TaggableStore implements LockProvider * @param \Illuminate\Contracts\Redis\Factory $redis * @param string $prefix * @param string $connection - * @return void */ public function __construct(Redis $redis, $prefix = '', $connection = 'default') { diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 978e2ffbadaf..9f34e4aa9679 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -69,7 +69,6 @@ class Repository implements ArrayAccess, CacheContract * * @param \Illuminate\Contracts\Cache\Store $store * @param array $config - * @return void */ public function __construct(Store $store, array $config = []) { diff --git a/src/Illuminate/Cache/TagSet.php b/src/Illuminate/Cache/TagSet.php index 8be559d849ae..9dc4d7720be4 100644 --- a/src/Illuminate/Cache/TagSet.php +++ b/src/Illuminate/Cache/TagSet.php @@ -25,7 +25,6 @@ class TagSet * * @param \Illuminate\Contracts\Cache\Store $store * @param array $names - * @return void */ public function __construct(Store $store, array $names = []) { diff --git a/src/Illuminate/Cache/TaggedCache.php b/src/Illuminate/Cache/TaggedCache.php index 7cd12303882c..62adff972249 100644 --- a/src/Illuminate/Cache/TaggedCache.php +++ b/src/Illuminate/Cache/TaggedCache.php @@ -22,7 +22,6 @@ class TaggedCache extends Repository * * @param \Illuminate\Contracts\Cache\Store $store * @param \Illuminate\Cache\TagSet $tags - * @return void */ public function __construct(Store $store, TagSet $tags) { diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 14c2f067efe9..784057067509 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -37,7 +37,6 @@ class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerabl * Create a new collection. * * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items - * @return void */ public function __construct($items = []) { diff --git a/src/Illuminate/Collections/HigherOrderCollectionProxy.php b/src/Illuminate/Collections/HigherOrderCollectionProxy.php index c5a723dd2134..7edfd4fa2c3b 100644 --- a/src/Illuminate/Collections/HigherOrderCollectionProxy.php +++ b/src/Illuminate/Collections/HigherOrderCollectionProxy.php @@ -31,7 +31,6 @@ class HigherOrderCollectionProxy * * @param \Illuminate\Support\Enumerable $collection * @param string $method - * @return void */ public function __construct(Enumerable $collection, $method) { diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 47fbb665c7c5..68d6a4acdfef 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -39,7 +39,6 @@ class LazyCollection implements CanBeEscapedWhenCastToString, Enumerable * Create a new lazy collection instance. * * @param \Illuminate\Contracts\Support\Arrayable|iterable|(Closure(): \Generator)|self|array|null $source - * @return void */ public function __construct($source = null) { diff --git a/src/Illuminate/Collections/MultipleItemsFoundException.php b/src/Illuminate/Collections/MultipleItemsFoundException.php index d90d835b4159..9c5c7c560ccb 100644 --- a/src/Illuminate/Collections/MultipleItemsFoundException.php +++ b/src/Illuminate/Collections/MultipleItemsFoundException.php @@ -19,7 +19,6 @@ class MultipleItemsFoundException extends RuntimeException * @param int $count * @param int $code * @param \Throwable|null $previous - * @return void */ public function __construct($count, $code = 0, $previous = null) { diff --git a/src/Illuminate/Conditionable/HigherOrderWhenProxy.php b/src/Illuminate/Conditionable/HigherOrderWhenProxy.php index 579114cf1989..0a694c24fcd2 100644 --- a/src/Illuminate/Conditionable/HigherOrderWhenProxy.php +++ b/src/Illuminate/Conditionable/HigherOrderWhenProxy.php @@ -36,7 +36,6 @@ class HigherOrderWhenProxy * Create a new proxy instance. * * @param mixed $target - * @return void */ public function __construct($target) { diff --git a/src/Illuminate/Config/Repository.php b/src/Illuminate/Config/Repository.php index bf4db4ea3945..19240b42ac93 100644 --- a/src/Illuminate/Config/Repository.php +++ b/src/Illuminate/Config/Repository.php @@ -23,7 +23,6 @@ class Repository implements ArrayAccess, ConfigContract * Create a new configuration repository. * * @param array $items - * @return void */ public function __construct(array $items = []) { diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 86399d0ac24a..07073aab309c 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -63,7 +63,6 @@ class Application extends SymfonyApplication implements ApplicationContract * @param \Illuminate\Contracts\Container\Container $laravel * @param \Illuminate\Contracts\Events\Dispatcher $events * @param string $version - * @return void */ public function __construct(Container $laravel, Dispatcher $events, $version) { diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 635c416100ef..e4be18364599 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -86,8 +86,6 @@ class Command extends SymfonyCommand /** * Create a new console command instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Console/ContainerCommandLoader.php b/src/Illuminate/Console/ContainerCommandLoader.php index f770f6c7101f..08af8f4cadc8 100644 --- a/src/Illuminate/Console/ContainerCommandLoader.php +++ b/src/Illuminate/Console/ContainerCommandLoader.php @@ -28,7 +28,6 @@ class ContainerCommandLoader implements CommandLoaderInterface * * @param \Psr\Container\ContainerInterface $container * @param array $commandMap - * @return void */ public function __construct(ContainerInterface $container, array $commandMap) { diff --git a/src/Illuminate/Console/Events/ArtisanStarting.php b/src/Illuminate/Console/Events/ArtisanStarting.php index 15f044979de7..30538804a044 100644 --- a/src/Illuminate/Console/Events/ArtisanStarting.php +++ b/src/Illuminate/Console/Events/ArtisanStarting.php @@ -10,7 +10,6 @@ class ArtisanStarting * Create a new event instance. * * @param \Illuminate\Console\Application $artisan The Artisan application instance. - * @return void */ public function __construct( public Application $artisan, diff --git a/src/Illuminate/Console/Events/CommandFinished.php b/src/Illuminate/Console/Events/CommandFinished.php index d2f229224c0f..850baea333bc 100644 --- a/src/Illuminate/Console/Events/CommandFinished.php +++ b/src/Illuminate/Console/Events/CommandFinished.php @@ -14,7 +14,6 @@ class CommandFinished * @param \Symfony\Component\Console\Input\InputInterface $input The console input implementation. * @param \Symfony\Component\Console\Output\OutputInterface $output The command output implementation. * @param int $exitCode The command exit code. - * @return void */ public function __construct( public string $command, diff --git a/src/Illuminate/Console/Events/CommandStarting.php b/src/Illuminate/Console/Events/CommandStarting.php index f8d56bcc8a35..658c70ffc57e 100644 --- a/src/Illuminate/Console/Events/CommandStarting.php +++ b/src/Illuminate/Console/Events/CommandStarting.php @@ -13,7 +13,6 @@ class CommandStarting * @param string $command The command name. * @param \Symfony\Component\Console\Input\InputInterface $input The console input implementation. * @param \Symfony\Component\Console\Output\OutputInterface $output The command output implementation. - * @return void */ public function __construct( public string $command, diff --git a/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php b/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php index cdc22c975169..b277a6fced65 100644 --- a/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php +++ b/src/Illuminate/Console/Events/ScheduledBackgroundTaskFinished.php @@ -10,7 +10,6 @@ class ScheduledBackgroundTaskFinished * Create a new event instance. * * @param \Illuminate\Console\Scheduling\Event $task The scheduled event that ran. - * @return void */ public function __construct( public Event $task, diff --git a/src/Illuminate/Console/Events/ScheduledTaskFailed.php b/src/Illuminate/Console/Events/ScheduledTaskFailed.php index 66aa004e9929..ba884bb657d6 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskFailed.php +++ b/src/Illuminate/Console/Events/ScheduledTaskFailed.php @@ -12,7 +12,6 @@ class ScheduledTaskFailed * * @param \Illuminate\Console\Scheduling\Event $task The scheduled event that failed. * @param \Throwable $exception The exception that was thrown. - * @return void */ public function __construct( public Event $task, diff --git a/src/Illuminate/Console/Events/ScheduledTaskFinished.php b/src/Illuminate/Console/Events/ScheduledTaskFinished.php index 1b73e6424680..0a56f382fafd 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskFinished.php +++ b/src/Illuminate/Console/Events/ScheduledTaskFinished.php @@ -11,7 +11,6 @@ class ScheduledTaskFinished * * @param \Illuminate\Console\Scheduling\Event $task The scheduled event that ran. * @param float $runtime The runtime of the scheduled event. - * @return void */ public function __construct( public Event $task, diff --git a/src/Illuminate/Console/Events/ScheduledTaskSkipped.php b/src/Illuminate/Console/Events/ScheduledTaskSkipped.php index 661f8f807e36..347c26593cff 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskSkipped.php +++ b/src/Illuminate/Console/Events/ScheduledTaskSkipped.php @@ -10,7 +10,6 @@ class ScheduledTaskSkipped * Create a new event instance. * * @param \Illuminate\Console\Scheduling\Event $task The scheduled event being run. - * @return void */ public function __construct( public Event $task, diff --git a/src/Illuminate/Console/Events/ScheduledTaskStarting.php b/src/Illuminate/Console/Events/ScheduledTaskStarting.php index dfdf18494df4..52a34c7746b4 100644 --- a/src/Illuminate/Console/Events/ScheduledTaskStarting.php +++ b/src/Illuminate/Console/Events/ScheduledTaskStarting.php @@ -10,7 +10,6 @@ class ScheduledTaskStarting * Create a new event instance. * * @param \Illuminate\Console\Scheduling\Event $task The scheduled event being run. - * @return void */ public function __construct( public Event $task, diff --git a/src/Illuminate/Console/GeneratorCommand.php b/src/Illuminate/Console/GeneratorCommand.php index 032b0b042c6b..5b6af51a576b 100644 --- a/src/Illuminate/Console/GeneratorCommand.php +++ b/src/Illuminate/Console/GeneratorCommand.php @@ -121,7 +121,6 @@ abstract class GeneratorCommand extends Command implements PromptsForMissingInpu * Create a new generator command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Console/MigrationGeneratorCommand.php b/src/Illuminate/Console/MigrationGeneratorCommand.php index c741c03358fe..21198c03052c 100644 --- a/src/Illuminate/Console/MigrationGeneratorCommand.php +++ b/src/Illuminate/Console/MigrationGeneratorCommand.php @@ -19,7 +19,6 @@ abstract class MigrationGeneratorCommand extends Command * Create a new migration generator command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Console/OutputStyle.php b/src/Illuminate/Console/OutputStyle.php index 193e93da4350..5bfd6675bfaf 100644 --- a/src/Illuminate/Console/OutputStyle.php +++ b/src/Illuminate/Console/OutputStyle.php @@ -40,7 +40,6 @@ class OutputStyle extends SymfonyStyle implements NewLineAware * * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output - * @return void */ public function __construct(InputInterface $input, OutputInterface $output) { diff --git a/src/Illuminate/Console/Scheduling/CacheEventMutex.php b/src/Illuminate/Console/Scheduling/CacheEventMutex.php index 3d1ad9247a1b..b2ca43e92a74 100644 --- a/src/Illuminate/Console/Scheduling/CacheEventMutex.php +++ b/src/Illuminate/Console/Scheduling/CacheEventMutex.php @@ -26,7 +26,6 @@ class CacheEventMutex implements EventMutex, CacheAware * Create a new overlapping strategy. * * @param \Illuminate\Contracts\Cache\Factory $cache - * @return void */ public function __construct(Cache $cache) { diff --git a/src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php b/src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php index ca8e2cb881f7..439e5bea3790 100644 --- a/src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php +++ b/src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php @@ -25,7 +25,6 @@ class CacheSchedulingMutex implements SchedulingMutex, CacheAware * Create a new scheduling strategy. * * @param \Illuminate\Contracts\Cache\Factory $cache - * @return void */ public function __construct(Cache $cache) { diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 74c588ef037e..944728361a7f 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -96,7 +96,6 @@ class Event * @param \Illuminate\Console\Scheduling\EventMutex $mutex * @param string $command * @param \DateTimeZone|string|null $timezone - * @return void */ public function __construct(EventMutex $mutex, $command, $timezone = null) { diff --git a/src/Illuminate/Console/Scheduling/ScheduleInterruptCommand.php b/src/Illuminate/Console/Scheduling/ScheduleInterruptCommand.php index 662606a2aee3..4477da56a4e1 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleInterruptCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleInterruptCommand.php @@ -35,7 +35,6 @@ class ScheduleInterruptCommand extends Command * Create a new schedule interrupt command. * * @param \Illuminate\Contracts\Cache\Repository $cache - * @return void */ public function __construct(Cache $cache) { diff --git a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php index b914229af51b..75cb579925cf 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php @@ -85,8 +85,6 @@ class ScheduleRunCommand extends Command /** * Create a new command instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Console/Signals.php b/src/Illuminate/Console/Signals.php index 33192dc1c1d2..425352594c88 100644 --- a/src/Illuminate/Console/Signals.php +++ b/src/Illuminate/Console/Signals.php @@ -32,7 +32,6 @@ class Signals * Create a new signal registrar instance. * * @param \Symfony\Component\Console\SignalRegistry\SignalRegistry $registry - * @return void */ public function __construct($registry) { diff --git a/src/Illuminate/Console/View/Components/Component.php b/src/Illuminate/Console/View/Components/Component.php index 913c8b9bbedb..cfb18e1ccd3a 100644 --- a/src/Illuminate/Console/View/Components/Component.php +++ b/src/Illuminate/Console/View/Components/Component.php @@ -30,7 +30,6 @@ abstract class Component * Creates a new component instance. * * @param \Illuminate\Console\OutputStyle $output - * @return void */ public function __construct($output) { diff --git a/src/Illuminate/Console/View/Components/Factory.php b/src/Illuminate/Console/View/Components/Factory.php index e226d79ae7e3..2929279057ee 100644 --- a/src/Illuminate/Console/View/Components/Factory.php +++ b/src/Illuminate/Console/View/Components/Factory.php @@ -33,7 +33,6 @@ class Factory * Creates a new factory instance. * * @param \Illuminate\Console\OutputStyle $output - * @return void */ public function __construct($output) { diff --git a/src/Illuminate/Container/ContextualBindingBuilder.php b/src/Illuminate/Container/ContextualBindingBuilder.php index 707b74c74beb..0f3163f9403a 100644 --- a/src/Illuminate/Container/ContextualBindingBuilder.php +++ b/src/Illuminate/Container/ContextualBindingBuilder.php @@ -33,7 +33,6 @@ class ContextualBindingBuilder implements ContextualBindingBuilderContract * * @param \Illuminate\Contracts\Container\Container $container * @param string|array $concrete - * @return void */ public function __construct(Container $container, $concrete) { diff --git a/src/Illuminate/Container/RewindableGenerator.php b/src/Illuminate/Container/RewindableGenerator.php index 14c0bd01789b..53013f8fa952 100644 --- a/src/Illuminate/Container/RewindableGenerator.php +++ b/src/Illuminate/Container/RewindableGenerator.php @@ -27,7 +27,6 @@ class RewindableGenerator implements Countable, IteratorAggregate * * @param callable $generator * @param callable|int $count - * @return void */ public function __construct(callable $generator, $count) { diff --git a/src/Illuminate/Contracts/Database/ModelIdentifier.php b/src/Illuminate/Contracts/Database/ModelIdentifier.php index 5742e8243ddf..95db3f4a74f8 100644 --- a/src/Illuminate/Contracts/Database/ModelIdentifier.php +++ b/src/Illuminate/Contracts/Database/ModelIdentifier.php @@ -48,7 +48,6 @@ class ModelIdentifier * @param mixed $id * @param array $relations * @param mixed $connection - * @return void */ public function __construct($class, $id, array $relations, $connection) { diff --git a/src/Illuminate/Contracts/Queue/EntityNotFoundException.php b/src/Illuminate/Contracts/Queue/EntityNotFoundException.php index 079250d06346..0b966a7285b3 100644 --- a/src/Illuminate/Contracts/Queue/EntityNotFoundException.php +++ b/src/Illuminate/Contracts/Queue/EntityNotFoundException.php @@ -11,7 +11,6 @@ class EntityNotFoundException extends InvalidArgumentException * * @param string $type * @param mixed $id - * @return void */ public function __construct($type, $id) { diff --git a/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php b/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php index 4caa57410fe2..40ab67b5dce5 100644 --- a/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php +++ b/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php @@ -18,7 +18,6 @@ class AddQueuedCookiesToResponse * Create a new CookieQueue instance. * * @param \Illuminate\Contracts\Cookie\QueueingFactory $cookies - * @return void */ public function __construct(CookieJar $cookies) { diff --git a/src/Illuminate/Cookie/Middleware/EncryptCookies.php b/src/Illuminate/Cookie/Middleware/EncryptCookies.php index aefd7bac2538..40146e38d34c 100644 --- a/src/Illuminate/Cookie/Middleware/EncryptCookies.php +++ b/src/Illuminate/Cookie/Middleware/EncryptCookies.php @@ -45,7 +45,6 @@ class EncryptCookies * Create a new CookieGuard instance. * * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter - * @return void */ public function __construct(EncrypterContract $encrypter) { diff --git a/src/Illuminate/Database/Capsule/Manager.php b/src/Illuminate/Database/Capsule/Manager.php index cfc47eb5abcf..ddcc85dcf7a0 100755 --- a/src/Illuminate/Database/Capsule/Manager.php +++ b/src/Illuminate/Database/Capsule/Manager.php @@ -25,7 +25,6 @@ class Manager * Create a new database capsule manager. * * @param \Illuminate\Container\Container|null $container - * @return void */ public function __construct(?Container $container = null) { diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 69780f78a2b4..a883e3edb22e 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -208,7 +208,6 @@ class Connection implements ConnectionInterface * @param string $database * @param string $tablePrefix * @param array $config - * @return void */ public function __construct($pdo, $database = '', $tablePrefix = '', array $config = []) { diff --git a/src/Illuminate/Database/ConnectionResolver.php b/src/Illuminate/Database/ConnectionResolver.php index dd16ffd65755..b7b6279e1fc5 100755 --- a/src/Illuminate/Database/ConnectionResolver.php +++ b/src/Illuminate/Database/ConnectionResolver.php @@ -22,7 +22,6 @@ class ConnectionResolver implements ConnectionResolverInterface * Create a new connection resolver instance. * * @param array $connections - * @return void */ public function __construct(array $connections = []) { diff --git a/src/Illuminate/Database/Connectors/ConnectionFactory.php b/src/Illuminate/Database/Connectors/ConnectionFactory.php index 9d28225de4c5..8660921633a0 100755 --- a/src/Illuminate/Database/Connectors/ConnectionFactory.php +++ b/src/Illuminate/Database/Connectors/ConnectionFactory.php @@ -26,7 +26,6 @@ class ConnectionFactory * Create a new connection factory instance. * * @param \Illuminate\Contracts\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Database/Console/Migrations/FreshCommand.php b/src/Illuminate/Database/Console/Migrations/FreshCommand.php index 45900ffe7a45..723d3c2298a4 100644 --- a/src/Illuminate/Database/Console/Migrations/FreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/FreshCommand.php @@ -41,7 +41,6 @@ class FreshCommand extends Command * Create a new fresh command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator - * @return void */ public function __construct(Migrator $migrator) { diff --git a/src/Illuminate/Database/Console/Migrations/InstallCommand.php b/src/Illuminate/Database/Console/Migrations/InstallCommand.php index 607553010a61..b89cd4b4e86f 100755 --- a/src/Illuminate/Database/Console/Migrations/InstallCommand.php +++ b/src/Illuminate/Database/Console/Migrations/InstallCommand.php @@ -35,7 +35,6 @@ class InstallCommand extends Command * Create a new migration install command instance. * * @param \Illuminate\Database\Migrations\MigrationRepositoryInterface $repository - * @return void */ public function __construct(MigrationRepositoryInterface $repository) { diff --git a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php index 6345985bf06f..497836c65a49 100755 --- a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php @@ -64,7 +64,6 @@ class MigrateCommand extends BaseCommand implements Isolatable * * @param \Illuminate\Database\Migrations\Migrator $migrator * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher - * @return void */ public function __construct(Migrator $migrator, Dispatcher $dispatcher) { diff --git a/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php index e3fb4076e476..c9494c5d5c44 100644 --- a/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php @@ -51,7 +51,6 @@ class MigrateMakeCommand extends BaseCommand implements PromptsForMissingInput * * @param \Illuminate\Database\Migrations\MigrationCreator $creator * @param \Illuminate\Support\Composer $composer - * @return void */ public function __construct(MigrationCreator $creator, Composer $composer) { diff --git a/src/Illuminate/Database/Console/Migrations/ResetCommand.php b/src/Illuminate/Database/Console/Migrations/ResetCommand.php index 85ccae9734e0..787801bab258 100755 --- a/src/Illuminate/Database/Console/Migrations/ResetCommand.php +++ b/src/Illuminate/Database/Console/Migrations/ResetCommand.php @@ -39,7 +39,6 @@ class ResetCommand extends BaseCommand * Create a new migration rollback command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator - * @return void */ public function __construct(Migrator $migrator) { diff --git a/src/Illuminate/Database/Console/Migrations/RollbackCommand.php b/src/Illuminate/Database/Console/Migrations/RollbackCommand.php index 8846a5e376cf..9c3543ec5bfe 100755 --- a/src/Illuminate/Database/Console/Migrations/RollbackCommand.php +++ b/src/Illuminate/Database/Console/Migrations/RollbackCommand.php @@ -39,7 +39,6 @@ class RollbackCommand extends BaseCommand * Create a new migration rollback command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator - * @return void */ public function __construct(Migrator $migrator) { diff --git a/src/Illuminate/Database/Console/Migrations/StatusCommand.php b/src/Illuminate/Database/Console/Migrations/StatusCommand.php index 378c4a720d26..cbb16a133c73 100644 --- a/src/Illuminate/Database/Console/Migrations/StatusCommand.php +++ b/src/Illuminate/Database/Console/Migrations/StatusCommand.php @@ -36,7 +36,6 @@ class StatusCommand extends BaseCommand * Create a new migration rollback command instance. * * @param \Illuminate\Database\Migrations\Migrator $migrator - * @return void */ public function __construct(Migrator $migrator) { diff --git a/src/Illuminate/Database/Console/Seeds/SeedCommand.php b/src/Illuminate/Database/Console/Seeds/SeedCommand.php index 4ce2b0213129..5ea590493eb2 100644 --- a/src/Illuminate/Database/Console/Seeds/SeedCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeedCommand.php @@ -40,7 +40,6 @@ class SeedCommand extends Command * Create a new database seed command instance. * * @param \Illuminate\Database\ConnectionResolverInterface $resolver - * @return void */ public function __construct(Resolver $resolver) { diff --git a/src/Illuminate/Database/DatabaseManager.php b/src/Illuminate/Database/DatabaseManager.php index d3018bcd3db4..4d3aafc83fe3 100755 --- a/src/Illuminate/Database/DatabaseManager.php +++ b/src/Illuminate/Database/DatabaseManager.php @@ -69,7 +69,6 @@ class DatabaseManager implements ConnectionResolverInterface * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Database\Connectors\ConnectionFactory $factory - * @return void */ public function __construct($app, ConnectionFactory $factory) { diff --git a/src/Illuminate/Database/DatabaseTransactionRecord.php b/src/Illuminate/Database/DatabaseTransactionRecord.php index c35acb184aa5..2afe5dfc1ce1 100755 --- a/src/Illuminate/Database/DatabaseTransactionRecord.php +++ b/src/Illuminate/Database/DatabaseTransactionRecord.php @@ -38,7 +38,6 @@ class DatabaseTransactionRecord * @param string $connection * @param int $level * @param \Illuminate\Database\DatabaseTransactionRecord|null $parent - * @return void */ public function __construct($connection, $level, ?DatabaseTransactionRecord $parent = null) { diff --git a/src/Illuminate/Database/DatabaseTransactionsManager.php b/src/Illuminate/Database/DatabaseTransactionsManager.php index ee2889a2d18a..f8d639e2a465 100755 --- a/src/Illuminate/Database/DatabaseTransactionsManager.php +++ b/src/Illuminate/Database/DatabaseTransactionsManager.php @@ -29,8 +29,6 @@ class DatabaseTransactionsManager /** * Create a new database transactions manager instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Database/Eloquent/Attributes/CollectedBy.php b/src/Illuminate/Database/Eloquent/Attributes/CollectedBy.php index 14eb3a43745d..356b85d83233 100644 --- a/src/Illuminate/Database/Eloquent/Attributes/CollectedBy.php +++ b/src/Illuminate/Database/Eloquent/Attributes/CollectedBy.php @@ -11,7 +11,6 @@ class CollectedBy * Create a new attribute instance. * * @param class-string<\Illuminate\Database\Eloquent\Collection<*, *>> $collectionClass - * @return void */ public function __construct(public string $collectionClass) { diff --git a/src/Illuminate/Database/Eloquent/Attributes/ObservedBy.php b/src/Illuminate/Database/Eloquent/Attributes/ObservedBy.php index 3db5182db7e5..32a9fffc07ca 100644 --- a/src/Illuminate/Database/Eloquent/Attributes/ObservedBy.php +++ b/src/Illuminate/Database/Eloquent/Attributes/ObservedBy.php @@ -11,7 +11,6 @@ class ObservedBy * Create a new attribute instance. * * @param array|string $classes - * @return void */ public function __construct(public array|string $classes) { diff --git a/src/Illuminate/Database/Eloquent/Attributes/ScopedBy.php b/src/Illuminate/Database/Eloquent/Attributes/ScopedBy.php index 431f63e57066..2b8855f8925b 100644 --- a/src/Illuminate/Database/Eloquent/Attributes/ScopedBy.php +++ b/src/Illuminate/Database/Eloquent/Attributes/ScopedBy.php @@ -11,7 +11,6 @@ class ScopedBy * Create a new attribute instance. * * @param array|string $classes - * @return void */ public function __construct(public array|string $classes) { diff --git a/src/Illuminate/Database/Eloquent/Attributes/UseFactory.php b/src/Illuminate/Database/Eloquent/Attributes/UseFactory.php index 7f56804e2134..a013102fcd72 100644 --- a/src/Illuminate/Database/Eloquent/Attributes/UseFactory.php +++ b/src/Illuminate/Database/Eloquent/Attributes/UseFactory.php @@ -11,7 +11,6 @@ class UseFactory * Create a new attribute instance. * * @param class-string<\Illuminate\Database\Eloquent\Factories\Factory> $factoryClass - * @return void */ public function __construct(public string $factoryClass) { diff --git a/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php b/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php index 1887ae8e40dc..8bd028032e67 100644 --- a/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php +++ b/src/Illuminate/Database/Eloquent/BroadcastableModelEventOccurred.php @@ -59,7 +59,6 @@ class BroadcastableModelEventOccurred implements ShouldBroadcast * * @param \Illuminate\Database\Eloquent\Model $model * @param string $event - * @return void */ public function __construct($model, $event) { diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index b01a2b79e4b7..192a707235bd 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -168,7 +168,6 @@ class Builder implements BuilderContract * Create a new Eloquent query builder instance. * * @param \Illuminate\Database\Query\Builder $query - * @return void */ public function __construct(QueryBuilder $query) { diff --git a/src/Illuminate/Database/Eloquent/Casts/Attribute.php b/src/Illuminate/Database/Eloquent/Casts/Attribute.php index 4fe2d807b690..26d13ba3fbe3 100644 --- a/src/Illuminate/Database/Eloquent/Casts/Attribute.php +++ b/src/Illuminate/Database/Eloquent/Casts/Attribute.php @@ -37,7 +37,6 @@ class Attribute * * @param callable|null $get * @param callable|null $set - * @return void */ public function __construct(?callable $get = null, ?callable $set = null) { diff --git a/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php b/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php index 8e40261021ef..da004c83bc74 100644 --- a/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php +++ b/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php @@ -34,7 +34,6 @@ class BelongsToManyRelationship * @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $factory * @param callable|array $pivot * @param string $relationship - * @return void */ public function __construct($factory, $pivot, $relationship) { diff --git a/src/Illuminate/Database/Eloquent/Factories/BelongsToRelationship.php b/src/Illuminate/Database/Eloquent/Factories/BelongsToRelationship.php index b2fb1b251a31..5979183d92f6 100644 --- a/src/Illuminate/Database/Eloquent/Factories/BelongsToRelationship.php +++ b/src/Illuminate/Database/Eloquent/Factories/BelongsToRelationship.php @@ -33,7 +33,6 @@ class BelongsToRelationship * * @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Database\Eloquent\Model $factory * @param string $relationship - * @return void */ public function __construct($factory, $relationship) { diff --git a/src/Illuminate/Database/Eloquent/Factories/CrossJoinSequence.php b/src/Illuminate/Database/Eloquent/Factories/CrossJoinSequence.php index 3270b305cde9..594120b38514 100644 --- a/src/Illuminate/Database/Eloquent/Factories/CrossJoinSequence.php +++ b/src/Illuminate/Database/Eloquent/Factories/CrossJoinSequence.php @@ -10,7 +10,6 @@ class CrossJoinSequence extends Sequence * Create a new cross join sequence instance. * * @param array ...$sequences - * @return void */ public function __construct(...$sequences) { diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index 58b00873b307..ffe9018e67f0 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -146,7 +146,6 @@ abstract class Factory * @param string|null $connection * @param \Illuminate\Support\Collection|null $recycle * @param bool $expandRelationships - * @return void */ public function __construct( $count = null, diff --git a/src/Illuminate/Database/Eloquent/Factories/Relationship.php b/src/Illuminate/Database/Eloquent/Factories/Relationship.php index 3eb62da38a6e..4024f1c929c0 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Relationship.php +++ b/src/Illuminate/Database/Eloquent/Factories/Relationship.php @@ -28,7 +28,6 @@ class Relationship * * @param \Illuminate\Database\Eloquent\Factories\Factory $factory * @param string $relationship - * @return void */ public function __construct(Factory $factory, $relationship) { diff --git a/src/Illuminate/Database/Eloquent/Factories/Sequence.php b/src/Illuminate/Database/Eloquent/Factories/Sequence.php index e523fb3eebd0..11971eced7da 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Sequence.php +++ b/src/Illuminate/Database/Eloquent/Factories/Sequence.php @@ -31,7 +31,6 @@ class Sequence implements Countable * Create a new sequence instance. * * @param mixed ...$sequence - * @return void */ public function __construct(...$sequence) { diff --git a/src/Illuminate/Database/Eloquent/HigherOrderBuilderProxy.php b/src/Illuminate/Database/Eloquent/HigherOrderBuilderProxy.php index 1c49ba28b7c4..dfcbbd677476 100644 --- a/src/Illuminate/Database/Eloquent/HigherOrderBuilderProxy.php +++ b/src/Illuminate/Database/Eloquent/HigherOrderBuilderProxy.php @@ -26,7 +26,6 @@ class HigherOrderBuilderProxy * * @param \Illuminate\Database\Eloquent\Builder<*> $builder * @param string $method - * @return void */ public function __construct(Builder $builder, $method) { diff --git a/src/Illuminate/Database/Eloquent/InvalidCastException.php b/src/Illuminate/Database/Eloquent/InvalidCastException.php index e90e9a71bd2b..f37672c0b9fa 100644 --- a/src/Illuminate/Database/Eloquent/InvalidCastException.php +++ b/src/Illuminate/Database/Eloquent/InvalidCastException.php @@ -33,7 +33,6 @@ class InvalidCastException extends RuntimeException * @param object $model * @param string $column * @param string $castType - * @return void */ public function __construct($model, $column, $castType) { diff --git a/src/Illuminate/Database/Eloquent/MissingAttributeException.php b/src/Illuminate/Database/Eloquent/MissingAttributeException.php index 87935c141dce..ef05109927ea 100755 --- a/src/Illuminate/Database/Eloquent/MissingAttributeException.php +++ b/src/Illuminate/Database/Eloquent/MissingAttributeException.php @@ -11,7 +11,6 @@ class MissingAttributeException extends OutOfBoundsException * * @param \Illuminate\Database\Eloquent\Model $model * @param string $key - * @return void */ public function __construct($model, $key) { diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 2994e8f256e9..a61a2f088b47 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -248,7 +248,6 @@ abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToSt * Create a new Eloquent model instance. * * @param array $attributes - * @return void */ public function __construct(array $attributes = []) { diff --git a/src/Illuminate/Database/Eloquent/ModelInspector.php b/src/Illuminate/Database/Eloquent/ModelInspector.php index 96afe44c187a..b0db2130c0a3 100644 --- a/src/Illuminate/Database/Eloquent/ModelInspector.php +++ b/src/Illuminate/Database/Eloquent/ModelInspector.php @@ -47,7 +47,6 @@ class ModelInspector * Create a new model inspector instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct(Application $app) { diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index d38d512af924..e145040a92c9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -59,7 +59,6 @@ class BelongsTo extends Relation * @param string $foreignKey * @param string $ownerKey * @param string $relationName - * @return void */ public function __construct(Builder $query, Model $child, $foreignKey, $ownerKey, $relationName) { diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 9e8a30c8de95..e125a760410b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -154,7 +154,6 @@ class BelongsToMany extends Relation * @param string $parentKey * @param string $relatedKey * @param string|null $relationName - * @return void */ public function __construct( Builder $query, diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 3d8426c2a85d..4142572207af 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -41,7 +41,6 @@ abstract class HasOneOrMany extends Relation * @param TDeclaringModel $parent * @param string $foreignKey * @param string $localKey - * @return void */ public function __construct(Builder $query, Model $parent, $foreignKey, $localKey) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index c25be24b7016..9b2ac58a3a50 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -77,7 +77,6 @@ abstract class HasOneOrManyThrough extends Relation * @param string $secondKey * @param string $localKey * @param string $secondLocalKey - * @return void */ public function __construct(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) { diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 9720cc218ed0..6d6a34c31f38 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -37,7 +37,6 @@ abstract class MorphOneOrMany extends HasOneOrMany * @param string $type * @param string $id * @param string $localKey - * @return void */ public function __construct(Builder $query, Model $parent, $type, $id, $localKey) { diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index ffa90acdf1a1..22e0cfce7227 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -83,7 +83,6 @@ class MorphTo extends BelongsTo * @param string|null $ownerKey * @param string $type * @param string $relation - * @return void */ public function __construct(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation) { diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 21c542de4bc9..162ebec1777b 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -53,7 +53,6 @@ class MorphToMany extends BelongsToMany * @param string $relatedKey * @param string|null $relationName * @param bool $inverse - * @return void */ public function __construct( Builder $query, diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 574560a398ed..ad7d75168e78 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -88,7 +88,6 @@ abstract class Relation implements BuilderContract * * @param \Illuminate\Database\Eloquent\Builder $query * @param TDeclaringModel $parent - * @return void */ public function __construct(Builder $query, Model $parent) { diff --git a/src/Illuminate/Database/Events/ConnectionEvent.php b/src/Illuminate/Database/Events/ConnectionEvent.php index 818c7850f3dd..0721a37c56c2 100644 --- a/src/Illuminate/Database/Events/ConnectionEvent.php +++ b/src/Illuminate/Database/Events/ConnectionEvent.php @@ -22,7 +22,6 @@ abstract class ConnectionEvent * Create a new event instance. * * @param \Illuminate\Database\Connection $connection - * @return void */ public function __construct($connection) { diff --git a/src/Illuminate/Database/Events/DatabaseRefreshed.php b/src/Illuminate/Database/Events/DatabaseRefreshed.php index 5c9fd45bb314..66879b6aae6a 100644 --- a/src/Illuminate/Database/Events/DatabaseRefreshed.php +++ b/src/Illuminate/Database/Events/DatabaseRefreshed.php @@ -11,7 +11,6 @@ class DatabaseRefreshed implements MigrationEventContract * * @param string|null $database * @param bool $seeding - * @return void */ public function __construct( public ?string $database = null, diff --git a/src/Illuminate/Database/Events/MigrationEvent.php b/src/Illuminate/Database/Events/MigrationEvent.php index 157303d2e2b5..83f10871a1d2 100644 --- a/src/Illuminate/Database/Events/MigrationEvent.php +++ b/src/Illuminate/Database/Events/MigrationEvent.php @@ -26,7 +26,6 @@ abstract class MigrationEvent implements MigrationEventContract * * @param \Illuminate\Database\Migrations\Migration $migration * @param string $method - * @return void */ public function __construct(Migration $migration, $method) { diff --git a/src/Illuminate/Database/Events/MigrationsEvent.php b/src/Illuminate/Database/Events/MigrationsEvent.php index 7575a02162fc..dbed4949e9c3 100644 --- a/src/Illuminate/Database/Events/MigrationsEvent.php +++ b/src/Illuminate/Database/Events/MigrationsEvent.php @@ -11,7 +11,6 @@ abstract class MigrationsEvent implements MigrationEventContract * * @param string $method The migration method that was invoked. * @param array $options The options provided when the migration method was invoked. - * @return void */ public function __construct( public $method, diff --git a/src/Illuminate/Database/Events/MigrationsPruned.php b/src/Illuminate/Database/Events/MigrationsPruned.php index 86b48e9c9d3c..16e519e27c06 100644 --- a/src/Illuminate/Database/Events/MigrationsPruned.php +++ b/src/Illuminate/Database/Events/MigrationsPruned.php @@ -32,7 +32,6 @@ class MigrationsPruned * * @param \Illuminate\Database\Connection $connection * @param string $path - * @return void */ public function __construct(Connection $connection, string $path) { diff --git a/src/Illuminate/Database/Events/ModelPruningFinished.php b/src/Illuminate/Database/Events/ModelPruningFinished.php index 034c971df97a..e27c687e847f 100644 --- a/src/Illuminate/Database/Events/ModelPruningFinished.php +++ b/src/Illuminate/Database/Events/ModelPruningFinished.php @@ -8,7 +8,6 @@ class ModelPruningFinished * Create a new event instance. * * @param array $models The class names of the models that were pruned. - * @return void */ public function __construct( public $models, diff --git a/src/Illuminate/Database/Events/ModelPruningStarting.php b/src/Illuminate/Database/Events/ModelPruningStarting.php index 7737a1442e4f..a45f912dc283 100644 --- a/src/Illuminate/Database/Events/ModelPruningStarting.php +++ b/src/Illuminate/Database/Events/ModelPruningStarting.php @@ -8,7 +8,6 @@ class ModelPruningStarting * Create a new event instance. * * @param array $models The class names of the models that will be pruned. - * @return void */ public function __construct( public $models diff --git a/src/Illuminate/Database/Events/ModelsPruned.php b/src/Illuminate/Database/Events/ModelsPruned.php index 08e9f7fb0d6d..2d9605e5fe60 100644 --- a/src/Illuminate/Database/Events/ModelsPruned.php +++ b/src/Illuminate/Database/Events/ModelsPruned.php @@ -9,7 +9,6 @@ class ModelsPruned * * @param string $model The class name of the model that was pruned. * @param int $count The number of pruned records. - * @return void */ public function __construct( public $model, diff --git a/src/Illuminate/Database/Events/NoPendingMigrations.php b/src/Illuminate/Database/Events/NoPendingMigrations.php index d51be1eff059..ab9eb6b620ea 100644 --- a/src/Illuminate/Database/Events/NoPendingMigrations.php +++ b/src/Illuminate/Database/Events/NoPendingMigrations.php @@ -10,7 +10,6 @@ class NoPendingMigrations implements MigrationEvent * Create a new event instance. * * @param string $method The migration method that was called. - * @return void */ public function __construct( public $method, diff --git a/src/Illuminate/Database/Events/QueryExecuted.php b/src/Illuminate/Database/Events/QueryExecuted.php index 644d947332c3..960df9da0954 100644 --- a/src/Illuminate/Database/Events/QueryExecuted.php +++ b/src/Illuminate/Database/Events/QueryExecuted.php @@ -46,7 +46,6 @@ class QueryExecuted * @param array $bindings * @param float|null $time * @param \Illuminate\Database\Connection $connection - * @return void */ public function __construct($sql, $bindings, $time, $connection) { diff --git a/src/Illuminate/Database/Events/SchemaDumped.php b/src/Illuminate/Database/Events/SchemaDumped.php index 1cbbfff96ec6..416462027c30 100644 --- a/src/Illuminate/Database/Events/SchemaDumped.php +++ b/src/Illuminate/Database/Events/SchemaDumped.php @@ -30,7 +30,6 @@ class SchemaDumped * * @param \Illuminate\Database\Connection $connection * @param string $path - * @return void */ public function __construct($connection, $path) { diff --git a/src/Illuminate/Database/Events/SchemaLoaded.php b/src/Illuminate/Database/Events/SchemaLoaded.php index 061a079a9611..d86ae5307499 100644 --- a/src/Illuminate/Database/Events/SchemaLoaded.php +++ b/src/Illuminate/Database/Events/SchemaLoaded.php @@ -30,7 +30,6 @@ class SchemaLoaded * * @param \Illuminate\Database\Connection $connection * @param string $path - * @return void */ public function __construct($connection, $path) { diff --git a/src/Illuminate/Database/Events/StatementPrepared.php b/src/Illuminate/Database/Events/StatementPrepared.php index 30b3e4bb7ebe..43f02a0e26a3 100644 --- a/src/Illuminate/Database/Events/StatementPrepared.php +++ b/src/Illuminate/Database/Events/StatementPrepared.php @@ -9,7 +9,6 @@ class StatementPrepared * * @param \Illuminate\Database\Connection $connection The database connection instance. * @param \PDOStatement $statement The PDO statement. - * @return void */ public function __construct( public $connection, diff --git a/src/Illuminate/Database/Grammar.php b/src/Illuminate/Database/Grammar.php index 8b326ca22a98..d56482dc889b 100755 --- a/src/Illuminate/Database/Grammar.php +++ b/src/Illuminate/Database/Grammar.php @@ -22,7 +22,6 @@ abstract class Grammar * Create a new grammar instance. * * @param \Illuminate\Database\Connection $connection - * @return void */ public function __construct(Connection $connection) { diff --git a/src/Illuminate/Database/LazyLoadingViolationException.php b/src/Illuminate/Database/LazyLoadingViolationException.php index 36d8fec43ce2..f0a90f6c95f2 100644 --- a/src/Illuminate/Database/LazyLoadingViolationException.php +++ b/src/Illuminate/Database/LazyLoadingViolationException.php @@ -25,7 +25,6 @@ class LazyLoadingViolationException extends RuntimeException * * @param object $model * @param string $relation - * @return void */ public function __construct($model, $relation) { diff --git a/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php b/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php index c5d5252854f1..a762da81b603 100755 --- a/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php +++ b/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php @@ -32,7 +32,6 @@ class DatabaseMigrationRepository implements MigrationRepositoryInterface * * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @param string $table - * @return void */ public function __construct(Resolver $resolver, $table) { diff --git a/src/Illuminate/Database/Migrations/MigrationCreator.php b/src/Illuminate/Database/Migrations/MigrationCreator.php index 8cd08674c536..ba98eb658148 100755 --- a/src/Illuminate/Database/Migrations/MigrationCreator.php +++ b/src/Illuminate/Database/Migrations/MigrationCreator.php @@ -35,7 +35,6 @@ class MigrationCreator * * @param \Illuminate\Filesystem\Filesystem $files * @param string $customStubPath - * @return void */ public function __construct(Filesystem $files, $customStubPath) { diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 1d47edea85d0..5bfcf60db365 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -100,7 +100,6 @@ class Migrator * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @param \Illuminate\Filesystem\Filesystem $files * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher - * @return void */ public function __construct( MigrationRepositoryInterface $repository, diff --git a/src/Illuminate/Database/MultipleRecordsFoundException.php b/src/Illuminate/Database/MultipleRecordsFoundException.php index b14a8598fb73..baeee221194c 100755 --- a/src/Illuminate/Database/MultipleRecordsFoundException.php +++ b/src/Illuminate/Database/MultipleRecordsFoundException.php @@ -19,7 +19,6 @@ class MultipleRecordsFoundException extends RuntimeException * @param int $count * @param int $code * @param \Throwable|null $previous - * @return void */ public function __construct($count, $code = 0, $previous = null) { diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index be76e9754fa2..edf184d919f8 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -251,8 +251,6 @@ class Builder implements BuilderContract /** * Create a new query builder instance. - * - * @return void */ public function __construct( ConnectionInterface $connection, diff --git a/src/Illuminate/Database/Query/Expression.php b/src/Illuminate/Database/Query/Expression.php index 1da00d5e9bc1..1568e1ff9436 100755 --- a/src/Illuminate/Database/Query/Expression.php +++ b/src/Illuminate/Database/Query/Expression.php @@ -14,7 +14,6 @@ class Expression implements ExpressionContract * Create a new raw query expression. * * @param TValue $value - * @return void */ public function __construct( protected $value diff --git a/src/Illuminate/Database/Query/IndexHint.php b/src/Illuminate/Database/Query/IndexHint.php index 2a720a2dee2b..5659daa548af 100755 --- a/src/Illuminate/Database/Query/IndexHint.php +++ b/src/Illuminate/Database/Query/IndexHint.php @@ -23,7 +23,6 @@ class IndexHint * * @param string $type * @param string $index - * @return void */ public function __construct($type, $index) { diff --git a/src/Illuminate/Database/Query/JoinClause.php b/src/Illuminate/Database/Query/JoinClause.php index 37a002c57245..a9168087b254 100755 --- a/src/Illuminate/Database/Query/JoinClause.php +++ b/src/Illuminate/Database/Query/JoinClause.php @@ -54,7 +54,6 @@ class JoinClause extends Builder * @param \Illuminate\Database\Query\Builder $parentQuery * @param string $type * @param string $table - * @return void */ public function __construct(Builder $parentQuery, $type, $table) { diff --git a/src/Illuminate/Database/QueryException.php b/src/Illuminate/Database/QueryException.php index 143910029956..a83657188538 100644 --- a/src/Illuminate/Database/QueryException.php +++ b/src/Illuminate/Database/QueryException.php @@ -37,7 +37,6 @@ class QueryException extends PDOException * @param string $sql * @param array $bindings * @param \Throwable $previous - * @return void */ public function __construct($connectionName, $sql, array $bindings, Throwable $previous) { diff --git a/src/Illuminate/Database/SQLiteDatabaseDoesNotExistException.php b/src/Illuminate/Database/SQLiteDatabaseDoesNotExistException.php index f93cfe444bbb..8ea87cf39e48 100644 --- a/src/Illuminate/Database/SQLiteDatabaseDoesNotExistException.php +++ b/src/Illuminate/Database/SQLiteDatabaseDoesNotExistException.php @@ -17,7 +17,6 @@ class SQLiteDatabaseDoesNotExistException extends InvalidArgumentException * Create a new exception instance. * * @param string $path - * @return void */ public function __construct($path) { diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index f21962dd9528..b7687e839f34 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -96,7 +96,6 @@ class Blueprint * @param \Illuminate\Database\Connection $connection * @param string $table * @param \Closure|null $callback - * @return void */ public function __construct(Connection $connection, $table, ?Closure $callback = null) { diff --git a/src/Illuminate/Database/Schema/BlueprintState.php b/src/Illuminate/Database/Schema/BlueprintState.php index a43ad20b241f..a4ad1149d479 100644 --- a/src/Illuminate/Database/Schema/BlueprintState.php +++ b/src/Illuminate/Database/Schema/BlueprintState.php @@ -57,7 +57,6 @@ class BlueprintState * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Database\Connection $connection - * @return void */ public function __construct(Blueprint $blueprint, Connection $connection) { diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 5f1fa7afc69a..b37dafbd9b19 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -57,7 +57,6 @@ class Builder * Create a new database Schema manager. * * @param \Illuminate\Database\Connection $connection - * @return void */ public function __construct(Connection $connection) { diff --git a/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php b/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php index d846f88ea497..c7f66d19bb96 100644 --- a/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php +++ b/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php @@ -18,7 +18,6 @@ class ForeignIdColumnDefinition extends ColumnDefinition * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param array $attributes - * @return void */ public function __construct(Blueprint $blueprint, $attributes = []) { diff --git a/src/Illuminate/Database/Schema/SchemaState.php b/src/Illuminate/Database/Schema/SchemaState.php index d72085081487..be792138f7b4 100644 --- a/src/Illuminate/Database/Schema/SchemaState.php +++ b/src/Illuminate/Database/Schema/SchemaState.php @@ -49,7 +49,6 @@ abstract class SchemaState * @param \Illuminate\Database\Connection $connection * @param \Illuminate\Filesystem\Filesystem|null $files * @param callable|null $processFactory - * @return void */ public function __construct(Connection $connection, ?Filesystem $files = null, ?callable $processFactory = null) { diff --git a/src/Illuminate/Encryption/MissingAppKeyException.php b/src/Illuminate/Encryption/MissingAppKeyException.php index d8ffcd184b51..3f6b07b63751 100644 --- a/src/Illuminate/Encryption/MissingAppKeyException.php +++ b/src/Illuminate/Encryption/MissingAppKeyException.php @@ -10,7 +10,6 @@ class MissingAppKeyException extends RuntimeException * Create a new exception instance. * * @param string $message - * @return void */ public function __construct($message = 'No application encryption key has been specified.') { diff --git a/src/Illuminate/Events/CallQueuedListener.php b/src/Illuminate/Events/CallQueuedListener.php index dd99058c3e6f..e78a4c4e2c5f 100644 --- a/src/Illuminate/Events/CallQueuedListener.php +++ b/src/Illuminate/Events/CallQueuedListener.php @@ -88,7 +88,6 @@ class CallQueuedListener implements ShouldQueue * @param class-string $class * @param string $method * @param array $data - * @return void */ public function __construct($class, $method, $data) { diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index a039965b08e9..ee409586efc8 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -71,7 +71,6 @@ class Dispatcher implements DispatcherContract * Create a new event dispatcher instance. * * @param \Illuminate\Contracts\Container\Container|null $container - * @return void */ public function __construct(?ContainerContract $container = null) { diff --git a/src/Illuminate/Events/NullDispatcher.php b/src/Illuminate/Events/NullDispatcher.php index 4b2d01119cc7..b0c9cdf8ef6f 100644 --- a/src/Illuminate/Events/NullDispatcher.php +++ b/src/Illuminate/Events/NullDispatcher.php @@ -20,7 +20,6 @@ class NullDispatcher implements DispatcherContract * Create a new event dispatcher instance that does not fire. * * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher - * @return void */ public function __construct(DispatcherContract $dispatcher) { diff --git a/src/Illuminate/Events/QueuedClosure.php b/src/Illuminate/Events/QueuedClosure.php index 0a012eb57d9d..a1a2d63d1fbb 100644 --- a/src/Illuminate/Events/QueuedClosure.php +++ b/src/Illuminate/Events/QueuedClosure.php @@ -49,7 +49,6 @@ class QueuedClosure * Create a new queued closure event listener resolver. * * @param \Closure $closure - * @return void */ public function __construct(Closure $closure) { diff --git a/src/Illuminate/Filesystem/AwsS3V3Adapter.php b/src/Illuminate/Filesystem/AwsS3V3Adapter.php index 8e908e81aa59..7b125e2a68fe 100644 --- a/src/Illuminate/Filesystem/AwsS3V3Adapter.php +++ b/src/Illuminate/Filesystem/AwsS3V3Adapter.php @@ -25,7 +25,6 @@ class AwsS3V3Adapter extends FilesystemAdapter * @param \League\Flysystem\AwsS3V3\AwsS3V3Adapter $adapter * @param array $config * @param \Aws\S3\S3Client $client - * @return void */ public function __construct(FilesystemOperator $driver, S3Adapter $adapter, array $config, S3Client $client) { diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 234d19abfc97..50ce21f3671d 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -97,7 +97,6 @@ class FilesystemAdapter implements CloudFilesystemContract * @param \League\Flysystem\FilesystemOperator $driver * @param \League\Flysystem\FilesystemAdapter $adapter * @param array $config - * @return void */ public function __construct(FilesystemOperator $driver, FlysystemAdapter $adapter, array $config = []) { diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index c1dc70905a4e..db6f82ddca0a 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -52,7 +52,6 @@ class FilesystemManager implements FactoryContract * Create a new filesystem manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Filesystem/LockableFile.php b/src/Illuminate/Filesystem/LockableFile.php index 80a3b8a13c51..6afd33012cfd 100644 --- a/src/Illuminate/Filesystem/LockableFile.php +++ b/src/Illuminate/Filesystem/LockableFile.php @@ -32,7 +32,6 @@ class LockableFile * * @param string $path * @param string $mode - * @return void */ public function __construct($path, $mode) { diff --git a/src/Illuminate/Foundation/AliasLoader.php b/src/Illuminate/Foundation/AliasLoader.php index d46748598d5a..9c8224538483 100755 --- a/src/Illuminate/Foundation/AliasLoader.php +++ b/src/Illuminate/Foundation/AliasLoader.php @@ -36,7 +36,6 @@ class AliasLoader * Create a new AliasLoader instance. * * @param array $aliases - * @return void */ private function __construct($aliases) { diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 5e2178803d79..8758596dc519 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -212,7 +212,6 @@ class Application extends Container implements ApplicationContract, CachesConfig * Create a new Illuminate application instance. * * @param string|null $basePath - * @return void */ public function __construct($basePath = null) { diff --git a/src/Illuminate/Foundation/Bus/PendingChain.php b/src/Illuminate/Foundation/Bus/PendingChain.php index 5e02eb8a0ee1..bcb381e51617 100644 --- a/src/Illuminate/Foundation/Bus/PendingChain.php +++ b/src/Illuminate/Foundation/Bus/PendingChain.php @@ -61,7 +61,6 @@ class PendingChain * * @param mixed $job * @param array $chain - * @return void */ public function __construct($job, $chain) { diff --git a/src/Illuminate/Foundation/Bus/PendingDispatch.php b/src/Illuminate/Foundation/Bus/PendingDispatch.php index f7f2d0ed71bc..443eb5eddf5a 100644 --- a/src/Illuminate/Foundation/Bus/PendingDispatch.php +++ b/src/Illuminate/Foundation/Bus/PendingDispatch.php @@ -31,7 +31,6 @@ class PendingDispatch * Create a new pending job dispatch. * * @param mixed $job - * @return void */ public function __construct($job) { diff --git a/src/Illuminate/Foundation/CacheBasedMaintenanceMode.php b/src/Illuminate/Foundation/CacheBasedMaintenanceMode.php index 01ff30d4b6a4..630df4f3a530 100644 --- a/src/Illuminate/Foundation/CacheBasedMaintenanceMode.php +++ b/src/Illuminate/Foundation/CacheBasedMaintenanceMode.php @@ -35,7 +35,6 @@ class CacheBasedMaintenanceMode implements MaintenanceMode * @param \Illuminate\Contracts\Cache\Factory $cache * @param string $store * @param string $key - * @return void */ public function __construct(Factory $cache, string $store, string $key) { diff --git a/src/Illuminate/Foundation/Configuration/Exceptions.php b/src/Illuminate/Foundation/Configuration/Exceptions.php index b02753abe4c0..1072a1431196 100644 --- a/src/Illuminate/Foundation/Configuration/Exceptions.php +++ b/src/Illuminate/Foundation/Configuration/Exceptions.php @@ -13,7 +13,6 @@ class Exceptions * Create a new exception handling configuration instance. * * @param \Illuminate\Foundation\Exceptions\Handler $handler - * @return void */ public function __construct(public Handler $handler) { diff --git a/src/Illuminate/Foundation/Console/AboutCommand.php b/src/Illuminate/Foundation/Console/AboutCommand.php index 77de686f958f..c6d61b6d8303 100644 --- a/src/Illuminate/Foundation/Console/AboutCommand.php +++ b/src/Illuminate/Foundation/Console/AboutCommand.php @@ -53,7 +53,6 @@ class AboutCommand extends Command * Create a new command instance. * * @param \Illuminate\Support\Composer $composer - * @return void */ public function __construct(Composer $composer) { diff --git a/src/Illuminate/Foundation/Console/CliDumper.php b/src/Illuminate/Foundation/Console/CliDumper.php index 6f5fd9a49886..44cddcb1e204 100644 --- a/src/Illuminate/Foundation/Console/CliDumper.php +++ b/src/Illuminate/Foundation/Console/CliDumper.php @@ -48,7 +48,6 @@ class CliDumper extends BaseCliDumper * @param \Symfony\Component\Console\Output\OutputInterface $output * @param string $basePath * @param string $compiledViewPath - * @return void */ public function __construct($output, $basePath, $compiledViewPath) { diff --git a/src/Illuminate/Foundation/Console/ClosureCommand.php b/src/Illuminate/Foundation/Console/ClosureCommand.php index 2c2eaf4d2744..a9817d4df22d 100644 --- a/src/Illuminate/Foundation/Console/ClosureCommand.php +++ b/src/Illuminate/Foundation/Console/ClosureCommand.php @@ -30,7 +30,6 @@ class ClosureCommand extends Command * * @param string $signature * @param \Closure $callback - * @return void */ public function __construct($signature, Closure $callback) { diff --git a/src/Illuminate/Foundation/Console/ConfigCacheCommand.php b/src/Illuminate/Foundation/Console/ConfigCacheCommand.php index 1de90e95839e..6cef3389ea64 100644 --- a/src/Illuminate/Foundation/Console/ConfigCacheCommand.php +++ b/src/Illuminate/Foundation/Console/ConfigCacheCommand.php @@ -37,7 +37,6 @@ class ConfigCacheCommand extends Command * Create a new config cache command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/ConfigClearCommand.php b/src/Illuminate/Foundation/Console/ConfigClearCommand.php index 47a978244a1f..e88e2432c034 100644 --- a/src/Illuminate/Foundation/Console/ConfigClearCommand.php +++ b/src/Illuminate/Foundation/Console/ConfigClearCommand.php @@ -34,7 +34,6 @@ class ConfigClearCommand extends Command * Create a new config clear command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php b/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php index 945d0781b389..1146489800c9 100644 --- a/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php +++ b/src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php @@ -46,7 +46,6 @@ class EnvironmentDecryptCommand extends Command * Create a new command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php b/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php index 1cbfbd59841c..a66d18f058db 100644 --- a/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php +++ b/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php @@ -45,7 +45,6 @@ class EnvironmentEncryptCommand extends Command * Create a new command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/EventClearCommand.php b/src/Illuminate/Foundation/Console/EventClearCommand.php index 966a18bcc3b2..61c503308609 100644 --- a/src/Illuminate/Foundation/Console/EventClearCommand.php +++ b/src/Illuminate/Foundation/Console/EventClearCommand.php @@ -34,7 +34,6 @@ class EventClearCommand extends Command * Create a new config clear command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index e798169ea765..55874df4d9b0 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -131,7 +131,6 @@ class Kernel implements KernelContract * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Contracts\Events\Dispatcher $events - * @return void */ public function __construct(Application $app, Dispatcher $events) { diff --git a/src/Illuminate/Foundation/Console/QueuedCommand.php b/src/Illuminate/Foundation/Console/QueuedCommand.php index 43848cc263e3..eef9cacc8754 100644 --- a/src/Illuminate/Foundation/Console/QueuedCommand.php +++ b/src/Illuminate/Foundation/Console/QueuedCommand.php @@ -22,7 +22,6 @@ class QueuedCommand implements ShouldQueue * Create a new job instance. * * @param array $data - * @return void */ public function __construct($data) { diff --git a/src/Illuminate/Foundation/Console/RouteCacheCommand.php b/src/Illuminate/Foundation/Console/RouteCacheCommand.php index 0aa21941edfa..9b8632af50b2 100644 --- a/src/Illuminate/Foundation/Console/RouteCacheCommand.php +++ b/src/Illuminate/Foundation/Console/RouteCacheCommand.php @@ -36,7 +36,6 @@ class RouteCacheCommand extends Command * Create a new route command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/RouteClearCommand.php b/src/Illuminate/Foundation/Console/RouteClearCommand.php index c496b10e73fc..b077f820076c 100644 --- a/src/Illuminate/Foundation/Console/RouteClearCommand.php +++ b/src/Illuminate/Foundation/Console/RouteClearCommand.php @@ -34,7 +34,6 @@ class RouteClearCommand extends Command * Create a new route clear command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index 5f735925ed04..36813d87d1a5 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -76,7 +76,6 @@ class RouteListCommand extends Command * Create a new route command instance. * * @param \Illuminate\Routing\Router $router - * @return void */ public function __construct(Router $router) { diff --git a/src/Illuminate/Foundation/Console/VendorPublishCommand.php b/src/Illuminate/Foundation/Console/VendorPublishCommand.php index 3921c9ca05f5..1ccab52ec83b 100644 --- a/src/Illuminate/Foundation/Console/VendorPublishCommand.php +++ b/src/Illuminate/Foundation/Console/VendorPublishCommand.php @@ -79,7 +79,6 @@ class VendorPublishCommand extends Command * Create a new command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Console/ViewClearCommand.php b/src/Illuminate/Foundation/Console/ViewClearCommand.php index 9cb58e23bf99..ec942bddb998 100644 --- a/src/Illuminate/Foundation/Console/ViewClearCommand.php +++ b/src/Illuminate/Foundation/Console/ViewClearCommand.php @@ -35,7 +35,6 @@ class ViewClearCommand extends Command * Create a new config clear command instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/Foundation/Events/LocaleUpdated.php b/src/Illuminate/Foundation/Events/LocaleUpdated.php index 0a932be06ed2..c46d33ccc245 100644 --- a/src/Illuminate/Foundation/Events/LocaleUpdated.php +++ b/src/Illuminate/Foundation/Events/LocaleUpdated.php @@ -15,7 +15,6 @@ class LocaleUpdated * Create a new event instance. * * @param string $locale - * @return void */ public function __construct($locale) { diff --git a/src/Illuminate/Foundation/Events/PublishingStubs.php b/src/Illuminate/Foundation/Events/PublishingStubs.php index 914ff1e40d65..854327982ed4 100644 --- a/src/Illuminate/Foundation/Events/PublishingStubs.php +++ b/src/Illuminate/Foundation/Events/PublishingStubs.php @@ -17,7 +17,6 @@ class PublishingStubs * Create a new event instance. * * @param array $stubs - * @return void */ public function __construct(array $stubs) { diff --git a/src/Illuminate/Foundation/Events/VendorTagPublished.php b/src/Illuminate/Foundation/Events/VendorTagPublished.php index 084c1293fcfd..05acc79cd70a 100644 --- a/src/Illuminate/Foundation/Events/VendorTagPublished.php +++ b/src/Illuminate/Foundation/Events/VendorTagPublished.php @@ -23,7 +23,6 @@ class VendorTagPublished * * @param string $tag * @param array $paths - * @return void */ public function __construct($tag, $paths) { diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index a4b773c4a43f..00a69266dcc7 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -184,7 +184,6 @@ class Handler implements ExceptionHandlerContract * Create a new exception handler instance. * * @param \Illuminate\Contracts\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Foundation/Exceptions/Renderer/Exception.php b/src/Illuminate/Foundation/Exceptions/Renderer/Exception.php index 3c562e05578c..eb65929f3150 100644 --- a/src/Illuminate/Foundation/Exceptions/Renderer/Exception.php +++ b/src/Illuminate/Foundation/Exceptions/Renderer/Exception.php @@ -47,7 +47,6 @@ class Exception * @param \Illuminate\Http\Request $request * @param \Illuminate\Foundation\Exceptions\Renderer\Listener $listener * @param string $basePath - * @return void */ public function __construct(FlattenException $exception, Request $request, Listener $listener, string $basePath) { diff --git a/src/Illuminate/Foundation/Exceptions/Renderer/Frame.php b/src/Illuminate/Foundation/Exceptions/Renderer/Frame.php index ac331d7a2ec9..efd6d7a62f63 100644 --- a/src/Illuminate/Foundation/Exceptions/Renderer/Frame.php +++ b/src/Illuminate/Foundation/Exceptions/Renderer/Frame.php @@ -44,7 +44,6 @@ class Frame * @param array $classMap * @param array{file: string, line: int, class?: string, type?: string, function?: string} $frame * @param string $basePath - * @return void */ public function __construct(FlattenException $exception, array $classMap, array $frame, string $basePath) { diff --git a/src/Illuminate/Foundation/Exceptions/Renderer/Mappers/BladeMapper.php b/src/Illuminate/Foundation/Exceptions/Renderer/Mappers/BladeMapper.php index 25b6b71377ac..a235812cb3fe 100644 --- a/src/Illuminate/Foundation/Exceptions/Renderer/Mappers/BladeMapper.php +++ b/src/Illuminate/Foundation/Exceptions/Renderer/Mappers/BladeMapper.php @@ -63,7 +63,6 @@ class BladeMapper * * @param \Illuminate\Contracts\View\Factory $factory * @param \Illuminate\View\Compilers\BladeCompiler $bladeCompiler - * @return void */ public function __construct(Factory $factory, BladeCompiler $bladeCompiler) { diff --git a/src/Illuminate/Foundation/Exceptions/Renderer/Renderer.php b/src/Illuminate/Foundation/Exceptions/Renderer/Renderer.php index 6772ae1d18ca..514be710840e 100644 --- a/src/Illuminate/Foundation/Exceptions/Renderer/Renderer.php +++ b/src/Illuminate/Foundation/Exceptions/Renderer/Renderer.php @@ -61,7 +61,6 @@ class Renderer * @param \Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer $htmlErrorRenderer * @param \Illuminate\Foundation\Exceptions\Renderer\Mappers\BladeMapper $bladeMapper * @param string $basePath - * @return void */ public function __construct( Factory $viewFactory, diff --git a/src/Illuminate/Foundation/Exceptions/ReportableHandler.php b/src/Illuminate/Foundation/Exceptions/ReportableHandler.php index 06a6172f5c03..f7193654e250 100644 --- a/src/Illuminate/Foundation/Exceptions/ReportableHandler.php +++ b/src/Illuminate/Foundation/Exceptions/ReportableHandler.php @@ -27,7 +27,6 @@ class ReportableHandler * Create a new reportable handler instance. * * @param callable $callback - * @return void */ public function __construct(callable $callback) { diff --git a/src/Illuminate/Foundation/Http/Events/RequestHandled.php b/src/Illuminate/Foundation/Http/Events/RequestHandled.php index d6f71e03fa16..3e99cb8321f3 100644 --- a/src/Illuminate/Foundation/Http/Events/RequestHandled.php +++ b/src/Illuminate/Foundation/Http/Events/RequestHandled.php @@ -23,7 +23,6 @@ class RequestHandled * * @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Response $response - * @return void */ public function __construct($request, $response) { diff --git a/src/Illuminate/Foundation/Http/HtmlDumper.php b/src/Illuminate/Foundation/Http/HtmlDumper.php index 2df09013fe65..72663f0ec1b6 100644 --- a/src/Illuminate/Foundation/Http/HtmlDumper.php +++ b/src/Illuminate/Foundation/Http/HtmlDumper.php @@ -53,7 +53,6 @@ class HtmlDumper extends BaseHtmlDumper * * @param string $basePath * @param string $compiledViewPath - * @return void */ public function __construct($basePath, $compiledViewPath) { diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index 02c0f3fdbd95..83a5ae42780c 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -119,7 +119,6 @@ class Kernel implements KernelContract * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Routing\Router $router - * @return void */ public function __construct(Application $app, Router $router) { diff --git a/src/Illuminate/Foundation/Http/Middleware/HandlePrecognitiveRequests.php b/src/Illuminate/Foundation/Http/Middleware/HandlePrecognitiveRequests.php index 32819c45a663..c13e2bf12277 100644 --- a/src/Illuminate/Foundation/Http/Middleware/HandlePrecognitiveRequests.php +++ b/src/Illuminate/Foundation/Http/Middleware/HandlePrecognitiveRequests.php @@ -21,7 +21,6 @@ class HandlePrecognitiveRequests * Create a new middleware instance. * * @param \Illuminate\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php b/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php index 1f0b22981e5a..1c20d22051b1 100644 --- a/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php +++ b/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php @@ -39,7 +39,6 @@ class PreventRequestsDuringMaintenance * Create a new middleware instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct(Application $app) { diff --git a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php index 5edc53d38f57..7a47b4fbe471 100644 --- a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php +++ b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php @@ -60,7 +60,6 @@ class VerifyCsrfToken * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter - * @return void */ public function __construct(Application $app, Encrypter $encrypter) { diff --git a/src/Illuminate/Foundation/PackageManifest.php b/src/Illuminate/Foundation/PackageManifest.php index c3f66ba69ab1..d2494db25993 100644 --- a/src/Illuminate/Foundation/PackageManifest.php +++ b/src/Illuminate/Foundation/PackageManifest.php @@ -50,7 +50,6 @@ class PackageManifest * @param \Illuminate\Filesystem\Filesystem $files * @param string $basePath * @param string $manifestPath - * @return void */ public function __construct(Filesystem $files, $basePath, $manifestPath) { diff --git a/src/Illuminate/Foundation/ProviderRepository.php b/src/Illuminate/Foundation/ProviderRepository.php index 75d382d83d29..df76e054bb41 100755 --- a/src/Illuminate/Foundation/ProviderRepository.php +++ b/src/Illuminate/Foundation/ProviderRepository.php @@ -35,7 +35,6 @@ class ProviderRepository * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Filesystem\Filesystem $files * @param string $manifestPath - * @return void */ public function __construct(ApplicationContract $app, Filesystem $files, $manifestPath) { diff --git a/src/Illuminate/Foundation/Testing/DatabaseTransactionsManager.php b/src/Illuminate/Foundation/Testing/DatabaseTransactionsManager.php index 7ee71d7b9edf..4fea491d51b1 100644 --- a/src/Illuminate/Foundation/Testing/DatabaseTransactionsManager.php +++ b/src/Illuminate/Foundation/Testing/DatabaseTransactionsManager.php @@ -15,7 +15,6 @@ class DatabaseTransactionsManager extends BaseManager * Create a new database transaction manager instance. * * @param array $connectionsTransacting - * @return void */ public function __construct(array $connectionsTransacting) { diff --git a/src/Illuminate/Foundation/Testing/Wormhole.php b/src/Illuminate/Foundation/Testing/Wormhole.php index beac013ab34c..3bf5d2e89af3 100644 --- a/src/Illuminate/Foundation/Testing/Wormhole.php +++ b/src/Illuminate/Foundation/Testing/Wormhole.php @@ -17,7 +17,6 @@ class Wormhole * Create a new wormhole instance. * * @param int $value - * @return void */ public function __construct($value) { diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index 233480ea5fb5..74ff9301ed7b 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -40,7 +40,6 @@ class ArgonHasher extends AbstractHasher implements HasherContract * Create a new hasher instance. * * @param array $options - * @return void */ public function __construct(array $options = []) { diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index 18df9c221a38..efe0c50aa44b 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -34,7 +34,6 @@ class BcryptHasher extends AbstractHasher implements HasherContract * Create a new hasher instance. * * @param array $options - * @return void */ public function __construct(array $options = []) { diff --git a/src/Illuminate/Http/Client/Events/ConnectionFailed.php b/src/Illuminate/Http/Client/Events/ConnectionFailed.php index 0906ad40f91a..94c829e56452 100644 --- a/src/Illuminate/Http/Client/Events/ConnectionFailed.php +++ b/src/Illuminate/Http/Client/Events/ConnectionFailed.php @@ -26,7 +26,6 @@ class ConnectionFailed * * @param \Illuminate\Http\Client\Request $request * @param \Illuminate\Http\Client\ConnectionException $exception - * @return void */ public function __construct(Request $request, ConnectionException $exception) { diff --git a/src/Illuminate/Http/Client/Events/RequestSending.php b/src/Illuminate/Http/Client/Events/RequestSending.php index 1b363fb751b3..f92c5c1438c0 100644 --- a/src/Illuminate/Http/Client/Events/RequestSending.php +++ b/src/Illuminate/Http/Client/Events/RequestSending.php @@ -17,7 +17,6 @@ class RequestSending * Create a new event instance. * * @param \Illuminate\Http\Client\Request $request - * @return void */ public function __construct(Request $request) { diff --git a/src/Illuminate/Http/Client/Events/ResponseReceived.php b/src/Illuminate/Http/Client/Events/ResponseReceived.php index 77be7aba7662..82db448371ff 100644 --- a/src/Illuminate/Http/Client/Events/ResponseReceived.php +++ b/src/Illuminate/Http/Client/Events/ResponseReceived.php @@ -26,7 +26,6 @@ class ResponseReceived * * @param \Illuminate\Http\Client\Request $request * @param \Illuminate\Http\Client\Response $response - * @return void */ public function __construct(Request $request, Response $response) { diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 61376e556904..559868655519 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -84,7 +84,6 @@ class Factory * Create a new factory instance. * * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher - * @return void */ public function __construct(?Dispatcher $dispatcher = null) { diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index cf87583e3264..08d64d8e4ad0 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -220,7 +220,6 @@ class PendingRequest * * @param \Illuminate\Http\Client\Factory|null $factory * @param array $middleware - * @return void */ public function __construct(?Factory $factory = null, $middleware = []) { diff --git a/src/Illuminate/Http/Client/Pool.php b/src/Illuminate/Http/Client/Pool.php index b5f00258fbab..aba741f4bf75 100644 --- a/src/Illuminate/Http/Client/Pool.php +++ b/src/Illuminate/Http/Client/Pool.php @@ -34,7 +34,6 @@ class Pool * Create a new requests pool. * * @param \Illuminate\Http\Client\Factory|null $factory - * @return void */ public function __construct(?Factory $factory = null) { diff --git a/src/Illuminate/Http/Client/Request.php b/src/Illuminate/Http/Client/Request.php index 7c0132a35f85..7e6891221864 100644 --- a/src/Illuminate/Http/Client/Request.php +++ b/src/Illuminate/Http/Client/Request.php @@ -30,7 +30,6 @@ class Request implements ArrayAccess * Create a new request instance. * * @param \Psr\Http\Message\RequestInterface $request - * @return void */ public function __construct($request) { diff --git a/src/Illuminate/Http/Client/RequestException.php b/src/Illuminate/Http/Client/RequestException.php index 0fccaee9563c..a72f12873594 100644 --- a/src/Illuminate/Http/Client/RequestException.php +++ b/src/Illuminate/Http/Client/RequestException.php @@ -24,7 +24,6 @@ class RequestException extends HttpClientException * Create a new exception instance. * * @param \Illuminate\Http\Client\Response $response - * @return void */ public function __construct(Response $response) { diff --git a/src/Illuminate/Http/Client/Response.php b/src/Illuminate/Http/Client/Response.php index 97a6cacea7c3..c2352bb01f81 100644 --- a/src/Illuminate/Http/Client/Response.php +++ b/src/Illuminate/Http/Client/Response.php @@ -51,7 +51,6 @@ class Response implements ArrayAccess, Stringable * Create a new response instance. * * @param \Psr\Http\Message\MessageInterface $response - * @return void */ public function __construct($response) { diff --git a/src/Illuminate/Http/Client/ResponseSequence.php b/src/Illuminate/Http/Client/ResponseSequence.php index e35736b05d99..23ac08511d4c 100644 --- a/src/Illuminate/Http/Client/ResponseSequence.php +++ b/src/Illuminate/Http/Client/ResponseSequence.php @@ -35,7 +35,6 @@ class ResponseSequence * Create a new response sequence. * * @param array $responses - * @return void */ public function __construct(array $responses) { diff --git a/src/Illuminate/Http/Exceptions/HttpResponseException.php b/src/Illuminate/Http/Exceptions/HttpResponseException.php index c45268680aeb..eeafe3205d60 100644 --- a/src/Illuminate/Http/Exceptions/HttpResponseException.php +++ b/src/Illuminate/Http/Exceptions/HttpResponseException.php @@ -20,7 +20,6 @@ class HttpResponseException extends RuntimeException * * @param \Symfony\Component\HttpFoundation\Response $response * @param \Throwable $previous - * @return void */ public function __construct(Response $response, ?Throwable $previous = null) { diff --git a/src/Illuminate/Http/Exceptions/MalformedUrlException.php b/src/Illuminate/Http/Exceptions/MalformedUrlException.php index c5aa86d418be..c720997d18b0 100644 --- a/src/Illuminate/Http/Exceptions/MalformedUrlException.php +++ b/src/Illuminate/Http/Exceptions/MalformedUrlException.php @@ -8,8 +8,6 @@ class MalformedUrlException extends HttpException { /** * Create a new exception instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Http/Exceptions/PostTooLargeException.php b/src/Illuminate/Http/Exceptions/PostTooLargeException.php index 560b8af411b0..e317448f02bb 100644 --- a/src/Illuminate/Http/Exceptions/PostTooLargeException.php +++ b/src/Illuminate/Http/Exceptions/PostTooLargeException.php @@ -14,7 +14,6 @@ class PostTooLargeException extends HttpException * @param \Throwable|null $previous * @param array $headers * @param int $code - * @return void */ public function __construct($message = '', ?Throwable $previous = null, array $headers = [], $code = 0) { diff --git a/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php b/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php index 98dc78ddbd3e..bbfd0c9c254c 100644 --- a/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php +++ b/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php @@ -14,7 +14,6 @@ class ThrottleRequestsException extends TooManyRequestsHttpException * @param \Throwable|null $previous * @param array $headers * @param int $code - * @return void */ public function __construct($message = '', ?Throwable $previous = null, array $headers = [], $code = 0) { diff --git a/src/Illuminate/Http/JsonResponse.php b/src/Illuminate/Http/JsonResponse.php index dd5ce0ef5f25..f604b86d30ae 100755 --- a/src/Illuminate/Http/JsonResponse.php +++ b/src/Illuminate/Http/JsonResponse.php @@ -23,7 +23,6 @@ class JsonResponse extends BaseJsonResponse * @param array $headers * @param int $options * @param bool $json - * @return void */ public function __construct($data = null, $status = 200, $headers = [], $options = 0, $json = false) { diff --git a/src/Illuminate/Http/Middleware/HandleCors.php b/src/Illuminate/Http/Middleware/HandleCors.php index eee030511e39..a417deb2b305 100644 --- a/src/Illuminate/Http/Middleware/HandleCors.php +++ b/src/Illuminate/Http/Middleware/HandleCors.php @@ -28,7 +28,6 @@ class HandleCors * * @param \Illuminate\Contracts\Container\Container $container * @param \Fruitcake\Cors\CorsService $cors - * @return void */ public function __construct(Container $container, CorsService $cors) { diff --git a/src/Illuminate/Http/Middleware/TrustHosts.php b/src/Illuminate/Http/Middleware/TrustHosts.php index 8eae16d1cec0..b0bb3b5c06a8 100644 --- a/src/Illuminate/Http/Middleware/TrustHosts.php +++ b/src/Illuminate/Http/Middleware/TrustHosts.php @@ -32,7 +32,6 @@ class TrustHosts * Create a new middleware instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct(Application $app) { diff --git a/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php b/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php index 26f5c460ce63..ba8c087f1194 100644 --- a/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php +++ b/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php @@ -23,7 +23,6 @@ class AnonymousResourceCollection extends ResourceCollection * * @param mixed $resource * @param string $collects - * @return void */ public function __construct($resource, $collects) { diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index 30b9425b08fb..7007507bbe45 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -53,7 +53,6 @@ class JsonResource implements ArrayAccess, JsonSerializable, Responsable, UrlRou * Create a new resource instance. * * @param mixed $resource - * @return void */ public function __construct($resource) { diff --git a/src/Illuminate/Http/Resources/Json/ResourceCollection.php b/src/Illuminate/Http/Resources/Json/ResourceCollection.php index af86849fec1d..81cfc1bd3181 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceCollection.php +++ b/src/Illuminate/Http/Resources/Json/ResourceCollection.php @@ -45,7 +45,6 @@ class ResourceCollection extends JsonResource implements Countable, IteratorAggr * Create a new resource instance. * * @param mixed $resource - * @return void */ public function __construct($resource) { diff --git a/src/Illuminate/Http/Resources/Json/ResourceResponse.php b/src/Illuminate/Http/Resources/Json/ResourceResponse.php index 430e41a72950..4e4f9d3e1313 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceResponse.php +++ b/src/Illuminate/Http/Resources/Json/ResourceResponse.php @@ -19,7 +19,6 @@ class ResourceResponse implements Responsable * Create a new resource response. * * @param mixed $resource - * @return void */ public function __construct($resource) { diff --git a/src/Illuminate/Http/Resources/MergeValue.php b/src/Illuminate/Http/Resources/MergeValue.php index fb6880fb725c..2cd963ef6ffb 100644 --- a/src/Illuminate/Http/Resources/MergeValue.php +++ b/src/Illuminate/Http/Resources/MergeValue.php @@ -18,7 +18,6 @@ class MergeValue * Create a new merge value instance. * * @param \Illuminate\Support\Collection|\JsonSerializable|array $data - * @return void */ public function __construct($data) { diff --git a/src/Illuminate/Http/StreamedEvent.php b/src/Illuminate/Http/StreamedEvent.php index e6defe52f8ee..5dd3c5707113 100644 --- a/src/Illuminate/Http/StreamedEvent.php +++ b/src/Illuminate/Http/StreamedEvent.php @@ -16,8 +16,6 @@ class StreamedEvent /** * Create a new streamed event instance. - * - * @return void */ public function __construct(string $event, mixed $data) { diff --git a/src/Illuminate/Http/Testing/File.php b/src/Illuminate/Http/Testing/File.php index aaba539cfbb5..fbdc7f3ed253 100644 --- a/src/Illuminate/Http/Testing/File.php +++ b/src/Illuminate/Http/Testing/File.php @@ -39,7 +39,6 @@ class File extends UploadedFile * * @param string $name * @param resource $tempFile - * @return void */ public function __construct($name, $tempFile) { diff --git a/src/Illuminate/Log/Events/MessageLogged.php b/src/Illuminate/Log/Events/MessageLogged.php index 312b343a356d..b3458815af5d 100644 --- a/src/Illuminate/Log/Events/MessageLogged.php +++ b/src/Illuminate/Log/Events/MessageLogged.php @@ -31,7 +31,6 @@ class MessageLogged * @param string $level * @param string $message * @param array $context - * @return void */ public function __construct($level, $message, array $context = []) { diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index de67c44057f8..f6a8b7cf0765 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -69,7 +69,6 @@ class LogManager implements LoggerInterface * Create a new Log manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Log/Logger.php b/src/Illuminate/Log/Logger.php index c94bf5bae249..f14536c7ccd7 100755 --- a/src/Illuminate/Log/Logger.php +++ b/src/Illuminate/Log/Logger.php @@ -41,7 +41,6 @@ class Logger implements LoggerInterface * * @param \Psr\Log\LoggerInterface $logger * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher - * @return void */ public function __construct(LoggerInterface $logger, ?Dispatcher $dispatcher = null) { diff --git a/src/Illuminate/Mail/Attachment.php b/src/Illuminate/Mail/Attachment.php index cdf601e8c02f..f49d32cc1e78 100644 --- a/src/Illuminate/Mail/Attachment.php +++ b/src/Illuminate/Mail/Attachment.php @@ -37,7 +37,6 @@ class Attachment * Create a mail attachment. * * @param \Closure $resolver - * @return void */ private function __construct(Closure $resolver) { diff --git a/src/Illuminate/Mail/Events/MessageSending.php b/src/Illuminate/Mail/Events/MessageSending.php index 3353a43c26dc..7215b14a265a 100644 --- a/src/Illuminate/Mail/Events/MessageSending.php +++ b/src/Illuminate/Mail/Events/MessageSending.php @@ -11,7 +11,6 @@ class MessageSending * * @param \Symfony\Component\Mime\Email $message The Symfony Email instance. * @param array $data The message data. - * @return void */ public function __construct( public Email $message, diff --git a/src/Illuminate/Mail/Events/MessageSent.php b/src/Illuminate/Mail/Events/MessageSent.php index 1634676aa02d..8a5ae558cb36 100644 --- a/src/Illuminate/Mail/Events/MessageSent.php +++ b/src/Illuminate/Mail/Events/MessageSent.php @@ -16,7 +16,6 @@ class MessageSent * * @param \Illuminate\Mail\SentMessage $sent The message that was sent. * @param array $data The message data. - * @return void */ public function __construct( public SentMessage $sent, diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index e6589e8827f8..2fc790361b80 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -59,7 +59,6 @@ class MailManager implements FactoryContract * Create a new Mail manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Mail/Mailables/Address.php b/src/Illuminate/Mail/Mailables/Address.php index 7a9ed2aa66cd..6a03e920e78d 100644 --- a/src/Illuminate/Mail/Mailables/Address.php +++ b/src/Illuminate/Mail/Mailables/Address.php @@ -23,7 +23,6 @@ class Address * * @param string $address * @param string|null $name - * @return void */ public function __construct(string $address, ?string $name = null) { diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index 864f09b45270..b0d3b75bfc80 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -95,7 +95,6 @@ class Mailer implements MailerContract, MailQueueContract * @param \Illuminate\Contracts\View\Factory $views * @param \Symfony\Component\Mailer\Transport\TransportInterface $transport * @param \Illuminate\Contracts\Events\Dispatcher|null $events - * @return void */ public function __construct(string $name, Factory $views, TransportInterface $transport, ?Dispatcher $events = null) { diff --git a/src/Illuminate/Mail/Markdown.php b/src/Illuminate/Mail/Markdown.php index 8faf739eb393..06d123ed3858 100644 --- a/src/Illuminate/Mail/Markdown.php +++ b/src/Illuminate/Mail/Markdown.php @@ -39,7 +39,6 @@ class Markdown * * @param \Illuminate\Contracts\View\Factory $view * @param array $options - * @return void */ public function __construct(ViewFactory $view, array $options = []) { diff --git a/src/Illuminate/Mail/Message.php b/src/Illuminate/Mail/Message.php index e5392dd52f8f..b9a4eb5352ca 100755 --- a/src/Illuminate/Mail/Message.php +++ b/src/Illuminate/Mail/Message.php @@ -38,7 +38,6 @@ class Message * Create a new message instance. * * @param \Symfony\Component\Mime\Email $message - * @return void */ public function __construct(Email $message) { diff --git a/src/Illuminate/Mail/PendingMail.php b/src/Illuminate/Mail/PendingMail.php index 1aa3d9a6cc2f..0523cac3db95 100644 --- a/src/Illuminate/Mail/PendingMail.php +++ b/src/Illuminate/Mail/PendingMail.php @@ -50,7 +50,6 @@ class PendingMail * Create a new mailable mailer instance. * * @param \Illuminate\Contracts\Mail\Mailer $mailer - * @return void */ public function __construct(MailerContract $mailer) { diff --git a/src/Illuminate/Mail/SendQueuedMailable.php b/src/Illuminate/Mail/SendQueuedMailable.php index b9fec9d03849..a5342da41f50 100644 --- a/src/Illuminate/Mail/SendQueuedMailable.php +++ b/src/Illuminate/Mail/SendQueuedMailable.php @@ -52,7 +52,6 @@ class SendQueuedMailable * Create a new job instance. * * @param \Illuminate\Contracts\Mail\Mailable $mailable - * @return void */ public function __construct(MailableContract $mailable) { diff --git a/src/Illuminate/Mail/SentMessage.php b/src/Illuminate/Mail/SentMessage.php index c33f87edc724..036b695e7f5a 100644 --- a/src/Illuminate/Mail/SentMessage.php +++ b/src/Illuminate/Mail/SentMessage.php @@ -24,7 +24,6 @@ class SentMessage * Create a new SentMessage instance. * * @param \Symfony\Component\Mailer\SentMessage $sentMessage - * @return void */ public function __construct(SymfonySentMessage $sentMessage) { diff --git a/src/Illuminate/Mail/TextMessage.php b/src/Illuminate/Mail/TextMessage.php index 5c615d2cfe58..ba81e3421968 100644 --- a/src/Illuminate/Mail/TextMessage.php +++ b/src/Illuminate/Mail/TextMessage.php @@ -22,7 +22,6 @@ class TextMessage * Create a new text message instance. * * @param \Illuminate\Mail\Message $message - * @return void */ public function __construct($message) { diff --git a/src/Illuminate/Mail/Transport/ArrayTransport.php b/src/Illuminate/Mail/Transport/ArrayTransport.php index 67da10780663..ae690f8b5a0e 100644 --- a/src/Illuminate/Mail/Transport/ArrayTransport.php +++ b/src/Illuminate/Mail/Transport/ArrayTransport.php @@ -20,8 +20,6 @@ class ArrayTransport implements Stringable, TransportInterface /** * Create a new array transport instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Mail/Transport/LogTransport.php b/src/Illuminate/Mail/Transport/LogTransport.php index 2dff1490fea5..90ba275bb202 100644 --- a/src/Illuminate/Mail/Transport/LogTransport.php +++ b/src/Illuminate/Mail/Transport/LogTransport.php @@ -23,7 +23,6 @@ class LogTransport implements Stringable, TransportInterface * Create a new log transport instance. * * @param \Psr\Log\LoggerInterface $logger - * @return void */ public function __construct(LoggerInterface $logger) { diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index daa3be18991e..f5dbd69e0a94 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -33,7 +33,6 @@ class SesTransport extends AbstractTransport implements Stringable * * @param \Aws\Ses\SesClient $ses * @param array $options - * @return void */ public function __construct(SesClient $ses, $options = []) { diff --git a/src/Illuminate/Mail/Transport/SesV2Transport.php b/src/Illuminate/Mail/Transport/SesV2Transport.php index ab47b44b3ea8..ff918dc3bad9 100644 --- a/src/Illuminate/Mail/Transport/SesV2Transport.php +++ b/src/Illuminate/Mail/Transport/SesV2Transport.php @@ -33,7 +33,6 @@ class SesV2Transport extends AbstractTransport implements Stringable * * @param \Aws\SesV2\SesV2Client $ses * @param array $options - * @return void */ public function __construct(SesV2Client $ses, $options = []) { diff --git a/src/Illuminate/Notifications/Action.php b/src/Illuminate/Notifications/Action.php index 071db2d9efdc..f59f86836d1a 100644 --- a/src/Illuminate/Notifications/Action.php +++ b/src/Illuminate/Notifications/Action.php @@ -23,7 +23,6 @@ class Action * * @param string $text * @param string $url - * @return void */ public function __construct($text, $url) { diff --git a/src/Illuminate/Notifications/Channels/BroadcastChannel.php b/src/Illuminate/Notifications/Channels/BroadcastChannel.php index 14739d8eb9d8..cc51f7188b46 100644 --- a/src/Illuminate/Notifications/Channels/BroadcastChannel.php +++ b/src/Illuminate/Notifications/Channels/BroadcastChannel.php @@ -21,7 +21,6 @@ class BroadcastChannel * Create a new broadcast channel. * * @param \Illuminate\Contracts\Events\Dispatcher $events - * @return void */ public function __construct(Dispatcher $events) { diff --git a/src/Illuminate/Notifications/Channels/MailChannel.php b/src/Illuminate/Notifications/Channels/MailChannel.php index 81215f3b0348..ffc23b9008ec 100644 --- a/src/Illuminate/Notifications/Channels/MailChannel.php +++ b/src/Illuminate/Notifications/Channels/MailChannel.php @@ -36,7 +36,6 @@ class MailChannel * * @param \Illuminate\Contracts\Mail\Factory $mailer * @param \Illuminate\Mail\Markdown $markdown - * @return void */ public function __construct(MailFactory $mailer, Markdown $markdown) { diff --git a/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php b/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php index 43f205e3efb0..ad4e730e1221 100644 --- a/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php +++ b/src/Illuminate/Notifications/Events/BroadcastNotificationCreated.php @@ -20,7 +20,6 @@ class BroadcastNotificationCreated implements ShouldBroadcast * @param mixed $notifiable The notifiable entity who received the notification. * @param \Illuminate\Notifications\Notification $notification The notification instance. * @param array $data The notification data. - * @return void */ public function __construct( public $notifiable, diff --git a/src/Illuminate/Notifications/Events/NotificationFailed.php b/src/Illuminate/Notifications/Events/NotificationFailed.php index b550333642bc..544c3b53b152 100644 --- a/src/Illuminate/Notifications/Events/NotificationFailed.php +++ b/src/Illuminate/Notifications/Events/NotificationFailed.php @@ -16,7 +16,6 @@ class NotificationFailed * @param \Illuminate\Notifications\Notification $notification The notification instance. * @param string $channel The channel name. * @param array $data The data needed to process this failure. - * @return void */ public function __construct( public $notifiable, diff --git a/src/Illuminate/Notifications/Events/NotificationSending.php b/src/Illuminate/Notifications/Events/NotificationSending.php index 2f4972a383db..42a7aeb8ac35 100644 --- a/src/Illuminate/Notifications/Events/NotificationSending.php +++ b/src/Illuminate/Notifications/Events/NotificationSending.php @@ -15,7 +15,6 @@ class NotificationSending * @param mixed $notifiable The notifiable entity who received the notification. * @param \Illuminate\Notifications\Notification $notification The notification instance. * @param string $channel The channel name. - * @return void */ public function __construct( public $notifiable, diff --git a/src/Illuminate/Notifications/Events/NotificationSent.php b/src/Illuminate/Notifications/Events/NotificationSent.php index 8c7cd8190c4b..8868b393154d 100644 --- a/src/Illuminate/Notifications/Events/NotificationSent.php +++ b/src/Illuminate/Notifications/Events/NotificationSent.php @@ -16,7 +16,6 @@ class NotificationSent * @param \Illuminate\Notifications\Notification $notification The notification instance. * @param string $channel The channel name. * @param mixed $response The channel's response. - * @return void */ public function __construct( public $notifiable, diff --git a/src/Illuminate/Notifications/Messages/BroadcastMessage.php b/src/Illuminate/Notifications/Messages/BroadcastMessage.php index 9884a8fbb382..810984296273 100644 --- a/src/Illuminate/Notifications/Messages/BroadcastMessage.php +++ b/src/Illuminate/Notifications/Messages/BroadcastMessage.php @@ -19,7 +19,6 @@ class BroadcastMessage * Create a new message instance. * * @param array $data - * @return void */ public function __construct(array $data) { diff --git a/src/Illuminate/Notifications/Messages/DatabaseMessage.php b/src/Illuminate/Notifications/Messages/DatabaseMessage.php index 55707a7c065f..d0ef936d6c1c 100644 --- a/src/Illuminate/Notifications/Messages/DatabaseMessage.php +++ b/src/Illuminate/Notifications/Messages/DatabaseMessage.php @@ -15,7 +15,6 @@ class DatabaseMessage * Create a new database message. * * @param array $data - * @return void */ public function __construct(array $data = []) { diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index ed08deac0e0e..c7e75fd851b2 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -51,7 +51,6 @@ class NotificationSender * @param \Illuminate\Contracts\Bus\Dispatcher $bus * @param \Illuminate\Contracts\Events\Dispatcher $events * @param string|null $locale - * @return void */ public function __construct($manager, $bus, $events, $locale = null) { diff --git a/src/Illuminate/Notifications/SendQueuedNotifications.php b/src/Illuminate/Notifications/SendQueuedNotifications.php index 3eca3cccea90..bdd6fc8b4729 100644 --- a/src/Illuminate/Notifications/SendQueuedNotifications.php +++ b/src/Illuminate/Notifications/SendQueuedNotifications.php @@ -71,7 +71,6 @@ class SendQueuedNotifications implements ShouldQueue * @param \Illuminate\Notifications\Notifiable|\Illuminate\Support\Collection $notifiables * @param \Illuminate\Notifications\Notification $notification * @param array|null $channels - * @return void */ public function __construct($notifiables, $notification, ?array $channels = null) { diff --git a/src/Illuminate/Pagination/CursorPaginator.php b/src/Illuminate/Pagination/CursorPaginator.php index 1a5e08e92ec9..e68281086ab8 100644 --- a/src/Illuminate/Pagination/CursorPaginator.php +++ b/src/Illuminate/Pagination/CursorPaginator.php @@ -39,7 +39,6 @@ class CursorPaginator extends AbstractCursorPaginator implements Arrayable, Arra * @param int $perPage * @param \Illuminate\Pagination\Cursor|null $cursor * @param array $options (path, query, fragment, pageName) - * @return void */ public function __construct($items, $perPage, $cursor = null, array $options = []) { diff --git a/src/Illuminate/Pagination/LengthAwarePaginator.php b/src/Illuminate/Pagination/LengthAwarePaginator.php index 6cde4aa4571c..2a6fd8d2149c 100644 --- a/src/Illuminate/Pagination/LengthAwarePaginator.php +++ b/src/Illuminate/Pagination/LengthAwarePaginator.php @@ -47,7 +47,6 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array * @param int $perPage * @param int|null $currentPage * @param array $options (path, query, fragment, pageName) - * @return void */ public function __construct($items, $total, $perPage, $currentPage = null, array $options = []) { diff --git a/src/Illuminate/Pagination/Paginator.php b/src/Illuminate/Pagination/Paginator.php index c2bc470be576..489b58fc2a8f 100644 --- a/src/Illuminate/Pagination/Paginator.php +++ b/src/Illuminate/Pagination/Paginator.php @@ -39,7 +39,6 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou * @param int $perPage * @param int|null $currentPage * @param array $options (path, query, fragment, pageName) - * @return void */ public function __construct($items, $perPage, $currentPage = null, array $options = []) { diff --git a/src/Illuminate/Pagination/UrlWindow.php b/src/Illuminate/Pagination/UrlWindow.php index 99286f7b3b8e..863d4c598c48 100644 --- a/src/Illuminate/Pagination/UrlWindow.php +++ b/src/Illuminate/Pagination/UrlWindow.php @@ -17,7 +17,6 @@ class UrlWindow * Create a new URL window instance. * * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator - * @return void */ public function __construct(PaginatorContract $paginator) { diff --git a/src/Illuminate/Pipeline/Hub.php b/src/Illuminate/Pipeline/Hub.php index 6f284fe7ae19..0f738a62ae4a 100644 --- a/src/Illuminate/Pipeline/Hub.php +++ b/src/Illuminate/Pipeline/Hub.php @@ -26,7 +26,6 @@ class Hub implements HubContract * Create a new Hub instance. * * @param \Illuminate\Contracts\Container\Container|null $container - * @return void */ public function __construct(?Container $container = null) { diff --git a/src/Illuminate/Pipeline/Pipeline.php b/src/Illuminate/Pipeline/Pipeline.php index 28f2b4084a2c..294d0d456161 100644 --- a/src/Illuminate/Pipeline/Pipeline.php +++ b/src/Illuminate/Pipeline/Pipeline.php @@ -52,7 +52,6 @@ class Pipeline implements PipelineContract * Create a new class instance. * * @param \Illuminate\Contracts\Container\Container|null $container - * @return void */ public function __construct(?Container $container = null) { diff --git a/src/Illuminate/Process/Exceptions/ProcessFailedException.php b/src/Illuminate/Process/Exceptions/ProcessFailedException.php index 6747c11867b3..c4a311864976 100644 --- a/src/Illuminate/Process/Exceptions/ProcessFailedException.php +++ b/src/Illuminate/Process/Exceptions/ProcessFailedException.php @@ -18,7 +18,6 @@ class ProcessFailedException extends RuntimeException * Create a new exception instance. * * @param \Illuminate\Contracts\Process\ProcessResult $result - * @return void */ public function __construct(ProcessResult $result) { diff --git a/src/Illuminate/Process/Exceptions/ProcessTimedOutException.php b/src/Illuminate/Process/Exceptions/ProcessTimedOutException.php index 5f939f8356a9..9c3c8988a7cb 100644 --- a/src/Illuminate/Process/Exceptions/ProcessTimedOutException.php +++ b/src/Illuminate/Process/Exceptions/ProcessTimedOutException.php @@ -20,7 +20,6 @@ class ProcessTimedOutException extends RuntimeException * * @param \Symfony\Component\Process\Exception\ProcessTimedOutException $original * @param \Illuminate\Contracts\Process\ProcessResult $result - * @return void */ public function __construct(SymfonyTimeoutException $original, ProcessResult $result) { diff --git a/src/Illuminate/Process/FakeInvokedProcess.php b/src/Illuminate/Process/FakeInvokedProcess.php index c74928e77c18..461511e433b2 100644 --- a/src/Illuminate/Process/FakeInvokedProcess.php +++ b/src/Illuminate/Process/FakeInvokedProcess.php @@ -60,7 +60,6 @@ class FakeInvokedProcess implements InvokedProcessContract * * @param string $command * @param \Illuminate\Process\FakeProcessDescription $process - * @return void */ public function __construct(string $command, FakeProcessDescription $process) { diff --git a/src/Illuminate/Process/FakeProcessResult.php b/src/Illuminate/Process/FakeProcessResult.php index 665f77865dd2..abb6a34755fa 100644 --- a/src/Illuminate/Process/FakeProcessResult.php +++ b/src/Illuminate/Process/FakeProcessResult.php @@ -43,7 +43,6 @@ class FakeProcessResult implements ProcessResultContract * @param int $exitCode * @param array|string $output * @param array|string $errorOutput - * @return void */ public function __construct(string $command = '', int $exitCode = 0, array|string $output = '', array|string $errorOutput = '') { diff --git a/src/Illuminate/Process/FakeProcessSequence.php b/src/Illuminate/Process/FakeProcessSequence.php index 02f9f4623777..6015309aa733 100644 --- a/src/Illuminate/Process/FakeProcessSequence.php +++ b/src/Illuminate/Process/FakeProcessSequence.php @@ -32,7 +32,6 @@ class FakeProcessSequence * Create a new fake process sequence instance. * * @param array $processes - * @return void */ public function __construct(array $processes = []) { diff --git a/src/Illuminate/Process/InvokedProcess.php b/src/Illuminate/Process/InvokedProcess.php index c93f6bfba0c5..6e2e9a84612b 100644 --- a/src/Illuminate/Process/InvokedProcess.php +++ b/src/Illuminate/Process/InvokedProcess.php @@ -20,7 +20,6 @@ class InvokedProcess implements InvokedProcessContract * Create a new invoked process instance. * * @param \Symfony\Component\Process\Process $process - * @return void */ public function __construct(Process $process) { diff --git a/src/Illuminate/Process/InvokedProcessPool.php b/src/Illuminate/Process/InvokedProcessPool.php index eb3df2130194..67b0d3d90277 100644 --- a/src/Illuminate/Process/InvokedProcessPool.php +++ b/src/Illuminate/Process/InvokedProcessPool.php @@ -18,7 +18,6 @@ class InvokedProcessPool implements Countable * Create a new invoked process pool. * * @param array $invokedProcesses - * @return void */ public function __construct(array $invokedProcesses) { diff --git a/src/Illuminate/Process/PendingProcess.php b/src/Illuminate/Process/PendingProcess.php index 3ce34e6222a7..90d324e7c74e 100644 --- a/src/Illuminate/Process/PendingProcess.php +++ b/src/Illuminate/Process/PendingProcess.php @@ -97,7 +97,6 @@ class PendingProcess * Create a new pending process instance. * * @param \Illuminate\Process\Factory $factory - * @return void */ public function __construct(Factory $factory) { diff --git a/src/Illuminate/Process/Pipe.php b/src/Illuminate/Process/Pipe.php index 06e7e16598e8..043ddb77e776 100644 --- a/src/Illuminate/Process/Pipe.php +++ b/src/Illuminate/Process/Pipe.php @@ -37,7 +37,6 @@ class Pipe * * @param \Illuminate\Process\Factory $factory * @param callable $callback - * @return void */ public function __construct(Factory $factory, callable $callback) { diff --git a/src/Illuminate/Process/Pool.php b/src/Illuminate/Process/Pool.php index 3e274d84c783..77d4b249ef01 100644 --- a/src/Illuminate/Process/Pool.php +++ b/src/Illuminate/Process/Pool.php @@ -37,7 +37,6 @@ class Pool * * @param \Illuminate\Process\Factory $factory * @param callable $callback - * @return void */ public function __construct(Factory $factory, callable $callback) { diff --git a/src/Illuminate/Process/ProcessPoolResults.php b/src/Illuminate/Process/ProcessPoolResults.php index debd3e09db6e..106aa94d54fc 100644 --- a/src/Illuminate/Process/ProcessPoolResults.php +++ b/src/Illuminate/Process/ProcessPoolResults.php @@ -18,7 +18,6 @@ class ProcessPoolResults implements ArrayAccess * Create a new process pool result set. * * @param array $results - * @return void */ public function __construct(array $results) { diff --git a/src/Illuminate/Process/ProcessResult.php b/src/Illuminate/Process/ProcessResult.php index 9bbf9c4aacc5..49900f537fab 100644 --- a/src/Illuminate/Process/ProcessResult.php +++ b/src/Illuminate/Process/ProcessResult.php @@ -19,7 +19,6 @@ class ProcessResult implements ProcessResultContract * Create a new process result instance. * * @param \Symfony\Component\Process\Process $process - * @return void */ public function __construct(Process $process) { diff --git a/src/Illuminate/Queue/BeanstalkdQueue.php b/src/Illuminate/Queue/BeanstalkdQueue.php index c13dc1c97e76..d1f64e982492 100755 --- a/src/Illuminate/Queue/BeanstalkdQueue.php +++ b/src/Illuminate/Queue/BeanstalkdQueue.php @@ -48,7 +48,6 @@ class BeanstalkdQueue extends Queue implements QueueContract * @param int $timeToRun * @param int $blockFor * @param bool $dispatchAfterCommit - * @return void */ public function __construct( $pheanstalk, diff --git a/src/Illuminate/Queue/CallQueuedClosure.php b/src/Illuminate/Queue/CallQueuedClosure.php index cdf5435171b6..732600ccfea1 100644 --- a/src/Illuminate/Queue/CallQueuedClosure.php +++ b/src/Illuminate/Queue/CallQueuedClosure.php @@ -40,7 +40,6 @@ class CallQueuedClosure implements ShouldQueue * Create a new job instance. * * @param \Laravel\SerializableClosure\SerializableClosure $closure - * @return void */ public function __construct($closure) { diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index c767fea8db47..0da7e735ca39 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -41,7 +41,6 @@ class CallQueuedHandler * * @param \Illuminate\Contracts\Bus\Dispatcher $dispatcher * @param \Illuminate\Contracts\Container\Container $container - * @return void */ public function __construct(Dispatcher $dispatcher, Container $container) { diff --git a/src/Illuminate/Queue/Capsule/Manager.php b/src/Illuminate/Queue/Capsule/Manager.php index f6c263d17c6b..d8927032b861 100644 --- a/src/Illuminate/Queue/Capsule/Manager.php +++ b/src/Illuminate/Queue/Capsule/Manager.php @@ -26,7 +26,6 @@ class Manager * Create a new queue capsule manager. * * @param \Illuminate\Container\Container|null $container - * @return void */ public function __construct(?Container $container = null) { diff --git a/src/Illuminate/Queue/Connectors/DatabaseConnector.php b/src/Illuminate/Queue/Connectors/DatabaseConnector.php index eeabc8ee7f7f..9dc970b02bef 100644 --- a/src/Illuminate/Queue/Connectors/DatabaseConnector.php +++ b/src/Illuminate/Queue/Connectors/DatabaseConnector.php @@ -18,7 +18,6 @@ class DatabaseConnector implements ConnectorInterface * Create a new connector instance. * * @param \Illuminate\Database\ConnectionResolverInterface $connections - * @return void */ public function __construct(ConnectionResolverInterface $connections) { diff --git a/src/Illuminate/Queue/Connectors/RedisConnector.php b/src/Illuminate/Queue/Connectors/RedisConnector.php index d442eea99f11..ed5235fa3047 100644 --- a/src/Illuminate/Queue/Connectors/RedisConnector.php +++ b/src/Illuminate/Queue/Connectors/RedisConnector.php @@ -26,7 +26,6 @@ class RedisConnector implements ConnectorInterface * * @param \Illuminate\Contracts\Redis\Factory $redis * @param string|null $connection - * @return void */ public function __construct(Redis $redis, $connection = null) { diff --git a/src/Illuminate/Queue/Console/ListenCommand.php b/src/Illuminate/Queue/Console/ListenCommand.php index 9f1b4f7d5a9f..eb545a1d7234 100755 --- a/src/Illuminate/Queue/Console/ListenCommand.php +++ b/src/Illuminate/Queue/Console/ListenCommand.php @@ -47,7 +47,6 @@ class ListenCommand extends Command * Create a new queue listen command. * * @param \Illuminate\Queue\Listener $listener - * @return void */ public function __construct(Listener $listener) { diff --git a/src/Illuminate/Queue/Console/MonitorCommand.php b/src/Illuminate/Queue/Console/MonitorCommand.php index c3df987a4c4e..466a09501bc0 100644 --- a/src/Illuminate/Queue/Console/MonitorCommand.php +++ b/src/Illuminate/Queue/Console/MonitorCommand.php @@ -47,7 +47,6 @@ class MonitorCommand extends Command * * @param \Illuminate\Contracts\Queue\Factory $manager * @param \Illuminate\Contracts\Events\Dispatcher $events - * @return void */ public function __construct(Factory $manager, Dispatcher $events) { diff --git a/src/Illuminate/Queue/Console/RestartCommand.php b/src/Illuminate/Queue/Console/RestartCommand.php index 7ade21a02eeb..892380682528 100644 --- a/src/Illuminate/Queue/Console/RestartCommand.php +++ b/src/Illuminate/Queue/Console/RestartCommand.php @@ -37,7 +37,6 @@ class RestartCommand extends Command * Create a new queue restart command. * * @param \Illuminate\Contracts\Cache\Repository $cache - * @return void */ public function __construct(Cache $cache) { diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index 09a45544b071..a03e63e91468 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -89,7 +89,6 @@ class WorkCommand extends Command * * @param \Illuminate\Queue\Worker $worker * @param \Illuminate\Contracts\Cache\Repository $cache - * @return void */ public function __construct(Worker $worker, Cache $cache) { diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index 41533f084217..0e6163a2c265 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -51,7 +51,6 @@ class DatabaseQueue extends Queue implements QueueContract, ClearableQueue * @param string $default * @param int $retryAfter * @param bool $dispatchAfterCommit - * @return void */ public function __construct( Connection $database, diff --git a/src/Illuminate/Queue/Events/JobAttempted.php b/src/Illuminate/Queue/Events/JobAttempted.php index b2303143c77d..b10c62903e77 100644 --- a/src/Illuminate/Queue/Events/JobAttempted.php +++ b/src/Illuminate/Queue/Events/JobAttempted.php @@ -10,7 +10,6 @@ class JobAttempted * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @param bool $exceptionOccurred Indicates if an exception occurred while processing the job. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobExceptionOccurred.php b/src/Illuminate/Queue/Events/JobExceptionOccurred.php index 301bd524f86b..3d4661710033 100644 --- a/src/Illuminate/Queue/Events/JobExceptionOccurred.php +++ b/src/Illuminate/Queue/Events/JobExceptionOccurred.php @@ -10,7 +10,6 @@ class JobExceptionOccurred * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @param \Throwable $exception The exception instance. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobFailed.php b/src/Illuminate/Queue/Events/JobFailed.php index a39fdedad592..0c616fdcf95a 100644 --- a/src/Illuminate/Queue/Events/JobFailed.php +++ b/src/Illuminate/Queue/Events/JobFailed.php @@ -10,7 +10,6 @@ class JobFailed * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. * @param \Throwable $exception The exception that caused the job to fail. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobPopped.php b/src/Illuminate/Queue/Events/JobPopped.php index ca907a8c7dff..eeda0c8cd9a8 100644 --- a/src/Illuminate/Queue/Events/JobPopped.php +++ b/src/Illuminate/Queue/Events/JobPopped.php @@ -9,7 +9,6 @@ class JobPopped * * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job|null $job The job instance. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobPopping.php b/src/Illuminate/Queue/Events/JobPopping.php index 1eb5fd6970a7..6ac966695dd2 100644 --- a/src/Illuminate/Queue/Events/JobPopping.php +++ b/src/Illuminate/Queue/Events/JobPopping.php @@ -8,7 +8,6 @@ class JobPopping * Create a new event instance. * * @param string $connectionName The connection name. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobProcessed.php b/src/Illuminate/Queue/Events/JobProcessed.php index e7b8ce17c068..0c3db8264ccd 100644 --- a/src/Illuminate/Queue/Events/JobProcessed.php +++ b/src/Illuminate/Queue/Events/JobProcessed.php @@ -9,7 +9,6 @@ class JobProcessed * * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobProcessing.php b/src/Illuminate/Queue/Events/JobProcessing.php index a48cc15aa195..4c1bf8bbee8f 100644 --- a/src/Illuminate/Queue/Events/JobProcessing.php +++ b/src/Illuminate/Queue/Events/JobProcessing.php @@ -9,7 +9,6 @@ class JobProcessing * * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobQueued.php b/src/Illuminate/Queue/Events/JobQueued.php index 599b9da7a18e..2418171ac9f8 100644 --- a/src/Illuminate/Queue/Events/JobQueued.php +++ b/src/Illuminate/Queue/Events/JobQueued.php @@ -13,7 +13,6 @@ class JobQueued * @param \Closure|string|object $job The job instance. * @param string $payload The job payload. * @param int|null $delay The amount of time the job was delayed. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobQueueing.php b/src/Illuminate/Queue/Events/JobQueueing.php index ed6815a34d30..5cc3e449d0cf 100644 --- a/src/Illuminate/Queue/Events/JobQueueing.php +++ b/src/Illuminate/Queue/Events/JobQueueing.php @@ -12,7 +12,6 @@ class JobQueueing * @param \Closure|string|object $job The job instance. * @param string $payload The job payload. * @param int|null $delay The number of seconds the job was delayed. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobReleasedAfterException.php b/src/Illuminate/Queue/Events/JobReleasedAfterException.php index b2271ed4134a..7dc248084832 100644 --- a/src/Illuminate/Queue/Events/JobReleasedAfterException.php +++ b/src/Illuminate/Queue/Events/JobReleasedAfterException.php @@ -9,7 +9,6 @@ class JobReleasedAfterException * * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/JobRetryRequested.php b/src/Illuminate/Queue/Events/JobRetryRequested.php index 99bd8d40c38f..929b4a89e4d8 100644 --- a/src/Illuminate/Queue/Events/JobRetryRequested.php +++ b/src/Illuminate/Queue/Events/JobRetryRequested.php @@ -15,7 +15,6 @@ class JobRetryRequested * Create a new event instance. * * @param \stdClass $job The job instance. - * @return void */ public function __construct( public $job, diff --git a/src/Illuminate/Queue/Events/JobTimedOut.php b/src/Illuminate/Queue/Events/JobTimedOut.php index 2b5e43650df0..4ef5f2ad5cc9 100644 --- a/src/Illuminate/Queue/Events/JobTimedOut.php +++ b/src/Illuminate/Queue/Events/JobTimedOut.php @@ -9,7 +9,6 @@ class JobTimedOut * * @param string $connectionName The connection name. * @param \Illuminate\Contracts\Queue\Job $job The job instance. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/Looping.php b/src/Illuminate/Queue/Events/Looping.php index f8056e453afa..84088c3107b2 100644 --- a/src/Illuminate/Queue/Events/Looping.php +++ b/src/Illuminate/Queue/Events/Looping.php @@ -9,7 +9,6 @@ class Looping * * @param string $connectionName The connection name. * @param string $queue The queue name. - * @return void */ public function __construct( public $connectionName, diff --git a/src/Illuminate/Queue/Events/QueueBusy.php b/src/Illuminate/Queue/Events/QueueBusy.php index a563ec0545fc..7219c2f9702d 100644 --- a/src/Illuminate/Queue/Events/QueueBusy.php +++ b/src/Illuminate/Queue/Events/QueueBusy.php @@ -10,7 +10,6 @@ class QueueBusy * @param string $connection The connection name. * @param string $queue The queue name. * @param int $size The size of the queue. - * @return void */ public function __construct( public $connection, diff --git a/src/Illuminate/Queue/Events/WorkerStopping.php b/src/Illuminate/Queue/Events/WorkerStopping.php index 6d862bac3c25..ae38a3d2c786 100644 --- a/src/Illuminate/Queue/Events/WorkerStopping.php +++ b/src/Illuminate/Queue/Events/WorkerStopping.php @@ -9,7 +9,6 @@ class WorkerStopping * * @param int $status The worker exit status. * @param \Illuminate\Queue\WorkerOptions|null $workerOptions The worker options. - * @return void */ public function __construct( public $status = 0, diff --git a/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php b/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php index 49cb3b98ae9a..be34d642d0b3 100644 --- a/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php @@ -35,7 +35,6 @@ class DatabaseFailedJobProvider implements CountableFailedJobProvider, FailedJob * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @param string $database * @param string $table - * @return void */ public function __construct(ConnectionResolverInterface $resolver, $database, $table) { diff --git a/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php b/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php index b3192f246beb..2eb47255d3f4 100644 --- a/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php @@ -35,7 +35,6 @@ class DatabaseUuidFailedJobProvider implements CountableFailedJobProvider, Faile * @param \Illuminate\Database\ConnectionResolverInterface $resolver * @param string $database * @param string $table - * @return void */ public function __construct(ConnectionResolverInterface $resolver, $database, $table) { diff --git a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php index c76a55ca8b1c..86c1635ab477 100644 --- a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php @@ -38,7 +38,6 @@ class DynamoDbFailedJobProvider implements FailedJobProviderInterface * @param \Aws\DynamoDb\DynamoDbClient $dynamo * @param string $applicationName * @param string $table - * @return void */ public function __construct(DynamoDbClient $dynamo, $applicationName, $table) { diff --git a/src/Illuminate/Queue/Failed/FileFailedJobProvider.php b/src/Illuminate/Queue/Failed/FileFailedJobProvider.php index 61f66657654d..20faf2f90530 100644 --- a/src/Illuminate/Queue/Failed/FileFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/FileFailedJobProvider.php @@ -36,7 +36,6 @@ class FileFailedJobProvider implements CountableFailedJobProvider, FailedJobProv * @param string $path * @param int $limit * @param \Closure|null $lockProviderResolver - * @return void */ public function __construct($path, $limit = 100, ?Closure $lockProviderResolver = null) { diff --git a/src/Illuminate/Queue/InvalidPayloadException.php b/src/Illuminate/Queue/InvalidPayloadException.php index abaf21f508f1..52cc4a2b9dfd 100644 --- a/src/Illuminate/Queue/InvalidPayloadException.php +++ b/src/Illuminate/Queue/InvalidPayloadException.php @@ -18,7 +18,6 @@ class InvalidPayloadException extends InvalidArgumentException * * @param string|null $message * @param mixed $value - * @return void */ public function __construct($message = null, $value = null) { diff --git a/src/Illuminate/Queue/Jobs/BeanstalkdJob.php b/src/Illuminate/Queue/Jobs/BeanstalkdJob.php index 10d0b3627c1d..52da72b41bca 100755 --- a/src/Illuminate/Queue/Jobs/BeanstalkdJob.php +++ b/src/Illuminate/Queue/Jobs/BeanstalkdJob.php @@ -31,7 +31,6 @@ class BeanstalkdJob extends Job implements JobContract * @param \Pheanstalk\Contract\JobIdInterface $job * @param string $connectionName * @param string $queue - * @return void */ public function __construct(Container $container, $pheanstalk, JobIdInterface $job, $connectionName, $queue) { diff --git a/src/Illuminate/Queue/Jobs/DatabaseJob.php b/src/Illuminate/Queue/Jobs/DatabaseJob.php index 77f50427d5eb..8fdb41801752 100644 --- a/src/Illuminate/Queue/Jobs/DatabaseJob.php +++ b/src/Illuminate/Queue/Jobs/DatabaseJob.php @@ -30,7 +30,6 @@ class DatabaseJob extends Job implements JobContract * @param \stdClass $job * @param string $connectionName * @param string $queue - * @return void */ public function __construct(Container $container, DatabaseQueue $database, $job, $connectionName, $queue) { diff --git a/src/Illuminate/Queue/Jobs/DatabaseJobRecord.php b/src/Illuminate/Queue/Jobs/DatabaseJobRecord.php index b4b5725467ef..207f2b529c82 100644 --- a/src/Illuminate/Queue/Jobs/DatabaseJobRecord.php +++ b/src/Illuminate/Queue/Jobs/DatabaseJobRecord.php @@ -19,7 +19,6 @@ class DatabaseJobRecord * Create a new job record instance. * * @param \stdClass $record - * @return void */ public function __construct($record) { diff --git a/src/Illuminate/Queue/Jobs/RedisJob.php b/src/Illuminate/Queue/Jobs/RedisJob.php index 1486ebcf9d9c..8fe55b03dbd4 100644 --- a/src/Illuminate/Queue/Jobs/RedisJob.php +++ b/src/Illuminate/Queue/Jobs/RedisJob.php @@ -45,7 +45,6 @@ class RedisJob extends Job implements JobContract * @param string $reserved * @param string $connectionName * @param string $queue - * @return void */ public function __construct(Container $container, RedisQueue $redis, $job, $reserved, $connectionName, $queue) { diff --git a/src/Illuminate/Queue/Jobs/SqsJob.php b/src/Illuminate/Queue/Jobs/SqsJob.php index 87b722e207b9..227c1b7b0ac1 100755 --- a/src/Illuminate/Queue/Jobs/SqsJob.php +++ b/src/Illuminate/Queue/Jobs/SqsJob.php @@ -30,7 +30,6 @@ class SqsJob extends Job implements JobContract * @param array $job * @param string $connectionName * @param string $queue - * @return void */ public function __construct(Container $container, SqsClient $sqs, array $job, $connectionName, $queue) { diff --git a/src/Illuminate/Queue/Jobs/SyncJob.php b/src/Illuminate/Queue/Jobs/SyncJob.php index fc9c7030fb59..a682fc962ae2 100755 --- a/src/Illuminate/Queue/Jobs/SyncJob.php +++ b/src/Illuminate/Queue/Jobs/SyncJob.php @@ -28,7 +28,6 @@ class SyncJob extends Job implements JobContract * @param string $payload * @param string $connectionName * @param string $queue - * @return void */ public function __construct(Container $container, $payload, $connectionName, $queue) { diff --git a/src/Illuminate/Queue/Listener.php b/src/Illuminate/Queue/Listener.php index de037d324297..fc56a569ebaa 100755 --- a/src/Illuminate/Queue/Listener.php +++ b/src/Illuminate/Queue/Listener.php @@ -49,7 +49,6 @@ class Listener * Create a new queue listener. * * @param string $commandPath - * @return void */ public function __construct($commandPath) { diff --git a/src/Illuminate/Queue/ListenerOptions.php b/src/Illuminate/Queue/ListenerOptions.php index d71989d90294..218a49851dea 100644 --- a/src/Illuminate/Queue/ListenerOptions.php +++ b/src/Illuminate/Queue/ListenerOptions.php @@ -23,7 +23,6 @@ class ListenerOptions extends WorkerOptions * @param int $maxTries * @param bool $force * @param int $rest - * @return void */ public function __construct($name = 'default', $environment = null, $backoff = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 1, $force = false, $rest = 0) { diff --git a/src/Illuminate/Queue/Middleware/RateLimited.php b/src/Illuminate/Queue/Middleware/RateLimited.php index 8612c634a8ef..1b4b2b78d941 100644 --- a/src/Illuminate/Queue/Middleware/RateLimited.php +++ b/src/Illuminate/Queue/Middleware/RateLimited.php @@ -36,7 +36,6 @@ class RateLimited * Create a new middleware instance. * * @param \BackedEnum|\UnitEnum|string $limiterName - * @return void */ public function __construct($limiterName) { diff --git a/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php b/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php index cbc809549333..bb87b101d404 100644 --- a/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php +++ b/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php @@ -29,7 +29,6 @@ class RateLimitedWithRedis extends RateLimited * Create a new middleware instance. * * @param string $limiterName - * @return void */ public function __construct($limiterName) { diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index 0b6baf05b645..68017795655c 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -76,7 +76,6 @@ class ThrottlesExceptions * * @param int $maxAttempts * @param int $decaySeconds - * @return void */ public function __construct($maxAttempts = 10, $decaySeconds = 600) { diff --git a/src/Illuminate/Queue/Middleware/WithoutOverlapping.php b/src/Illuminate/Queue/Middleware/WithoutOverlapping.php index 3b773adf43b9..42fabdaa3303 100644 --- a/src/Illuminate/Queue/Middleware/WithoutOverlapping.php +++ b/src/Illuminate/Queue/Middleware/WithoutOverlapping.php @@ -51,7 +51,6 @@ class WithoutOverlapping * @param string $key * @param \DateTimeInterface|int|null $releaseAfter * @param \DateTimeInterface|int $expiresAfter - * @return void */ public function __construct($key = '', $releaseAfter = 0, $expiresAfter = 0) { diff --git a/src/Illuminate/Queue/QueueManager.php b/src/Illuminate/Queue/QueueManager.php index 399b66bc8729..a809a736df00 100755 --- a/src/Illuminate/Queue/QueueManager.php +++ b/src/Illuminate/Queue/QueueManager.php @@ -37,7 +37,6 @@ class QueueManager implements FactoryContract, MonitorContract * Create a new queue manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Queue/RedisQueue.php b/src/Illuminate/Queue/RedisQueue.php index 9e7c1c908886..e8d6d77c7a51 100644 --- a/src/Illuminate/Queue/RedisQueue.php +++ b/src/Illuminate/Queue/RedisQueue.php @@ -75,7 +75,6 @@ class RedisQueue extends Queue implements QueueContract, ClearableQueue * @param int|null $blockFor * @param bool $dispatchAfterCommit * @param int $migrationBatchSize - * @return void */ public function __construct( Redis $redis, diff --git a/src/Illuminate/Queue/SqsQueue.php b/src/Illuminate/Queue/SqsQueue.php index f840f7cf0e38..0d74b8dda43f 100755 --- a/src/Illuminate/Queue/SqsQueue.php +++ b/src/Illuminate/Queue/SqsQueue.php @@ -46,7 +46,6 @@ class SqsQueue extends Queue implements QueueContract, ClearableQueue * @param string $prefix * @param string $suffix * @param bool $dispatchAfterCommit - * @return void */ public function __construct( SqsClient $sqs, diff --git a/src/Illuminate/Queue/SyncQueue.php b/src/Illuminate/Queue/SyncQueue.php index 57974960d4bb..873146da9fe4 100755 --- a/src/Illuminate/Queue/SyncQueue.php +++ b/src/Illuminate/Queue/SyncQueue.php @@ -16,7 +16,6 @@ class SyncQueue extends Queue implements QueueContract * Create a new sync queue instance. * * @param bool $dispatchAfterCommit - * @return void */ public function __construct($dispatchAfterCommit = false) { diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 3f8fe38b9b82..6ac69dcf5ec8 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -106,7 +106,6 @@ class Worker * @param \Illuminate\Contracts\Debug\ExceptionHandler $exceptions * @param callable $isDownForMaintenance * @param callable|null $resetScope - * @return void */ public function __construct( QueueManager $manager, diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index e3206bd7d9e9..036168b39e70 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -95,7 +95,6 @@ class WorkerOptions * @param int $maxJobs * @param int $maxTime * @param int $rest - * @return void */ public function __construct( $name = 'default', diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index bf7c9e2949c5..a0448f2e270b 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -35,7 +35,6 @@ class PhpRedisConnection extends Connection implements ConnectionContract * @param \Redis $client * @param callable|null $connector * @param array $config - * @return void */ public function __construct($client, ?callable $connector = null, array $config = []) { diff --git a/src/Illuminate/Redis/Connections/PredisConnection.php b/src/Illuminate/Redis/Connections/PredisConnection.php index 2a44c19fb4f0..1f6ec698627f 100644 --- a/src/Illuminate/Redis/Connections/PredisConnection.php +++ b/src/Illuminate/Redis/Connections/PredisConnection.php @@ -23,7 +23,6 @@ class PredisConnection extends Connection implements ConnectionContract * Create a new Predis connection. * * @param \Predis\Client $client - * @return void */ public function __construct($client) { diff --git a/src/Illuminate/Redis/Events/CommandExecuted.php b/src/Illuminate/Redis/Events/CommandExecuted.php index fa65719af02a..dacd7c6914f4 100644 --- a/src/Illuminate/Redis/Events/CommandExecuted.php +++ b/src/Illuminate/Redis/Events/CommandExecuted.php @@ -46,7 +46,6 @@ class CommandExecuted * @param array $parameters * @param float|null $time * @param \Illuminate\Redis\Connections\Connection $connection - * @return void */ public function __construct($command, $parameters, $time, $connection) { diff --git a/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php b/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php index 62e50b01aad1..02c17870862a 100644 --- a/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php +++ b/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php @@ -44,7 +44,6 @@ class ConcurrencyLimiter * @param string $name * @param int $maxLocks * @param int $releaseAfter - * @return void */ public function __construct($redis, $name, $maxLocks, $releaseAfter) { diff --git a/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php b/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php index 8ff02768297f..aee3df80f281 100644 --- a/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php +++ b/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php @@ -56,7 +56,6 @@ class ConcurrencyLimiterBuilder * * @param \Illuminate\Redis\Connections\Connection $connection * @param string $name - * @return void */ public function __construct($connection, $name) { diff --git a/src/Illuminate/Redis/Limiters/DurationLimiter.php b/src/Illuminate/Redis/Limiters/DurationLimiter.php index b0ecdaf9f4b4..e6c66c30957c 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiter.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiter.php @@ -56,7 +56,6 @@ class DurationLimiter * @param string $name * @param int $maxLocks * @param int $decay - * @return void */ public function __construct($redis, $name, $maxLocks, $decay) { diff --git a/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php b/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php index 8eedc1177c58..013469079b44 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php @@ -56,7 +56,6 @@ class DurationLimiterBuilder * * @param \Illuminate\Redis\Connections\Connection $connection * @param string $name - * @return void */ public function __construct($connection, $name) { diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 4c4f3b876623..7910c9468bbe 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -64,7 +64,6 @@ class RedisManager implements Factory * @param \Illuminate\Contracts\Foundation\Application $app * @param string $driver * @param array $config - * @return void */ public function __construct($app, $driver, array $config) { diff --git a/src/Illuminate/Routing/CallableDispatcher.php b/src/Illuminate/Routing/CallableDispatcher.php index 737e76dfed7a..7e63e54dd9f4 100644 --- a/src/Illuminate/Routing/CallableDispatcher.php +++ b/src/Illuminate/Routing/CallableDispatcher.php @@ -21,7 +21,6 @@ class CallableDispatcher implements CallableDispatcherContract * Create a new callable dispatcher instance. * * @param \Illuminate\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Routing/CompiledRouteCollection.php b/src/Illuminate/Routing/CompiledRouteCollection.php index 0178f783ee42..a20979bf4e41 100644 --- a/src/Illuminate/Routing/CompiledRouteCollection.php +++ b/src/Illuminate/Routing/CompiledRouteCollection.php @@ -54,7 +54,6 @@ class CompiledRouteCollection extends AbstractRouteCollection * * @param array $compiled * @param array $attributes - * @return void */ public function __construct(array $compiled, array $attributes) { diff --git a/src/Illuminate/Routing/ControllerDispatcher.php b/src/Illuminate/Routing/ControllerDispatcher.php index 9f96eeb3ec89..f82e768d0f7b 100644 --- a/src/Illuminate/Routing/ControllerDispatcher.php +++ b/src/Illuminate/Routing/ControllerDispatcher.php @@ -21,7 +21,6 @@ class ControllerDispatcher implements ControllerDispatcherContract * Create a new controller dispatcher instance. * * @param \Illuminate\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Routing/ControllerMiddlewareOptions.php b/src/Illuminate/Routing/ControllerMiddlewareOptions.php index dfb9f473f71d..9fb468f22018 100644 --- a/src/Illuminate/Routing/ControllerMiddlewareOptions.php +++ b/src/Illuminate/Routing/ControllerMiddlewareOptions.php @@ -15,7 +15,6 @@ class ControllerMiddlewareOptions * Create a new middleware option instance. * * @param array $options - * @return void */ public function __construct(array &$options) { diff --git a/src/Illuminate/Routing/Controllers/Middleware.php b/src/Illuminate/Routing/Controllers/Middleware.php index ebe9389e0b2e..330d9871ee17 100644 --- a/src/Illuminate/Routing/Controllers/Middleware.php +++ b/src/Illuminate/Routing/Controllers/Middleware.php @@ -11,7 +11,6 @@ class Middleware * Create a new controller middleware definition. * * @param \Closure|string|array $middleware - * @return void */ public function __construct(public Closure|string|array $middleware, public ?array $only = null, public ?array $except = null) { diff --git a/src/Illuminate/Routing/Events/PreparingResponse.php b/src/Illuminate/Routing/Events/PreparingResponse.php index f427431fcde1..f99367ba9a41 100644 --- a/src/Illuminate/Routing/Events/PreparingResponse.php +++ b/src/Illuminate/Routing/Events/PreparingResponse.php @@ -9,7 +9,6 @@ class PreparingResponse * * @param \Symfony\Component\HttpFoundation\Request $request The request instance. * @param mixed $response The response instance. - * @return void */ public function __construct( public $request, diff --git a/src/Illuminate/Routing/Events/ResponsePrepared.php b/src/Illuminate/Routing/Events/ResponsePrepared.php index 549d9b49c77e..940d2cc4c520 100644 --- a/src/Illuminate/Routing/Events/ResponsePrepared.php +++ b/src/Illuminate/Routing/Events/ResponsePrepared.php @@ -9,7 +9,6 @@ class ResponsePrepared * * @param \Symfony\Component\HttpFoundation\Request $request The request instance. * @param \Symfony\Component\HttpFoundation\Response $response The response instance. - * @return void */ public function __construct( public $request, diff --git a/src/Illuminate/Routing/Events/RouteMatched.php b/src/Illuminate/Routing/Events/RouteMatched.php index eb73ee796bce..503ddb438ae1 100644 --- a/src/Illuminate/Routing/Events/RouteMatched.php +++ b/src/Illuminate/Routing/Events/RouteMatched.php @@ -9,7 +9,6 @@ class RouteMatched * * @param \Illuminate\Routing\Route $route The route instance. * @param \Illuminate\Http\Request $request The request instance. - * @return void */ public function __construct( public $route, diff --git a/src/Illuminate/Routing/Events/Routing.php b/src/Illuminate/Routing/Events/Routing.php index 2bb7919eefa5..a97a817cfb31 100644 --- a/src/Illuminate/Routing/Events/Routing.php +++ b/src/Illuminate/Routing/Events/Routing.php @@ -8,7 +8,6 @@ class Routing * Create a new event instance. * * @param \Illuminate\Http\Request $request The request instance. - * @return void */ public function __construct( public $request, diff --git a/src/Illuminate/Routing/Exceptions/BackedEnumCaseNotFoundException.php b/src/Illuminate/Routing/Exceptions/BackedEnumCaseNotFoundException.php index 468583d2a583..d637551f401b 100644 --- a/src/Illuminate/Routing/Exceptions/BackedEnumCaseNotFoundException.php +++ b/src/Illuminate/Routing/Exceptions/BackedEnumCaseNotFoundException.php @@ -11,7 +11,6 @@ class BackedEnumCaseNotFoundException extends RuntimeException * * @param string $backedEnumClass * @param string $case - * @return void */ public function __construct($backedEnumClass, $case) { diff --git a/src/Illuminate/Routing/Exceptions/InvalidSignatureException.php b/src/Illuminate/Routing/Exceptions/InvalidSignatureException.php index 06a35c5e04ef..e7c9c899d60e 100644 --- a/src/Illuminate/Routing/Exceptions/InvalidSignatureException.php +++ b/src/Illuminate/Routing/Exceptions/InvalidSignatureException.php @@ -8,8 +8,6 @@ class InvalidSignatureException extends HttpException { /** * Create a new exception instance. - * - * @return void */ public function __construct() { diff --git a/src/Illuminate/Routing/Exceptions/StreamedResponseException.php b/src/Illuminate/Routing/Exceptions/StreamedResponseException.php index fa6eb7602b4c..6173aed01421 100644 --- a/src/Illuminate/Routing/Exceptions/StreamedResponseException.php +++ b/src/Illuminate/Routing/Exceptions/StreamedResponseException.php @@ -19,7 +19,6 @@ class StreamedResponseException extends RuntimeException * Create a new exception instance. * * @param \Throwable $originalException - * @return void */ public function __construct(Throwable $originalException) { diff --git a/src/Illuminate/Routing/Middleware/SubstituteBindings.php b/src/Illuminate/Routing/Middleware/SubstituteBindings.php index eb1438d0fdd7..68fe621e4dd7 100644 --- a/src/Illuminate/Routing/Middleware/SubstituteBindings.php +++ b/src/Illuminate/Routing/Middleware/SubstituteBindings.php @@ -19,7 +19,6 @@ class SubstituteBindings * Create a new bindings substitutor. * * @param \Illuminate\Contracts\Routing\Registrar $router - * @return void */ public function __construct(Registrar $router) { diff --git a/src/Illuminate/Routing/Middleware/ThrottleRequests.php b/src/Illuminate/Routing/Middleware/ThrottleRequests.php index 034c91b84286..f6a21dd4098b 100644 --- a/src/Illuminate/Routing/Middleware/ThrottleRequests.php +++ b/src/Illuminate/Routing/Middleware/ThrottleRequests.php @@ -35,7 +35,6 @@ class ThrottleRequests * Create a new request throttler. * * @param \Illuminate\Cache\RateLimiter $limiter - * @return void */ public function __construct(RateLimiter $limiter) { diff --git a/src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php b/src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php index 20afd95dd9b8..547f082c0f91 100644 --- a/src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php +++ b/src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php @@ -35,7 +35,6 @@ class ThrottleRequestsWithRedis extends ThrottleRequests * * @param \Illuminate\Cache\RateLimiter $limiter * @param \Illuminate\Contracts\Redis\Factory $redis - * @return void */ public function __construct(RateLimiter $limiter, Redis $redis) { diff --git a/src/Illuminate/Routing/PendingResourceRegistration.php b/src/Illuminate/Routing/PendingResourceRegistration.php index 587edb3a5e5f..81e25b4b16aa 100644 --- a/src/Illuminate/Routing/PendingResourceRegistration.php +++ b/src/Illuminate/Routing/PendingResourceRegistration.php @@ -51,7 +51,6 @@ class PendingResourceRegistration * @param string $name * @param string $controller * @param array $options - * @return void */ public function __construct(ResourceRegistrar $registrar, $name, $controller, array $options) { diff --git a/src/Illuminate/Routing/PendingSingletonResourceRegistration.php b/src/Illuminate/Routing/PendingSingletonResourceRegistration.php index 84ad1a9aea0d..6b01de6f0a2e 100644 --- a/src/Illuminate/Routing/PendingSingletonResourceRegistration.php +++ b/src/Illuminate/Routing/PendingSingletonResourceRegistration.php @@ -51,7 +51,6 @@ class PendingSingletonResourceRegistration * @param string $name * @param string $controller * @param array $options - * @return void */ public function __construct(ResourceRegistrar $registrar, $name, $controller, array $options) { diff --git a/src/Illuminate/Routing/Redirector.php b/src/Illuminate/Routing/Redirector.php index d779fcf50844..1b9a62a57aa9 100755 --- a/src/Illuminate/Routing/Redirector.php +++ b/src/Illuminate/Routing/Redirector.php @@ -28,7 +28,6 @@ class Redirector * Create a new Redirector instance. * * @param \Illuminate\Routing\UrlGenerator $generator - * @return void */ public function __construct(UrlGenerator $generator) { diff --git a/src/Illuminate/Routing/ResourceRegistrar.php b/src/Illuminate/Routing/ResourceRegistrar.php index 18dba2cff60f..82ccc1620b83 100644 --- a/src/Illuminate/Routing/ResourceRegistrar.php +++ b/src/Illuminate/Routing/ResourceRegistrar.php @@ -62,7 +62,6 @@ class ResourceRegistrar * Create a new resource registrar instance. * * @param \Illuminate\Routing\Router $router - * @return void */ public function __construct(Router $router) { diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index 2a71ad57c9a3..a85b264daaeb 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -40,7 +40,6 @@ class ResponseFactory implements FactoryContract * * @param \Illuminate\Contracts\View\Factory $view * @param \Illuminate\Routing\Redirector $redirector - * @return void */ public function __construct(ViewFactory $view, Redirector $redirector) { diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index a4ccd94cb99b..22008aa091de 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -170,7 +170,6 @@ class Route * @param array|string $methods * @param string $uri * @param \Closure|array $action - * @return void */ public function __construct($methods, $uri, $action) { diff --git a/src/Illuminate/Routing/RouteFileRegistrar.php b/src/Illuminate/Routing/RouteFileRegistrar.php index 7670b10eb376..f94e31d8d57e 100644 --- a/src/Illuminate/Routing/RouteFileRegistrar.php +++ b/src/Illuminate/Routing/RouteFileRegistrar.php @@ -15,7 +15,6 @@ class RouteFileRegistrar * Create a new route file registrar instance. * * @param \Illuminate\Routing\Router $router - * @return void */ public function __construct(Router $router) { diff --git a/src/Illuminate/Routing/RouteParameterBinder.php b/src/Illuminate/Routing/RouteParameterBinder.php index 8c3968e0f828..5c53e5c786e3 100644 --- a/src/Illuminate/Routing/RouteParameterBinder.php +++ b/src/Illuminate/Routing/RouteParameterBinder.php @@ -17,7 +17,6 @@ class RouteParameterBinder * Create a new Route parameter binder instance. * * @param \Illuminate\Routing\Route $route - * @return void */ public function __construct($route) { diff --git a/src/Illuminate/Routing/RouteRegistrar.php b/src/Illuminate/Routing/RouteRegistrar.php index 11973904b397..b3e543b777b1 100644 --- a/src/Illuminate/Routing/RouteRegistrar.php +++ b/src/Illuminate/Routing/RouteRegistrar.php @@ -95,7 +95,6 @@ class RouteRegistrar * Create a new route registrar instance. * * @param \Illuminate\Routing\Router $router - * @return void */ public function __construct(Router $router) { diff --git a/src/Illuminate/Routing/RouteUri.php b/src/Illuminate/Routing/RouteUri.php index 323717741e17..77003fac9a92 100644 --- a/src/Illuminate/Routing/RouteUri.php +++ b/src/Illuminate/Routing/RouteUri.php @@ -23,7 +23,6 @@ class RouteUri * * @param string $uri * @param array $bindingFields - * @return void */ public function __construct(string $uri, array $bindingFields = []) { diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index 5f38c13e4cee..7586288ec246 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -55,7 +55,6 @@ class RouteUrlGenerator * * @param \Illuminate\Routing\UrlGenerator $url * @param \Illuminate\Http\Request $request - * @return void */ public function __construct($url, $request) { diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 4a0c21ccc48b..eb9c986bfe9e 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -140,7 +140,6 @@ class Router implements BindingRegistrar, RegistrarContract * * @param \Illuminate\Contracts\Events\Dispatcher $events * @param \Illuminate\Container\Container|null $container - * @return void */ public function __construct(Dispatcher $events, ?Container $container = null) { diff --git a/src/Illuminate/Routing/SortedMiddleware.php b/src/Illuminate/Routing/SortedMiddleware.php index 3c2c7912d219..2fa2e3c5f06f 100644 --- a/src/Illuminate/Routing/SortedMiddleware.php +++ b/src/Illuminate/Routing/SortedMiddleware.php @@ -11,7 +11,6 @@ class SortedMiddleware extends Collection * * @param array $priorityMap * @param \Illuminate\Support\Collection|array $middlewares - * @return void */ public function __construct(array $priorityMap, $middlewares) { diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 36ffd20c164d..3234d01f64dc 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -124,7 +124,6 @@ class UrlGenerator implements UrlGeneratorContract * @param \Illuminate\Routing\RouteCollectionInterface $routes * @param \Illuminate\Http\Request $request * @param string|null $assetRoot - * @return void */ public function __construct(RouteCollectionInterface $routes, Request $request, $assetRoot = null) { diff --git a/src/Illuminate/Routing/ViewController.php b/src/Illuminate/Routing/ViewController.php index f5b5525d838b..e99d7ff871b3 100644 --- a/src/Illuminate/Routing/ViewController.php +++ b/src/Illuminate/Routing/ViewController.php @@ -17,7 +17,6 @@ class ViewController extends Controller * Create a new controller instance. * * @param \Illuminate\Contracts\Routing\ResponseFactory $response - * @return void */ public function __construct(ResponseFactory $response) { diff --git a/src/Illuminate/Session/ArraySessionHandler.php b/src/Illuminate/Session/ArraySessionHandler.php index 44d50dafd93e..7820ab1aeee4 100644 --- a/src/Illuminate/Session/ArraySessionHandler.php +++ b/src/Illuminate/Session/ArraySessionHandler.php @@ -27,7 +27,6 @@ class ArraySessionHandler implements SessionHandlerInterface * Create a new array driven handler instance. * * @param int $minutes - * @return void */ public function __construct($minutes) { diff --git a/src/Illuminate/Session/CacheBasedSessionHandler.php b/src/Illuminate/Session/CacheBasedSessionHandler.php index 0cccdf2d922c..bac3e18619f1 100755 --- a/src/Illuminate/Session/CacheBasedSessionHandler.php +++ b/src/Illuminate/Session/CacheBasedSessionHandler.php @@ -26,7 +26,6 @@ class CacheBasedSessionHandler implements SessionHandlerInterface * * @param \Illuminate\Contracts\Cache\Repository $cache * @param int $minutes - * @return void */ public function __construct(CacheContract $cache, $minutes) { diff --git a/src/Illuminate/Session/CookieSessionHandler.php b/src/Illuminate/Session/CookieSessionHandler.php index 396022b37f4f..09376afee045 100755 --- a/src/Illuminate/Session/CookieSessionHandler.php +++ b/src/Illuminate/Session/CookieSessionHandler.php @@ -45,7 +45,6 @@ class CookieSessionHandler implements SessionHandlerInterface * @param \Illuminate\Contracts\Cookie\QueueingFactory $cookie * @param int $minutes * @param bool $expireOnClose - * @return void */ public function __construct(CookieJar $cookie, $minutes, $expireOnClose = false) { diff --git a/src/Illuminate/Session/DatabaseSessionHandler.php b/src/Illuminate/Session/DatabaseSessionHandler.php index 132f1e347246..5023808bafa2 100644 --- a/src/Illuminate/Session/DatabaseSessionHandler.php +++ b/src/Illuminate/Session/DatabaseSessionHandler.php @@ -57,7 +57,6 @@ class DatabaseSessionHandler implements ExistenceAwareInterface, SessionHandlerI * @param string $table * @param int $minutes * @param \Illuminate\Contracts\Container\Container|null $container - * @return void */ public function __construct(ConnectionInterface $connection, $table, $minutes, ?Container $container = null) { diff --git a/src/Illuminate/Session/EncryptedStore.php b/src/Illuminate/Session/EncryptedStore.php index 0f2bbef124ea..a3a3e9abd897 100644 --- a/src/Illuminate/Session/EncryptedStore.php +++ b/src/Illuminate/Session/EncryptedStore.php @@ -23,7 +23,6 @@ class EncryptedStore extends Store * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter * @param string|null $id * @param string $serialization - * @return void */ public function __construct($name, SessionHandlerInterface $handler, EncrypterContract $encrypter, $id = null, $serialization = 'php') { diff --git a/src/Illuminate/Session/FileSessionHandler.php b/src/Illuminate/Session/FileSessionHandler.php index 82fe2245384b..64d930e5f378 100644 --- a/src/Illuminate/Session/FileSessionHandler.php +++ b/src/Illuminate/Session/FileSessionHandler.php @@ -36,7 +36,6 @@ class FileSessionHandler implements SessionHandlerInterface * @param \Illuminate\Filesystem\Filesystem $files * @param string $path * @param int $minutes - * @return void */ public function __construct(Filesystem $files, $path, $minutes) { diff --git a/src/Illuminate/Session/Middleware/AuthenticateSession.php b/src/Illuminate/Session/Middleware/AuthenticateSession.php index efd34c35e662..89c36e8a1d41 100644 --- a/src/Illuminate/Session/Middleware/AuthenticateSession.php +++ b/src/Illuminate/Session/Middleware/AuthenticateSession.php @@ -28,7 +28,6 @@ class AuthenticateSession implements AuthenticatesSessions * Create a new middleware instance. * * @param \Illuminate\Contracts\Auth\Factory $auth - * @return void */ public function __construct(AuthFactory $auth) { diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 9f456a3ba577..ec5b00b63ba9 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -33,7 +33,6 @@ class StartSession * * @param \Illuminate\Session\SessionManager $manager * @param callable|null $cacheFactoryResolver - * @return void */ public function __construct(SessionManager $manager, ?callable $cacheFactoryResolver = null) { diff --git a/src/Illuminate/Session/Store.php b/src/Illuminate/Session/Store.php index 5c5d447a3413..342544668ecb 100755 --- a/src/Illuminate/Session/Store.php +++ b/src/Illuminate/Session/Store.php @@ -69,7 +69,6 @@ class Store implements Session * @param \SessionHandlerInterface $handler * @param string|null $id * @param string $serialization - * @return void */ public function __construct($name, SessionHandlerInterface $handler, $id = null, $serialization = 'php') { diff --git a/src/Illuminate/Session/SymfonySessionDecorator.php b/src/Illuminate/Session/SymfonySessionDecorator.php index 55dde71a7cbe..365aca670333 100644 --- a/src/Illuminate/Session/SymfonySessionDecorator.php +++ b/src/Illuminate/Session/SymfonySessionDecorator.php @@ -21,7 +21,6 @@ class SymfonySessionDecorator implements SessionInterface * Create a new session decorator. * * @param \Illuminate\Contracts\Session\Session $store - * @return void */ public function __construct(Session $store) { diff --git a/src/Illuminate/Support/Composer.php b/src/Illuminate/Support/Composer.php index 76c9c57544b5..78186c8e9afb 100644 --- a/src/Illuminate/Support/Composer.php +++ b/src/Illuminate/Support/Composer.php @@ -29,7 +29,6 @@ class Composer * * @param \Illuminate\Filesystem\Filesystem $files * @param string|null $workingPath - * @return void */ public function __construct(Filesystem $files, $workingPath = null) { diff --git a/src/Illuminate/Support/DefaultProviders.php b/src/Illuminate/Support/DefaultProviders.php index 791e86072b75..6430e8439f54 100644 --- a/src/Illuminate/Support/DefaultProviders.php +++ b/src/Illuminate/Support/DefaultProviders.php @@ -13,8 +13,6 @@ class DefaultProviders /** * Create a new default provider collection. - * - * @return void */ public function __construct(?array $providers = null) { diff --git a/src/Illuminate/Support/Defer/DeferredCallback.php b/src/Illuminate/Support/Defer/DeferredCallback.php index 2bf6ad4cbd1c..8372d12fccad 100644 --- a/src/Illuminate/Support/Defer/DeferredCallback.php +++ b/src/Illuminate/Support/Defer/DeferredCallback.php @@ -10,7 +10,6 @@ class DeferredCallback * Create a new deferred callback instance. * * @param callable $callback - * @return void */ public function __construct(public $callback, public ?string $name = null, public bool $always = false) { diff --git a/src/Illuminate/Support/Fluent.php b/src/Illuminate/Support/Fluent.php index 4622829907ff..0d087806583a 100755 --- a/src/Illuminate/Support/Fluent.php +++ b/src/Illuminate/Support/Fluent.php @@ -33,7 +33,6 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable * Create a new fluent instance. * * @param iterable $attributes - * @return void */ public function __construct($attributes = []) { diff --git a/src/Illuminate/Support/HigherOrderTapProxy.php b/src/Illuminate/Support/HigherOrderTapProxy.php index bbf9b2e54db8..85201f0814c1 100644 --- a/src/Illuminate/Support/HigherOrderTapProxy.php +++ b/src/Illuminate/Support/HigherOrderTapProxy.php @@ -15,7 +15,6 @@ class HigherOrderTapProxy * Create a new tap proxy instance. * * @param mixed $target - * @return void */ public function __construct($target) { diff --git a/src/Illuminate/Support/HtmlString.php b/src/Illuminate/Support/HtmlString.php index a25311132579..6b8d98ccb063 100644 --- a/src/Illuminate/Support/HtmlString.php +++ b/src/Illuminate/Support/HtmlString.php @@ -18,7 +18,6 @@ class HtmlString implements Htmlable, Stringable * Create a new HTML string instance. * * @param string $html - * @return void */ public function __construct($html = '') { diff --git a/src/Illuminate/Support/Lottery.php b/src/Illuminate/Support/Lottery.php index d6de350dbc9f..1f8c80588345 100644 --- a/src/Illuminate/Support/Lottery.php +++ b/src/Illuminate/Support/Lottery.php @@ -46,7 +46,6 @@ class Lottery * * @param int|float $chances * @param int|null $outOf - * @return void */ public function __construct($chances, $outOf = null) { diff --git a/src/Illuminate/Support/Manager.php b/src/Illuminate/Support/Manager.php index dac4731226b2..ea1a22751241 100755 --- a/src/Illuminate/Support/Manager.php +++ b/src/Illuminate/Support/Manager.php @@ -40,7 +40,6 @@ abstract class Manager * Create a new manager instance. * * @param \Illuminate\Contracts\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Support/MessageBag.php b/src/Illuminate/Support/MessageBag.php index 5b4e6a64ebd5..76172ae73cf7 100755 --- a/src/Illuminate/Support/MessageBag.php +++ b/src/Illuminate/Support/MessageBag.php @@ -29,7 +29,6 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess * Create a new message bag instance. * * @param array $messages - * @return void */ public function __construct(array $messages = []) { diff --git a/src/Illuminate/Support/MultipleInstanceManager.php b/src/Illuminate/Support/MultipleInstanceManager.php index 5706bde1e234..66fff08e3c9a 100644 --- a/src/Illuminate/Support/MultipleInstanceManager.php +++ b/src/Illuminate/Support/MultipleInstanceManager.php @@ -47,7 +47,6 @@ abstract class MultipleInstanceManager * Create a new manager instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Support/Once.php b/src/Illuminate/Support/Once.php index 0b1741ff46b1..4d860b298f02 100644 --- a/src/Illuminate/Support/Once.php +++ b/src/Illuminate/Support/Once.php @@ -24,7 +24,6 @@ class Once * Create a new once instance. * * @param \WeakMap> $values - * @return void */ protected function __construct(protected WeakMap $values) { diff --git a/src/Illuminate/Support/Onceable.php b/src/Illuminate/Support/Onceable.php index 0e01406fdcdf..3b55d79227cc 100644 --- a/src/Illuminate/Support/Onceable.php +++ b/src/Illuminate/Support/Onceable.php @@ -13,7 +13,6 @@ class Onceable * @param string $hash * @param object|null $object * @param callable $callable - * @return void */ public function __construct( public string $hash, diff --git a/src/Illuminate/Support/Optional.php b/src/Illuminate/Support/Optional.php index ba84a2ccf231..fcf71ed0c4a4 100644 --- a/src/Illuminate/Support/Optional.php +++ b/src/Illuminate/Support/Optional.php @@ -23,7 +23,6 @@ class Optional implements ArrayAccess * Create a new optional instance. * * @param mixed $value - * @return void */ public function __construct($value) { diff --git a/src/Illuminate/Support/ServiceProvider.php b/src/Illuminate/Support/ServiceProvider.php index 3db60f9f5988..5c68c101313d 100755 --- a/src/Illuminate/Support/ServiceProvider.php +++ b/src/Illuminate/Support/ServiceProvider.php @@ -76,7 +76,6 @@ abstract class ServiceProvider * Create a new service provider instance. * * @param \Illuminate\Contracts\Foundation\Application $app - * @return void */ public function __construct($app) { diff --git a/src/Illuminate/Support/Sleep.php b/src/Illuminate/Support/Sleep.php index b1825957b6a3..9b761811cfb9 100644 --- a/src/Illuminate/Support/Sleep.php +++ b/src/Illuminate/Support/Sleep.php @@ -80,7 +80,6 @@ class Sleep * Create a new class instance. * * @param int|float|\DateInterval $duration - * @return void */ public function __construct($duration) { diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 797ffbccaeb1..b0f194fa6e0b 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -27,7 +27,6 @@ class Stringable implements JsonSerializable, ArrayAccess, BaseStringable * Create a new instance of the class. * * @param string $value - * @return void */ public function __construct($value = '') { diff --git a/src/Illuminate/Support/Testing/Fakes/BatchFake.php b/src/Illuminate/Support/Testing/Fakes/BatchFake.php index 57eb2013705b..f3712f1f1bc9 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchFake.php @@ -37,7 +37,6 @@ class BatchFake extends Batch * @param \Carbon\CarbonImmutable $createdAt * @param \Carbon\CarbonImmutable|null $cancelledAt * @param \Carbon\CarbonImmutable|null $finishedAt - * @return void */ public function __construct( string $id, diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index 72dcb845eedd..129e6c39eb55 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -86,7 +86,6 @@ class BusFake implements Fake, QueueingDispatcher * @param \Illuminate\Contracts\Bus\QueueingDispatcher $dispatcher * @param array|string $jobsToFake * @param \Illuminate\Bus\BatchRepository|null $batchRepository - * @return void */ public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = [], ?BatchRepository $batchRepository = null) { diff --git a/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php b/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php index 4026ad2338b3..63a44e75e52a 100644 --- a/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php +++ b/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php @@ -17,7 +17,6 @@ class ChainedBatchTruthTest * Create a new truth test instance. * * @param \Closure $callback - * @return void */ public function __construct(Closure $callback) { diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 9a4c9ea10024..cc30fd3a9474 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -51,7 +51,6 @@ class EventFake implements Dispatcher, Fake * * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher * @param array|string $eventsToFake - * @return void */ public function __construct(Dispatcher $dispatcher, $eventsToFake = []) { diff --git a/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php b/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php index 2a41b528887f..7a187980bf05 100644 --- a/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php +++ b/src/Illuminate/Support/Testing/Fakes/ExceptionHandlerFake.php @@ -39,7 +39,6 @@ class ExceptionHandlerFake implements ExceptionHandler, Fake * * @param \Illuminate\Contracts\Debug\ExceptionHandler $handler * @param list> $exceptions - * @return void */ public function __construct( protected ExceptionHandler $handler, diff --git a/src/Illuminate/Support/Testing/Fakes/MailFake.php b/src/Illuminate/Support/Testing/Fakes/MailFake.php index 7d4f16b334d0..ec00522c2dfb 100644 --- a/src/Illuminate/Support/Testing/Fakes/MailFake.php +++ b/src/Illuminate/Support/Testing/Fakes/MailFake.php @@ -51,7 +51,6 @@ class MailFake implements Factory, Fake, Mailer, MailQueue * Create a new mail fake. * * @param MailManager $manager - * @return void */ public function __construct(MailManager $manager) { diff --git a/src/Illuminate/Support/Testing/Fakes/PendingBatchFake.php b/src/Illuminate/Support/Testing/Fakes/PendingBatchFake.php index 3d0f499291b1..6c06cf06d7bc 100644 --- a/src/Illuminate/Support/Testing/Fakes/PendingBatchFake.php +++ b/src/Illuminate/Support/Testing/Fakes/PendingBatchFake.php @@ -19,7 +19,6 @@ class PendingBatchFake extends PendingBatch * * @param \Illuminate\Support\Testing\Fakes\BusFake $bus * @param \Illuminate\Support\Collection $jobs - * @return void */ public function __construct(BusFake $bus, Collection $jobs) { diff --git a/src/Illuminate/Support/Testing/Fakes/PendingChainFake.php b/src/Illuminate/Support/Testing/Fakes/PendingChainFake.php index 533c6498b331..42d98c172ad3 100644 --- a/src/Illuminate/Support/Testing/Fakes/PendingChainFake.php +++ b/src/Illuminate/Support/Testing/Fakes/PendingChainFake.php @@ -21,7 +21,6 @@ class PendingChainFake extends PendingChain * @param \Illuminate\Support\Testing\Fakes\BusFake $bus * @param mixed $job * @param array $chain - * @return void */ public function __construct(BusFake $bus, $job, $chain) { diff --git a/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php b/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php index 37c797dce8ee..a3d64e73e14f 100644 --- a/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php +++ b/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php @@ -11,7 +11,6 @@ class PendingMailFake extends PendingMail * Create a new instance. * * @param \Illuminate\Support\Testing\Fakes\MailFake $mailer - * @return void */ public function __construct($mailer) { diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index 5209ed60c9d6..c2fa139c5fb2 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -67,7 +67,6 @@ class QueueFake extends QueueManager implements Fake, Queue * @param \Illuminate\Contracts\Foundation\Application $app * @param array $jobsToFake * @param \Illuminate\Queue\QueueManager|null $queue - * @return void */ public function __construct($app, $jobsToFake = [], $queue = null) { diff --git a/src/Illuminate/Support/ValidatedInput.php b/src/Illuminate/Support/ValidatedInput.php index f3ac30c79e2a..1fa586ba10d1 100644 --- a/src/Illuminate/Support/ValidatedInput.php +++ b/src/Illuminate/Support/ValidatedInput.php @@ -23,7 +23,6 @@ class ValidatedInput implements ValidatedData * Create a new validated input container. * * @param array $input - * @return void */ public function __construct(array $input) { diff --git a/src/Illuminate/Testing/AssertableJsonString.php b/src/Illuminate/Testing/AssertableJsonString.php index b970edd3b482..0bf221bea0da 100644 --- a/src/Illuminate/Testing/AssertableJsonString.php +++ b/src/Illuminate/Testing/AssertableJsonString.php @@ -32,7 +32,6 @@ class AssertableJsonString implements ArrayAccess, Countable * Create a new assertable JSON string instance. * * @param \Illuminate\Contracts\Support\Jsonable|\JsonSerializable|array|string $jsonable - * @return void */ public function __construct($jsonable) { diff --git a/src/Illuminate/Testing/Concerns/RunsInParallel.php b/src/Illuminate/Testing/Concerns/RunsInParallel.php index 18380e588ab1..468bba8e0c48 100644 --- a/src/Illuminate/Testing/Concerns/RunsInParallel.php +++ b/src/Illuminate/Testing/Concerns/RunsInParallel.php @@ -54,7 +54,6 @@ trait RunsInParallel * * @param \ParaTest\Runners\PHPUnit\Options|\ParaTest\Options $options * @param \Symfony\Component\Console\Output\OutputInterface $output - * @return void */ public function __construct($options, OutputInterface $output) { diff --git a/src/Illuminate/Testing/Constraints/ArraySubset.php b/src/Illuminate/Testing/Constraints/ArraySubset.php index b77088a3b8ac..ccc20beb7f56 100644 --- a/src/Illuminate/Testing/Constraints/ArraySubset.php +++ b/src/Illuminate/Testing/Constraints/ArraySubset.php @@ -25,7 +25,6 @@ class ArraySubset extends Constraint * * @param iterable $subset * @param bool $strict - * @return void */ public function __construct(iterable $subset, bool $strict = false) { diff --git a/src/Illuminate/Testing/Constraints/CountInDatabase.php b/src/Illuminate/Testing/Constraints/CountInDatabase.php index 3ed6826929a4..3ba260790ffb 100644 --- a/src/Illuminate/Testing/Constraints/CountInDatabase.php +++ b/src/Illuminate/Testing/Constraints/CountInDatabase.php @@ -34,7 +34,6 @@ class CountInDatabase extends Constraint * * @param \Illuminate\Database\Connection $database * @param int $expectedCount - * @return void */ public function __construct(Connection $database, int $expectedCount) { diff --git a/src/Illuminate/Testing/Constraints/HasInDatabase.php b/src/Illuminate/Testing/Constraints/HasInDatabase.php index 3a30b8b07172..cb885b133c20 100644 --- a/src/Illuminate/Testing/Constraints/HasInDatabase.php +++ b/src/Illuminate/Testing/Constraints/HasInDatabase.php @@ -34,7 +34,6 @@ class HasInDatabase extends Constraint * * @param \Illuminate\Database\Connection $database * @param array $data - * @return void */ public function __construct(Connection $database, array $data) { diff --git a/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php b/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php index 665a50588caf..3eebc12f1a85 100644 --- a/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php +++ b/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php @@ -41,7 +41,6 @@ class NotSoftDeletedInDatabase extends Constraint * @param \Illuminate\Database\Connection $database * @param array $data * @param string $deletedAtColumn - * @return void */ public function __construct(Connection $database, array $data, string $deletedAtColumn) { diff --git a/src/Illuminate/Testing/Constraints/SeeInOrder.php b/src/Illuminate/Testing/Constraints/SeeInOrder.php index aba5c6bdac4c..08d30ab82fe6 100644 --- a/src/Illuminate/Testing/Constraints/SeeInOrder.php +++ b/src/Illuminate/Testing/Constraints/SeeInOrder.php @@ -25,7 +25,6 @@ class SeeInOrder extends Constraint * Create a new constraint instance. * * @param string $content - * @return void */ public function __construct($content) { diff --git a/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php b/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php index c764d5f39c4e..0e78f34bc319 100644 --- a/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php +++ b/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php @@ -41,7 +41,6 @@ class SoftDeletedInDatabase extends Constraint * @param \Illuminate\Database\Connection $database * @param array $data * @param string $deletedAtColumn - * @return void */ public function __construct(Connection $database, array $data, string $deletedAtColumn) { diff --git a/src/Illuminate/Testing/Fluent/AssertableJson.php b/src/Illuminate/Testing/Fluent/AssertableJson.php index 9afc94c7fd36..0b57db0f54b5 100644 --- a/src/Illuminate/Testing/Fluent/AssertableJson.php +++ b/src/Illuminate/Testing/Fluent/AssertableJson.php @@ -40,7 +40,6 @@ class AssertableJson implements Arrayable * * @param array $props * @param string|null $path - * @return void */ protected function __construct(array $props, ?string $path = null) { diff --git a/src/Illuminate/Testing/ParallelConsoleOutput.php b/src/Illuminate/Testing/ParallelConsoleOutput.php index c4927cfdce34..6dd351e6d26a 100644 --- a/src/Illuminate/Testing/ParallelConsoleOutput.php +++ b/src/Illuminate/Testing/ParallelConsoleOutput.php @@ -29,7 +29,6 @@ class ParallelConsoleOutput extends ConsoleOutput * Create a new Parallel ConsoleOutput instance. * * @param \Symfony\Component\Console\Output\OutputInterface $output - * @return void */ public function __construct($output) { diff --git a/src/Illuminate/Testing/ParallelTesting.php b/src/Illuminate/Testing/ParallelTesting.php index e633bc57192f..736aea91a880 100644 --- a/src/Illuminate/Testing/ParallelTesting.php +++ b/src/Illuminate/Testing/ParallelTesting.php @@ -67,7 +67,6 @@ class ParallelTesting * Create a new parallel testing instance. * * @param \Illuminate\Contracts\Container\Container $container - * @return void */ public function __construct(Container $container) { diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index e6d9b4be17e5..d1ed6f3382bd 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -80,7 +80,6 @@ class PendingCommand * @param \Illuminate\Contracts\Container\Container $app * @param string $command * @param array $parameters - * @return void */ public function __construct(PHPUnitTestCase $test, Container $app, $command, $parameters) { diff --git a/src/Illuminate/Testing/TestComponent.php b/src/Illuminate/Testing/TestComponent.php index e795300d9294..c0bebbc96529 100644 --- a/src/Illuminate/Testing/TestComponent.php +++ b/src/Illuminate/Testing/TestComponent.php @@ -32,7 +32,6 @@ class TestComponent implements Stringable * * @param \Illuminate\View\Component $component * @param \Illuminate\View\View $view - * @return void */ public function __construct($component, $view) { diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 9ad041a160db..5b632ce11051 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -71,7 +71,6 @@ class TestResponse implements ArrayAccess * * @param TResponse $response * @param \Illuminate\Http\Request|null $request - * @return void */ public function __construct($response, $request = null) { diff --git a/src/Illuminate/Testing/TestView.php b/src/Illuminate/Testing/TestView.php index acbb7435efa2..694d1dc7ce23 100644 --- a/src/Illuminate/Testing/TestView.php +++ b/src/Illuminate/Testing/TestView.php @@ -34,7 +34,6 @@ class TestView implements Stringable * Create a new test view instance. * * @param \Illuminate\View\View $view - * @return void */ public function __construct(View $view) { diff --git a/src/Illuminate/Translation/FileLoader.php b/src/Illuminate/Translation/FileLoader.php index 2723491e07a8..3ebbfcc1264b 100755 --- a/src/Illuminate/Translation/FileLoader.php +++ b/src/Illuminate/Translation/FileLoader.php @@ -42,7 +42,6 @@ class FileLoader implements Loader * * @param \Illuminate\Filesystem\Filesystem $files * @param array|string $path - * @return void */ public function __construct(Filesystem $files, array|string $path) { diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index a24f1d6f542f..6296bff9b84a 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -84,7 +84,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract * * @param \Illuminate\Contracts\Translation\Loader $loader * @param string $locale - * @return void */ public function __construct(Loader $loader, $locale) { diff --git a/src/Illuminate/Validation/ClosureValidationRule.php b/src/Illuminate/Validation/ClosureValidationRule.php index 0ce67698aede..29ee46884cb5 100644 --- a/src/Illuminate/Validation/ClosureValidationRule.php +++ b/src/Illuminate/Validation/ClosureValidationRule.php @@ -42,7 +42,6 @@ class ClosureValidationRule implements RuleContract, ValidatorAwareRule * Create a new Closure based validation rule. * * @param \Closure $callback - * @return void */ public function __construct($callback) { diff --git a/src/Illuminate/Validation/Concerns/FilterEmailValidation.php b/src/Illuminate/Validation/Concerns/FilterEmailValidation.php index 7bb929ee7e8b..50acbcf1311a 100644 --- a/src/Illuminate/Validation/Concerns/FilterEmailValidation.php +++ b/src/Illuminate/Validation/Concerns/FilterEmailValidation.php @@ -19,7 +19,6 @@ class FilterEmailValidation implements EmailValidation * Create a new validation instance. * * @param int $flags - * @return void */ public function __construct($flags = null) { diff --git a/src/Illuminate/Validation/ConditionalRules.php b/src/Illuminate/Validation/ConditionalRules.php index 0dae7c1a2fcd..d78d3e5da1b2 100644 --- a/src/Illuminate/Validation/ConditionalRules.php +++ b/src/Illuminate/Validation/ConditionalRules.php @@ -33,7 +33,6 @@ class ConditionalRules * @param callable|bool $condition * @param \Illuminate\Contracts\Validation\ValidationRule|\Illuminate\Contracts\Validation\InvokableRule|\Illuminate\Contracts\Validation\Rule|\Closure|array|string $rules * @param \Illuminate\Contracts\Validation\ValidationRule|\Illuminate\Contracts\Validation\InvokableRule|\Illuminate\Contracts\Validation\Rule|\Closure|array|string $defaultRules - * @return void */ public function __construct($condition, $rules, $defaultRules = []) { diff --git a/src/Illuminate/Validation/DatabasePresenceVerifier.php b/src/Illuminate/Validation/DatabasePresenceVerifier.php index 9229f06b708a..46601a35e872 100755 --- a/src/Illuminate/Validation/DatabasePresenceVerifier.php +++ b/src/Illuminate/Validation/DatabasePresenceVerifier.php @@ -25,7 +25,6 @@ class DatabasePresenceVerifier implements DatabasePresenceVerifierInterface * Create a new database presence verifier. * * @param \Illuminate\Database\ConnectionResolverInterface $db - * @return void */ public function __construct(ConnectionResolverInterface $db) { diff --git a/src/Illuminate/Validation/Factory.php b/src/Illuminate/Validation/Factory.php index 6ebfcac50d2d..8cf5027eb26f 100755 --- a/src/Illuminate/Validation/Factory.php +++ b/src/Illuminate/Validation/Factory.php @@ -85,7 +85,6 @@ class Factory implements FactoryContract * * @param \Illuminate\Contracts\Translation\Translator $translator * @param \Illuminate\Contracts\Container\Container|null $container - * @return void */ public function __construct(Translator $translator, ?Container $container = null) { diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index c9e43943ef59..dbd60a0173ad 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -53,7 +53,6 @@ class InvokableValidationRule implements Rule, ValidatorAwareRule * Create a new explicit Invokable validation rule. * * @param \Illuminate\Contracts\Validation\ValidationRule|\Illuminate\Contracts\Validation\InvokableRule $invokable - * @return void */ protected function __construct(ValidationRule|InvokableRule $invokable) { diff --git a/src/Illuminate/Validation/NestedRules.php b/src/Illuminate/Validation/NestedRules.php index 9d5efbe9455e..c5abe6680de2 100644 --- a/src/Illuminate/Validation/NestedRules.php +++ b/src/Illuminate/Validation/NestedRules.php @@ -17,7 +17,6 @@ class NestedRules implements CompilableRules * Create a new nested rule instance. * * @param callable $callback - * @return void */ public function __construct(callable $callback) { diff --git a/src/Illuminate/Validation/NotPwnedVerifier.php b/src/Illuminate/Validation/NotPwnedVerifier.php index 50ab2954db40..a6dbaa3c7de0 100644 --- a/src/Illuminate/Validation/NotPwnedVerifier.php +++ b/src/Illuminate/Validation/NotPwnedVerifier.php @@ -27,7 +27,6 @@ class NotPwnedVerifier implements UncompromisedVerifier * * @param \Illuminate\Http\Client\Factory $factory * @param int|null $timeout - * @return void */ public function __construct($factory, $timeout = null) { diff --git a/src/Illuminate/Validation/Rules/ArrayRule.php b/src/Illuminate/Validation/Rules/ArrayRule.php index 8914f77a449c..f29264f59933 100644 --- a/src/Illuminate/Validation/Rules/ArrayRule.php +++ b/src/Illuminate/Validation/Rules/ArrayRule.php @@ -20,7 +20,6 @@ class ArrayRule implements Stringable * Create a new array rule instance. * * @param array|null $keys - * @return void */ public function __construct($keys = null) { diff --git a/src/Illuminate/Validation/Rules/DatabaseRule.php b/src/Illuminate/Validation/Rules/DatabaseRule.php index 90e69f087ae5..00de0a0821d6 100644 --- a/src/Illuminate/Validation/Rules/DatabaseRule.php +++ b/src/Illuminate/Validation/Rules/DatabaseRule.php @@ -44,7 +44,6 @@ trait DatabaseRule * * @param string $table * @param string $column - * @return void */ public function __construct($table, $column = 'NULL') { diff --git a/src/Illuminate/Validation/Rules/Dimensions.php b/src/Illuminate/Validation/Rules/Dimensions.php index bdbaf13a2ea1..76331fbd6ff8 100644 --- a/src/Illuminate/Validation/Rules/Dimensions.php +++ b/src/Illuminate/Validation/Rules/Dimensions.php @@ -20,7 +20,6 @@ class Dimensions implements Stringable * Create a new dimensions rule instance. * * @param array $constraints - * @return void */ public function __construct(array $constraints = []) { diff --git a/src/Illuminate/Validation/Rules/Enum.php b/src/Illuminate/Validation/Rules/Enum.php index 59991bbdd7c6..d100dca4d8ff 100644 --- a/src/Illuminate/Validation/Rules/Enum.php +++ b/src/Illuminate/Validation/Rules/Enum.php @@ -45,7 +45,6 @@ class Enum implements Rule, ValidatorAwareRule * Create a new rule instance. * * @param class-string $type - * @return void */ public function __construct($type) { diff --git a/src/Illuminate/Validation/Rules/ImageFile.php b/src/Illuminate/Validation/Rules/ImageFile.php index 4142a63382c0..6c89ee96bd79 100644 --- a/src/Illuminate/Validation/Rules/ImageFile.php +++ b/src/Illuminate/Validation/Rules/ImageFile.php @@ -8,7 +8,6 @@ class ImageFile extends File * Create a new image file rule instance. * * @param bool $allowSvg - * @return void */ public function __construct($allowSvg = false) { diff --git a/src/Illuminate/Validation/Rules/In.php b/src/Illuminate/Validation/Rules/In.php index b4a8769825bc..4a2071f9adf1 100644 --- a/src/Illuminate/Validation/Rules/In.php +++ b/src/Illuminate/Validation/Rules/In.php @@ -27,7 +27,6 @@ class In implements Stringable * Create a new in rule instance. * * @param \Illuminate\Contracts\Support\Arrayable|\BackedEnum|\UnitEnum|array|string $values - * @return void */ public function __construct($values) { diff --git a/src/Illuminate/Validation/Rules/NotIn.php b/src/Illuminate/Validation/Rules/NotIn.php index 38dd259821cc..7ccb8f99bd12 100644 --- a/src/Illuminate/Validation/Rules/NotIn.php +++ b/src/Illuminate/Validation/Rules/NotIn.php @@ -27,7 +27,6 @@ class NotIn implements Stringable * Create a new "not in" rule instance. * * @param \Illuminate\Contracts\Support\Arrayable|\BackedEnum|\UnitEnum|array|string $values - * @return void */ public function __construct($values) { diff --git a/src/Illuminate/Validation/Rules/Password.php b/src/Illuminate/Validation/Rules/Password.php index fe4d55fb5b7a..7b89672dc923 100644 --- a/src/Illuminate/Validation/Rules/Password.php +++ b/src/Illuminate/Validation/Rules/Password.php @@ -111,7 +111,6 @@ class Password implements Rule, DataAwareRule, ValidatorAwareRule * Create a new rule instance. * * @param int $min - * @return void */ public function __construct($min) { diff --git a/src/Illuminate/Validation/Rules/RequiredIf.php b/src/Illuminate/Validation/Rules/RequiredIf.php index bee7c2886033..6643de8a7b16 100644 --- a/src/Illuminate/Validation/Rules/RequiredIf.php +++ b/src/Illuminate/Validation/Rules/RequiredIf.php @@ -18,7 +18,6 @@ class RequiredIf implements Stringable * Create a new required validation rule based on a condition. * * @param callable|bool $condition - * @return void */ public function __construct($condition) { diff --git a/src/Illuminate/Validation/ValidationException.php b/src/Illuminate/Validation/ValidationException.php index 1418874333b8..aacbfe8d6571 100644 --- a/src/Illuminate/Validation/ValidationException.php +++ b/src/Illuminate/Validation/ValidationException.php @@ -49,7 +49,6 @@ class ValidationException extends Exception * @param \Illuminate\Contracts\Validation\Validator $validator * @param \Symfony\Component\HttpFoundation\Response|null $response * @param string $errorBag - * @return void */ public function __construct($validator, $response = null, $errorBag = 'default') { diff --git a/src/Illuminate/Validation/ValidationRuleParser.php b/src/Illuminate/Validation/ValidationRuleParser.php index 27d8d74c03a9..bf63a222c0dc 100644 --- a/src/Illuminate/Validation/ValidationRuleParser.php +++ b/src/Illuminate/Validation/ValidationRuleParser.php @@ -35,7 +35,6 @@ class ValidationRuleParser * Create a new validation rule parser. * * @param array $data - * @return void */ public function __construct(array $data) { diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 0bafe724bb0b..816ac3df65b6 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -335,7 +335,6 @@ class Validator implements ValidatorContract * @param array $rules * @param array $messages * @param array $attributes - * @return void */ public function __construct( Translator $translator, diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php index eba64365626b..661838181bda 100644 --- a/src/Illuminate/View/AnonymousComponent.php +++ b/src/Illuminate/View/AnonymousComponent.php @@ -23,7 +23,6 @@ class AnonymousComponent extends Component * * @param string $view * @param array $data - * @return void */ public function __construct($view, $data) { diff --git a/src/Illuminate/View/AppendableAttributeValue.php b/src/Illuminate/View/AppendableAttributeValue.php index 10981bf976e7..35609f26f717 100644 --- a/src/Illuminate/View/AppendableAttributeValue.php +++ b/src/Illuminate/View/AppendableAttributeValue.php @@ -17,7 +17,6 @@ class AppendableAttributeValue implements Stringable * Create a new appendable attribute value. * * @param mixed $value - * @return void */ public function __construct($value) { diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 06b73c928df6..94876988546f 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -54,7 +54,6 @@ class ComponentTagCompiler * @param array $aliases * @param array $namespaces * @param \Illuminate\View\Compilers\BladeCompiler|null $blade - * @return void */ public function __construct(array $aliases = [], array $namespaces = [], ?BladeCompiler $blade = null) { diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index b7ea097b9527..f9f8812f0895 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -31,7 +31,6 @@ class ComponentAttributeBag implements ArrayAccess, IteratorAggregate, JsonSeria * Create a new component attribute bag instance. * * @param array $attributes - * @return void */ public function __construct(array $attributes = []) { diff --git a/src/Illuminate/View/ComponentSlot.php b/src/Illuminate/View/ComponentSlot.php index f363391cffc9..3a3ecd2e5a17 100644 --- a/src/Illuminate/View/ComponentSlot.php +++ b/src/Illuminate/View/ComponentSlot.php @@ -27,7 +27,6 @@ class ComponentSlot implements Htmlable, Stringable * * @param string $contents * @param array $attributes - * @return void */ public function __construct($contents = '', $attributes = []) { diff --git a/src/Illuminate/View/DynamicComponent.php b/src/Illuminate/View/DynamicComponent.php index 0e0edd1f6bfa..b34d3759d086 100644 --- a/src/Illuminate/View/DynamicComponent.php +++ b/src/Illuminate/View/DynamicComponent.php @@ -34,7 +34,6 @@ class DynamicComponent extends Component * Create a new component instance. * * @param string $component - * @return void */ public function __construct(string $component) { diff --git a/src/Illuminate/View/Engines/CompilerEngine.php b/src/Illuminate/View/Engines/CompilerEngine.php index a14903421830..e72afac85fd5 100755 --- a/src/Illuminate/View/Engines/CompilerEngine.php +++ b/src/Illuminate/View/Engines/CompilerEngine.php @@ -40,7 +40,6 @@ class CompilerEngine extends PhpEngine * * @param \Illuminate\View\Compilers\CompilerInterface $compiler * @param \Illuminate\Filesystem\Filesystem|null $files - * @return void */ public function __construct(CompilerInterface $compiler, ?Filesystem $files = null) { diff --git a/src/Illuminate/View/Engines/FileEngine.php b/src/Illuminate/View/Engines/FileEngine.php index 992f6758d980..65cf2d06924c 100644 --- a/src/Illuminate/View/Engines/FileEngine.php +++ b/src/Illuminate/View/Engines/FileEngine.php @@ -18,7 +18,6 @@ class FileEngine implements Engine * Create a new file engine instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/View/Engines/PhpEngine.php b/src/Illuminate/View/Engines/PhpEngine.php index 13525aeeab53..617fbd8c7245 100755 --- a/src/Illuminate/View/Engines/PhpEngine.php +++ b/src/Illuminate/View/Engines/PhpEngine.php @@ -19,7 +19,6 @@ class PhpEngine implements Engine * Create a new file engine instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @return void */ public function __construct(Filesystem $files) { diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php index 7fe5c999aee0..56718e2a84ad 100755 --- a/src/Illuminate/View/Factory.php +++ b/src/Illuminate/View/Factory.php @@ -110,7 +110,6 @@ class Factory implements FactoryContract * @param \Illuminate\View\Engines\EngineResolver $engines * @param \Illuminate\View\ViewFinderInterface $finder * @param \Illuminate\Contracts\Events\Dispatcher $events - * @return void */ public function __construct(EngineResolver $engines, ViewFinderInterface $finder, Dispatcher $events) { diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 917661d96bf2..3f0ece8fa55b 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -48,7 +48,6 @@ class FileViewFinder implements ViewFinderInterface * @param \Illuminate\Filesystem\Filesystem $files * @param array $paths * @param array|null $extensions - * @return void */ public function __construct(Filesystem $files, array $paths, ?array $extensions = null) { diff --git a/src/Illuminate/View/InvokableComponentVariable.php b/src/Illuminate/View/InvokableComponentVariable.php index d1ea11768d8c..e9963b9ea96b 100644 --- a/src/Illuminate/View/InvokableComponentVariable.php +++ b/src/Illuminate/View/InvokableComponentVariable.php @@ -23,7 +23,6 @@ class InvokableComponentVariable implements DeferringDisplayableValue, IteratorA * Create a new variable instance. * * @param \Closure $callable - * @return void */ public function __construct(Closure $callable) { diff --git a/src/Illuminate/View/Middleware/ShareErrorsFromSession.php b/src/Illuminate/View/Middleware/ShareErrorsFromSession.php index 64015d58678c..6c99a87ed17e 100644 --- a/src/Illuminate/View/Middleware/ShareErrorsFromSession.php +++ b/src/Illuminate/View/Middleware/ShareErrorsFromSession.php @@ -19,7 +19,6 @@ class ShareErrorsFromSession * Create a new error binder instance. * * @param \Illuminate\Contracts\View\Factory $view - * @return void */ public function __construct(ViewFactory $view) { diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php index 8442660e6054..c388d23d5baa 100755 --- a/src/Illuminate/View/View.php +++ b/src/Illuminate/View/View.php @@ -67,7 +67,6 @@ class View implements ArrayAccess, Htmlable, Stringable, ViewContract * @param string $view * @param string $path * @param mixed $data - * @return void */ public function __construct(Factory $factory, Engine $engine, $view, $path, $data = []) { From 67133936c6b33b6abe21dc02e2a52e21ecb0b7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= <11225821+shaedrich@users.noreply.github.com> Date: Wed, 19 Mar 2025 21:35:52 +0100 Subject: [PATCH 225/455] [12.x] Add NamedScope attribute (#54450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add NamedScope attribute * StyleCI * Make Model::getAttributedNamedScope() protected * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * fix(database): ✏ Fix typo * refactor(database): :truck: Rename attribute class to comply with PSR-4 * refactor(database): :white_check_mark: Simplify test * refactor(database): :recycle: Simplify named local scope attribute check logic * fix(database): :bug: Make attributed named scope statically callable * style(database): :rotating_light: StyleCI * style(database): :rotating_light: StyleCI * formatting * add files * fix tests --------- Signed-off-by: Mior Muhammad Zaki Co-authored-by: Mior Muhammad Zaki Co-authored-by: Taylor Otwell --- .../Database/Eloquent/Attributes/Scope.php | 19 ++++++++++ src/Illuminate/Database/Eloquent/Model.php | 26 ++++++++++++- .../Database/EloquentModelScopeTest.php | 19 +++++++++- .../EloquentNamedScopeAttibuteTest.php | 36 ++++++++++++++++++ .../Database/Fixtures/NamedScopeUser.php | 38 +++++++++++++++++++ 5 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Database/Eloquent/Attributes/Scope.php create mode 100644 tests/Integration/Database/EloquentNamedScopeAttibuteTest.php create mode 100644 tests/Integration/Database/Fixtures/NamedScopeUser.php diff --git a/src/Illuminate/Database/Eloquent/Attributes/Scope.php b/src/Illuminate/Database/Eloquent/Attributes/Scope.php new file mode 100644 index 000000000000..ff7d1048cbad --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Attributes/Scope.php @@ -0,0 +1,19 @@ +isScopeMethodWithAttribute($scope)) { + return $this->{$scope}(...$parameters); + } + return $this->{'scope'.ucfirst($scope)}(...$parameters); } + /** + * Determine if the given method has a scope attribute. + * + * @param string $method + * @return bool + */ + protected static function isScopeMethodWithAttribute(string $method) + { + return method_exists(static::class, $method) && + (new ReflectionMethod(static::class, $method)) + ->getAttributes(LocalScope::class) !== []; + } + /** * Convert the model instance to an array. * @@ -2381,6 +2401,10 @@ public function __call($method, $parameters) */ public static function __callStatic($method, $parameters) { + if (static::isScopeMethodWithAttribute($method)) { + $parameters = [static::query(), ...$parameters]; + } + return (new static)->$method(...$parameters); } diff --git a/tests/Integration/Database/EloquentModelScopeTest.php b/tests/Integration/Database/EloquentModelScopeTest.php index 408026738c2e..7ea822b42810 100644 --- a/tests/Integration/Database/EloquentModelScopeTest.php +++ b/tests/Integration/Database/EloquentModelScopeTest.php @@ -2,6 +2,8 @@ namespace Illuminate\Tests\Integration\Database; +use Illuminate\Contracts\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Attributes\Scope as NamedScope; use Illuminate\Database\Eloquent\Model; class EloquentModelScopeTest extends DatabaseTestCase @@ -19,12 +21,25 @@ public function testModelDoesNotHaveScope() $this->assertFalse($model->hasNamedScope('doesNotExist')); } + + public function testModelHasAttributedScope() + { + $model = new TestScopeModel1; + + $this->assertTrue($model->hasNamedScope('existsAsWell')); + } } class TestScopeModel1 extends Model { - public function scopeExists() + public function scopeExists(Builder $builder) + { + return $builder; + } + + #[NamedScope] + protected function existsAsWell(Builder $builder) { - return true; + return $builder; } } diff --git a/tests/Integration/Database/EloquentNamedScopeAttibuteTest.php b/tests/Integration/Database/EloquentNamedScopeAttibuteTest.php new file mode 100644 index 000000000000..4eb58a7930bc --- /dev/null +++ b/tests/Integration/Database/EloquentNamedScopeAttibuteTest.php @@ -0,0 +1,36 @@ +markTestSkippedUnless( + $this->usesSqliteInMemoryDatabaseConnection(), + 'Requires in-memory database connection', + ); + } + + public function test_it_can_query_named_scoped_from_the_query_builder() + { + $query = Fixtures\NamedScopeUser::query()->verified(true); + + $this->assertSame($this->query, $query->toRawSql()); + } + + public function test_it_can_query_named_scoped_from_static_query() + { + $query = Fixtures\NamedScopeUser::verified(true); + + $this->assertSame($this->query, $query->toRawSql()); + } +} diff --git a/tests/Integration/Database/Fixtures/NamedScopeUser.php b/tests/Integration/Database/Fixtures/NamedScopeUser.php new file mode 100644 index 000000000000..111258eb3489 --- /dev/null +++ b/tests/Integration/Database/Fixtures/NamedScopeUser.php @@ -0,0 +1,38 @@ + 'datetime', + 'password' => 'hashed', + ]; + } + + #[NamedScope] + protected function verified(Builder $builder, bool $email = true) + { + return $builder->when( + $email === true, + fn ($query) => $query->whereNotNull('email_verified_at'), + fn ($query) => $query->whereNull('email_verified_at'), + ); + } + + public function scopeVerifiedUser(Builder $builder, bool $email = true) + { + return $builder->when( + $email === true, + fn ($query) => $query->whereNotNull('email_verified_at'), + fn ($query) => $query->whereNull('email_verified_at'), + ); + } +} From 3d9a67090e26190838a1137b16947c0e21fa8859 Mon Sep 17 00:00:00 2001 From: "Kay W." Date: Thu, 20 Mar 2025 22:26:49 +0800 Subject: [PATCH 226/455] Improve syntax highlighting for stub type files (#55094) --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitattributes b/.gitattributes index 7e0ca4441814..ba7452152c0d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,6 +6,9 @@ *.md diff=markdown *.php diff=php +*.stub linguist-language=php +*.neon.dist linguist-language=neon + /.github export-ignore /bin export-ignore /tests export-ignore From 67286590127b8531b661a85e17c0a39d12030429 Mon Sep 17 00:00:00 2001 From: Ahmed Alaa <92916738+AhmedAlaa4611@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:27:49 +0200 Subject: [PATCH 227/455] prefer new Collection over collect() (#55091) --- tests/Integration/Http/HttpClientTest.php | 2 +- tests/Pagination/CursorPaginatorTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Http/HttpClientTest.php b/tests/Integration/Http/HttpClientTest.php index b66c4c18f5cb..8e2b75dfaaf6 100644 --- a/tests/Integration/Http/HttpClientTest.php +++ b/tests/Integration/Http/HttpClientTest.php @@ -21,7 +21,7 @@ public function testGlobalMiddlewarePersistsBeforeWeDispatchEvent(): void Http::get('laravel.com'); Event::assertDispatched(RequestSending::class, function (RequestSending $event) { - return Collection::make($event->request->header('User-Agent'))->contains('Facade/1.0'); + return (new Collection($event->request->header('User-Agent')))->contains('Facade/1.0'); }); } diff --git a/tests/Pagination/CursorPaginatorTest.php b/tests/Pagination/CursorPaginatorTest.php index ce32537c1670..11cfb4c009a7 100644 --- a/tests/Pagination/CursorPaginatorTest.php +++ b/tests/Pagination/CursorPaginatorTest.php @@ -101,7 +101,7 @@ public function testReturnEmptyCursorWhenItemsAreEmpty() { $cursor = new Cursor(['id' => 25], true); - $p = new CursorPaginator(Collection::make(), 25, $cursor, [ + $p = new CursorPaginator(new Collection, 25, $cursor, [ 'path' => 'http://website.com/test', 'cursorName' => 'cursor', 'parameters' => ['id'], From dd246d77f07116445a68dd5f3b5aae43a6c96bbd Mon Sep 17 00:00:00 2001 From: Vishal Chavda <41144797+vishal2931@users.noreply.github.com> Date: Sat, 22 Mar 2025 06:52:02 +0530 Subject: [PATCH 228/455] Added support for casts (#55124) --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index fcdb7e35e761..8c06e658e47e 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -2021,7 +2021,7 @@ public function except($attributes) foreach ($this->getAttributes() as $key => $value) { if (! in_array($key, $attributes)) { - $results[$key] = $value; + $results[$key] = $this->getAttribute($key); } } From fd0242aacff5bb621ed0d47ebfa18a0581e45522 Mon Sep 17 00:00:00 2001 From: Tran Trong Cuong Date: Sat, 22 Mar 2025 08:22:57 +0700 Subject: [PATCH 229/455] [12.x] Add testcase for findSole method (#55115) * add testcase for findSole method * update testcase testFindSoleMethod * fix testcase testFindSoleMethod * styleci --------- Co-authored-by: cuong.tt --- .../Database/DatabaseEloquentBuilderTest.php | 13 ++++++++++ .../Database/EloquentBelongsToManyTest.php | 24 +++++++++++++++++++ types/Database/Eloquent/Builder.php | 1 + 3 files changed, 38 insertions(+) diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 7bda1ad2916c..a3ba7837cc2d 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -48,6 +48,19 @@ public function testFindMethod() $this->assertSame('baz', $result); } + public function testFindSoleMethod() + { + $builder = m::mock(Builder::class.'[sole]', [$this->getMockQueryBuilder()]); + $model = $this->getMockModel(); + $builder->setModel($model); + $model->shouldReceive('getKeyType')->once()->andReturn('int'); + $builder->getQuery()->shouldReceive('where')->once()->with('foo_table.foo', '=', 'bar'); + $builder->shouldReceive('sole')->with(['column'])->andReturn('baz'); + + $result = $builder->findSole('bar', ['column']); + $this->assertSame('baz', $result); + } + public function testFindManyMethod() { // ids are not empty diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 608e9ce1318c..3f00341da5a1 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\Relations\Pivot; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; @@ -413,6 +414,29 @@ public function testFindMethodStringyKey() $this->assertCount(2, $post->tags()->findMany(new Collection([$tag->id, $tag2->id]))); } + public function testFindSoleMethod() + { + $post = Post::create(['title' => Str::random()]); + + $tag = Tag::create(['name' => Str::random()]); + + $post->tags()->attach($tag); + + $this->assertEquals($tag->id, $post->tags()->findSole($tag->id)->id); + + $this->assertEquals($tag->id, $post->tags()->findSole($tag)->id); + + // Test with no records + $post->tags()->detach($tag); + + try { + $post->tags()->findSole($tag); + $this->fail('Expected RecordsNotFoundException was not thrown.'); + } catch (RecordsNotFoundException $e) { + $this->assertTrue(true); + } + } + public function testFindOrFailMethod() { $this->expectException(ModelNotFoundException::class); diff --git a/types/Database/Eloquent/Builder.php b/types/Database/Eloquent/Builder.php index 61cea1d75508..fe11459c1875 100644 --- a/types/Database/Eloquent/Builder.php +++ b/types/Database/Eloquent/Builder.php @@ -63,6 +63,7 @@ function test( assertType('Illuminate\Types\Builder\User', $query->forceCreate(['name' => 'John'])); assertType('Illuminate\Types\Builder\User', $query->updateOrCreate(['id' => 1], ['name' => 'John'])); assertType('Illuminate\Types\Builder\User', $query->firstOrFail()); + assertType('Illuminate\Types\Builder\User', $query->findSole(1)); assertType('Illuminate\Types\Builder\User', $query->sole()); assertType('Illuminate\Support\LazyCollection', $query->cursor()); assertType('Illuminate\Support\LazyCollection', $query->cursor()); From 1abb88aae7bb38f1be1599c8cb34ee34816bb2ae Mon Sep 17 00:00:00 2001 From: Liam Duckett Date: Sat, 22 Mar 2025 01:24:26 +0000 Subject: [PATCH 230/455] [12.x] Types: PasswordBroker::reset (#55109) * narrow return type from mixed to string * narrow return type from mixed to string for facade --- src/Illuminate/Auth/Passwords/PasswordBroker.php | 2 +- src/Illuminate/Support/Facades/Password.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Auth/Passwords/PasswordBroker.php b/src/Illuminate/Auth/Passwords/PasswordBroker.php index 91b3d29fab7c..c71faa598b66 100755 --- a/src/Illuminate/Auth/Passwords/PasswordBroker.php +++ b/src/Illuminate/Auth/Passwords/PasswordBroker.php @@ -91,7 +91,7 @@ public function sendResetLink(#[\SensitiveParameter] array $credentials, ?Closur * * @param array $credentials * @param \Closure $callback - * @return mixed + * @return string */ public function reset(#[\SensitiveParameter] array $credentials, Closure $callback) { diff --git a/src/Illuminate/Support/Facades/Password.php b/src/Illuminate/Support/Facades/Password.php index 7099e3971fd8..0deda7d1c296 100755 --- a/src/Illuminate/Support/Facades/Password.php +++ b/src/Illuminate/Support/Facades/Password.php @@ -9,7 +9,7 @@ * @method static string getDefaultDriver() * @method static void setDefaultDriver(string $name) * @method static string sendResetLink(array $credentials, \Closure|null $callback = null) - * @method static mixed reset(array $credentials, \Closure $callback) + * @method static string reset(array $credentials, \Closure $callback) * @method static \Illuminate\Contracts\Auth\CanResetPassword|null getUser(array $credentials) * @method static string createToken(\Illuminate\Contracts\Auth\CanResetPassword $user) * @method static void deleteToken(\Illuminate\Contracts\Auth\CanResetPassword $user) From 203503cba0ad85ec33b301e4f46b0d16b912af8c Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Sat, 22 Mar 2025 01:24:53 +0000 Subject: [PATCH 231/455] Update facade docblocks --- src/Illuminate/Support/Facades/Password.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Password.php b/src/Illuminate/Support/Facades/Password.php index 0deda7d1c296..7099e3971fd8 100755 --- a/src/Illuminate/Support/Facades/Password.php +++ b/src/Illuminate/Support/Facades/Password.php @@ -9,7 +9,7 @@ * @method static string getDefaultDriver() * @method static void setDefaultDriver(string $name) * @method static string sendResetLink(array $credentials, \Closure|null $callback = null) - * @method static string reset(array $credentials, \Closure $callback) + * @method static mixed reset(array $credentials, \Closure $callback) * @method static \Illuminate\Contracts\Auth\CanResetPassword|null getUser(array $credentials) * @method static string createToken(\Illuminate\Contracts\Auth\CanResetPassword $user) * @method static void deleteToken(\Illuminate\Contracts\Auth\CanResetPassword $user) From 01b1450b0f9e79f8229184e5f12a245ae0f03257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Sat, 22 Mar 2025 02:26:57 +0100 Subject: [PATCH 232/455] [12.x] assertThrowsNothing (#55100) * assertThrowsNothing * formatting --------- Co-authored-by: Taylor Otwell --- .../InteractsWithExceptionHandling.php | 27 +++++++++++++++++ .../FoundationExceptionsHandlerTest.php | 29 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php index d6bcf8f23530..af1739d1c07a 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php @@ -213,4 +213,31 @@ protected function assertThrows(Closure $test, string|Closure $expectedClass = T return $this; } + + /** + * Assert that the given callback does not throw an exception. + * + * @param \Closure $test + * @return $this + */ + protected function assertDoesntThrow(Closure $test) + { + try { + $test(); + + $thrown = false; + } catch (Throwable $exception) { + $thrown = true; + + $exceptionClass = get_class($exception); + $exceptionMessage = $exception->getMessage(); + } + + Assert::assertTrue( + ! $thrown, + sprintf('Unexpected exception of type %s with message %s was thrown.', $exceptionClass ?? null, $exceptionMessage ?? null) + ); + + return $this; + } } diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index c4f1044f1e55..ac901c6ef992 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -571,6 +571,35 @@ public function testAssertExceptionIsThrown() } } + public function testAssertNoExceptionIsThrown() + { + try { + $this->assertDoesntThrow(function () { + throw new Exception; + }); + + $testFailed = true; + } catch (AssertionFailedError) { + $testFailed = false; + } + + if ($testFailed) { + Assert::fail('assertDoesntThrow failed: thrown exception was not detected.'); + } + + try { + $this->assertDoesntThrow(function () { }); + + $testFailed = false; + } catch (AssertionFailedError) { + $testFailed = true; + } + + if ($testFailed) { + Assert::fail('assertDoesntThrow failed: exception was detected while no exception was thrown.'); + } + } + public function testItReportsDuplicateExceptions() { $reported = []; From c5f5e3c2c7fc3cc6310c4742fa09a8bc463f54e5 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sat, 22 Mar 2025 01:27:19 +0000 Subject: [PATCH 233/455] Apply fixes from StyleCI --- tests/Foundation/FoundationExceptionsHandlerTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index ac901c6ef992..98af2559a578 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -588,7 +588,8 @@ public function testAssertNoExceptionIsThrown() } try { - $this->assertDoesntThrow(function () { }); + $this->assertDoesntThrow(function () { + }); $testFailed = false; } catch (AssertionFailedError) { From dee10cad2e1f7debd03ee9b02339bb8c2938b326 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Sat, 22 Mar 2025 02:27:42 +0100 Subject: [PATCH 234/455] Fix type nullability on PasswordBroker.events property (#55097) Per constructor, this property may be null. --- src/Illuminate/Auth/Passwords/PasswordBroker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Passwords/PasswordBroker.php b/src/Illuminate/Auth/Passwords/PasswordBroker.php index c71faa598b66..89565eb77b3a 100755 --- a/src/Illuminate/Auth/Passwords/PasswordBroker.php +++ b/src/Illuminate/Auth/Passwords/PasswordBroker.php @@ -30,7 +30,7 @@ class PasswordBroker implements PasswordBrokerContract /** * The event dispatcher instance. * - * @var \Illuminate\Contracts\Events\Dispatcher + * @var \Illuminate\Contracts\Events\Dispatcher|null */ protected $events; From bbc4a69e93749cee6e69ec08773651efd9a5f921 Mon Sep 17 00:00:00 2001 From: Shane Date: Sun, 23 Mar 2025 00:19:42 +0800 Subject: [PATCH 235/455] [12.x] Fix return type annotation in decrementPendingJobs method (#55133) --- src/Illuminate/Support/Testing/Fakes/BatchFake.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/BatchFake.php b/src/Illuminate/Support/Testing/Fakes/BatchFake.php index f3712f1f1bc9..0d1176c2b3ec 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchFake.php @@ -106,7 +106,7 @@ public function recordSuccessfulJob(string $jobId) * Decrement the pending jobs for the batch. * * @param string $jobId - * @return \Illuminate\Bus\UpdatedBatchJobCounts + * @return void */ public function decrementPendingJobs(string $jobId) { From d6915c19274ddf2ab56aafba820e97031f729531 Mon Sep 17 00:00:00 2001 From: Shane Date: Sun, 23 Mar 2025 00:20:11 +0800 Subject: [PATCH 236/455] [12.x] Fix return type annotation in compile method (#55132) --- src/Illuminate/Console/View/Components/Component.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/View/Components/Component.php b/src/Illuminate/Console/View/Components/Component.php index cfb18e1ccd3a..f515f916ff62 100644 --- a/src/Illuminate/Console/View/Components/Component.php +++ b/src/Illuminate/Console/View/Components/Component.php @@ -56,7 +56,7 @@ protected function renderView($view, $data, $verbosity) * * @param string $view * @param array $data - * @return void + * @return string */ protected function compile($view, $data) { From 468fb7445f0128a42d698662b37f5ab9a2dafc96 Mon Sep 17 00:00:00 2001 From: Faissal Wahabali Date: Sat, 22 Mar 2025 16:21:19 +0000 Subject: [PATCH 237/455] [12.x] feat: Add `whereNull` and `whereNotNull` to `Assertablejson` (#55131) * add whereNull to AssertableJson * add whereNotNull to AssertableJson * whereNull custom exception message * Update Matching.php --------- Co-authored-by: Taylor Otwell --- .../Testing/Fluent/Concerns/Matching.php | 46 +++++++++++++ tests/Testing/Fluent/AssertTest.php | 66 +++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php index 3e3d940d9651..76c6fcba5750 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -92,6 +92,52 @@ public function whereNot(string $key, $expected): self return $this; } + /** + * Asserts that the property is null. + * + * @param string $key + * @return $this + */ + public function whereNull(string $key): self + { + $this->has($key); + + $actual = $this->prop($key); + + PHPUnit::assertNull( + $actual, + sprintf( + 'Property [%s] should be null.', + $this->dotPath($key), + ) + ); + + return $this; + } + + /** + * Asserts that the property is not null. + * + * @param string $key + * @return $this + */ + public function whereNotNull(string $key): self + { + $this->has($key); + + $actual = $this->prop($key); + + PHPUnit::assertNotNull( + $actual, + sprintf( + 'Property [%s] should not be null.', + $this->dotPath($key), + ) + ); + + return $this; + } + /** * Asserts that all properties match their expected values. * diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php index c4771c583285..b248977c36e0 100644 --- a/tests/Testing/Fluent/AssertTest.php +++ b/tests/Testing/Fluent/AssertTest.php @@ -580,6 +580,72 @@ public function testAssertWhereFailsUsingBackedEnum() $assert->where('bar', BackedEnum::test_empty); } + public function testAssertWhereNullMatchesValue() + { + $assert = AssertableJson::fromArray([ + 'bar' => null, + ]); + + $assert->whereNull('bar'); + } + + public function testAssertWhereNullFailsWhenNotNull() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] should be null.'); + + $assert->whereNull('bar'); + } + + public function testAssertWhereNullFailsWhenMissing() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->whereNull('baz'); + } + + public function testAssertWhereNotNullMatchesValue() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $assert->whereNotNull('bar'); + } + + public function testAssertWhereNotNullFailsWhenNull() + { + $assert = AssertableJson::fromArray([ + 'bar' => null, + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] should not be null.'); + + $assert->whereNotNull('bar'); + } + + public function testAssertWhereNotNullFailsWhenMissing() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->whereNotNull('baz'); + } + public function testAssertWhereContainsFailsWithEmptyValue() { $assert = AssertableJson::fromArray([]); From 12dfad8ccbf2326170a0a98e20469200161ddf15 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Sat, 22 Mar 2025 12:41:27 -0500 Subject: [PATCH 238/455] [12.x] fix: use contextual bindings in class dependency resolution (#55090) * fix: use contextual bindings in class dependency resolution * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Container/Container.php | 17 ++++++----------- tests/Container/ContainerTest.php | 11 +++++++++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index a36398a47ca7..32ecaeabe998 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -1187,17 +1187,12 @@ protected function resolveClass(ReflectionParameter $parameter) { $className = Util::getParameterClassName($parameter); - // First, we check if the dependency has been explicitly bound in the container - // and if so, we will resolve it directly from there to respect any explicit - // bindings the developer has defined rather than using any default value. - if ($this->bound($className)) { - return $this->make($className); - } - - // If no binding exists, we will check if a default value has been defined for - // the parameter. If it has, we should return it to avoid overriding any of - // the developer specified default values for the constructor parameters. - if ($parameter->isDefaultValueAvailable()) { + // First we will check if a default value has been defined for the parameter. + // If it has, and no explicit binding exists, we should return it to avoid + // overriding any of the developer specified defaults for the parameters. + if ($parameter->isDefaultValueAvailable() && + ! $this->bound($className) && + $this->findInContextualBindings($className) === null) { return $parameter->getDefaultValue(); } diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 2ef9189cba19..5522b8af9b2f 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -319,6 +319,17 @@ public function testResolutionOfClassWithDefaultParameters() $this->assertInstanceOf(ContainerConcreteStub::class, $instance->default); } + public function testResolutionOfClassWithDefaultParametersAndContextualBindings() + { + $container = new Container; + + $container->when(ContainerClassWithDefaultValueStub::class) + ->needs(ContainerConcreteStub::class) + ->give(fn () => new ContainerConcreteStub); + $instance = $container->make(ContainerClassWithDefaultValueStub::class); + $this->assertInstanceOf(ContainerConcreteStub::class, $instance->default); + } + public function testBound() { $container = new Container; From 9bf2d35eaf0e0634fd1a05d1d9cc3cc1a88e31c1 Mon Sep 17 00:00:00 2001 From: Petr Knap <8299754+petrknap@users.noreply.github.com> Date: Sun, 23 Mar 2025 00:03:20 +0100 Subject: [PATCH 239/455] fix: better return types for `Illuminate\Queue\Jobs\Job::getJobId()` and `Illuminate\Queue\Jobs\DatabaseJob::getJobId()` methods (#55138) https://github.com/laravel/framework/issues/55080 --- src/Illuminate/Queue/Jobs/DatabaseJob.php | 2 +- src/Illuminate/Queue/Jobs/Job.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Jobs/DatabaseJob.php b/src/Illuminate/Queue/Jobs/DatabaseJob.php index 8fdb41801752..5a5644c499e7 100644 --- a/src/Illuminate/Queue/Jobs/DatabaseJob.php +++ b/src/Illuminate/Queue/Jobs/DatabaseJob.php @@ -78,7 +78,7 @@ public function attempts() /** * Get the job identifier. * - * @return string + * @return string|int */ public function getJobId() { diff --git a/src/Illuminate/Queue/Jobs/Job.php b/src/Illuminate/Queue/Jobs/Job.php index 0dee23712fa9..8ec6ac54f805 100755 --- a/src/Illuminate/Queue/Jobs/Job.php +++ b/src/Illuminate/Queue/Jobs/Job.php @@ -67,7 +67,7 @@ abstract class Job /** * Get the job identifier. * - * @return string + * @return string|int|null */ abstract public function getJobId(); From c45c3613fa9e19963bdbf40635d6872fc44d8b01 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Sun, 23 Mar 2025 02:33:39 +0330 Subject: [PATCH 240/455] docs: remove @return tags from constructors (#55136) - Remove unnecessary @return tags from class constructors - Improve docblock consistency across the framework - Follow PHP documentation standards as constructors don't return values Refs: #55076 --- src/Illuminate/Console/Scheduling/CallbackEvent.php | 1 - src/Illuminate/Console/Scheduling/Schedule.php | 1 - src/Illuminate/Encryption/Encrypter.php | 1 - src/Illuminate/Http/Response.php | 1 - src/Illuminate/Mail/Mailables/Envelope.php | 1 - src/Illuminate/Mail/Mailables/Headers.php | 1 - src/Illuminate/Support/Js.php | 1 - src/Illuminate/Validation/Rules/ExcludeIf.php | 1 - src/Illuminate/View/Compilers/Compiler.php | 1 - 9 files changed, 9 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/CallbackEvent.php b/src/Illuminate/Console/Scheduling/CallbackEvent.php index 0ef6fddce633..9ee9a6e46e38 100644 --- a/src/Illuminate/Console/Scheduling/CallbackEvent.php +++ b/src/Illuminate/Console/Scheduling/CallbackEvent.php @@ -46,7 +46,6 @@ class CallbackEvent extends Event * @param string|callable $callback * @param array $parameters * @param \DateTimeZone|string|null $timezone - * @return void * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index 975e7fd6e4eb..17de97bad8cb 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -102,7 +102,6 @@ class Schedule * Create a new schedule instance. * * @param \DateTimeZone|string|null $timezone - * @return void * * @throws \RuntimeException */ diff --git a/src/Illuminate/Encryption/Encrypter.php b/src/Illuminate/Encryption/Encrypter.php index 0990b0a209c2..5c6c021a1965 100755 --- a/src/Illuminate/Encryption/Encrypter.php +++ b/src/Illuminate/Encryption/Encrypter.php @@ -48,7 +48,6 @@ class Encrypter implements EncrypterContract, StringEncrypter * * @param string $key * @param string $cipher - * @return void * * @throws \RuntimeException */ diff --git a/src/Illuminate/Http/Response.php b/src/Illuminate/Http/Response.php index b1661063dd63..6576f47f6a14 100755 --- a/src/Illuminate/Http/Response.php +++ b/src/Illuminate/Http/Response.php @@ -24,7 +24,6 @@ class Response extends SymfonyResponse * @param mixed $content * @param int $status * @param array $headers - * @return void * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/Mail/Mailables/Envelope.php b/src/Illuminate/Mail/Mailables/Envelope.php index 945e63f57990..727942d665ff 100644 --- a/src/Illuminate/Mail/Mailables/Envelope.php +++ b/src/Illuminate/Mail/Mailables/Envelope.php @@ -86,7 +86,6 @@ class Envelope * @param array $tags * @param array $metadata * @param \Closure|array $using - * @return void * * @named-arguments-supported */ diff --git a/src/Illuminate/Mail/Mailables/Headers.php b/src/Illuminate/Mail/Mailables/Headers.php index 166c344b2f90..26678f608bec 100644 --- a/src/Illuminate/Mail/Mailables/Headers.php +++ b/src/Illuminate/Mail/Mailables/Headers.php @@ -37,7 +37,6 @@ class Headers * @param string|null $messageId * @param array $references * @param array $text - * @return void * * @named-arguments-supported */ diff --git a/src/Illuminate/Support/Js.php b/src/Illuminate/Support/Js.php index aeb67665d2ca..ad26ddb4b47a 100644 --- a/src/Illuminate/Support/Js.php +++ b/src/Illuminate/Support/Js.php @@ -31,7 +31,6 @@ class Js implements Htmlable, Stringable * @param mixed $data * @param int|null $flags * @param int $depth - * @return void * * @throws \JsonException */ diff --git a/src/Illuminate/Validation/Rules/ExcludeIf.php b/src/Illuminate/Validation/Rules/ExcludeIf.php index 12869d46679c..3d00ff9422de 100644 --- a/src/Illuminate/Validation/Rules/ExcludeIf.php +++ b/src/Illuminate/Validation/Rules/ExcludeIf.php @@ -19,7 +19,6 @@ class ExcludeIf implements Stringable * Create a new exclude validation rule based on a condition. * * @param \Closure|bool $condition - * @return void * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/View/Compilers/Compiler.php b/src/Illuminate/View/Compilers/Compiler.php index e93b78310d17..dbd349e69e2a 100755 --- a/src/Illuminate/View/Compilers/Compiler.php +++ b/src/Illuminate/View/Compilers/Compiler.php @@ -52,7 +52,6 @@ abstract class Compiler * @param string $basePath * @param bool $shouldCache * @param string $compiledExtension - * @return void * * @throws \InvalidArgumentException */ From 27acc099f252f92ade3c1db0769e4385e5a3b8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Sun, 23 Mar 2025 00:37:55 +0100 Subject: [PATCH 241/455] [12.x] Various URL generation bugfixes (#54811) * Add regression test: passed parameters have precedence over defaults * Add RouteUrlGenerator::formatParameters() This method turns a list of passed parameters into a list of *named* parameters (where possible) reducing ambiguity and making other code work more accurately with positional route parameters, especially when URL::defaults() is involved. This commit also resolves a known bug -- removing a 'mark skipped' mark for a test. * Add test: complex route generation with defaults and binding fields * Add support for URL::defaults(['model:slug' => 'foo']) * Code style: Apply StyleCI diff * Cleanup, additional test cases * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Routing/RouteUrlGenerator.php | 94 ++ src/Illuminate/Routing/UrlGenerator.php | 14 +- tests/Routing/RoutingUrlGeneratorTest.php | 879 ++++++++++++++++++- 3 files changed, 967 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index 7586288ec246..c82324363418 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -2,8 +2,11 @@ namespace Illuminate\Routing; +use BackedEnum; +use Illuminate\Contracts\Routing\UrlRoutable; use Illuminate\Routing\Exceptions\UrlGenerationException; use Illuminate\Support\Arr; +use Illuminate\Support\Collection; class RouteUrlGenerator { @@ -74,6 +77,8 @@ public function __construct($url, $request) */ public function to($route, $parameters = [], $absolute = false) { + $parameters = $this->formatParameters($route, $parameters); + $domain = $this->getRouteDomain($route, $parameters); // First we will construct the entire URI including the root and query string. Once it @@ -167,6 +172,95 @@ protected function addPortToDomain($domain) : $domain.':'.$port; } + /** + * Format the array of route parameters. + * + * @param \Illuminate\Routing\Route $route + * @param mixed $parameters + * @return array + */ + protected function formatParameters(Route $route, $parameters) + { + $parameters = Arr::wrap($parameters); + + $passedParameterCount = count($parameters); + + $namedParameters = []; + $namedQueryParameters = []; + $routeParametersWithoutDefaultsOrNamedParameters = []; + + $routeParameters = $route->parameterNames(); + + foreach ($routeParameters as $name) { + if (isset($parameters[$name])) { + // Named parameters don't need any special handling... + $namedParameters[$name] = $parameters[$name]; + unset($parameters[$name]); + + continue; + } elseif (! isset($this->defaultParameters[$name])) { + // No named parameter or default value, try to match to positional parameter below... + array_push($routeParametersWithoutDefaultsOrNamedParameters, $name); + } + + $namedParameters[$name] = ''; + } + + // Named parameters that don't have route parameters will be used for query string... + foreach ($parameters as $key => $value) { + if (is_string($key)) { + $namedQueryParameters[$key] = $value; + + unset($parameters[$key]); + } + } + + // Match positional parameters to the route parameters that didn't have a value in order... + if (count($parameters) == count($routeParametersWithoutDefaultsOrNamedParameters)) { + foreach (array_reverse($routeParametersWithoutDefaultsOrNamedParameters) as $name) { + if (count($parameters) === 0) { + break; + } + + $namedParameters[$name] = array_pop($parameters); + } + } + + // If there are extra parameters, just fill left to right... if not, fill right to left and try to use defaults... + $extraParameters = $passedParameterCount > count($routeParameters); + + foreach ($extraParameters ? $namedParameters : array_reverse($namedParameters) as $key => $value) { + $bindingField = $route->bindingFieldFor($key); + + $defaultParameterKey = $bindingField ? "$key:$bindingField" : $key; + + if ($value !== '') { + continue; + } elseif (! empty($parameters)) { + $namedParameters[$key] = $extraParameters ? array_shift($parameters) : array_pop($parameters); + } elseif (isset($this->defaultParameters[$defaultParameterKey])) { + $namedParameters[$key] = $this->defaultParameters[$defaultParameterKey]; + } + } + + // Any remaining values in $parameters are unnamed query string parameters... + $parameters = array_merge($namedParameters, $namedQueryParameters, $parameters); + + $parameters = Collection::wrap($parameters)->map(function ($value, $key) use ($route) { + return $value instanceof UrlRoutable && $route->bindingFieldFor($key) + ? $value->{$route->bindingFieldFor($key)} + : $value; + })->all(); + + array_walk_recursive($parameters, function (&$item) { + if ($item instanceof BackedEnum) { + $item = $item->value; + } + }); + + return $this->url->formatParameters($parameters); + } + /** * Replace the parameters on the root path. * diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 3234d01f64dc..4808c1c0a89e 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -538,20 +538,8 @@ public function route($name, $parameters = [], $absolute = true) */ public function toRoute($route, $parameters, $absolute) { - $parameters = Collection::wrap($parameters)->map(function ($value, $key) use ($route) { - return $value instanceof UrlRoutable && $route->bindingFieldFor($key) - ? $value->{$route->bindingFieldFor($key)} - : $value; - })->all(); - - array_walk_recursive($parameters, function (&$item) { - if ($item instanceof BackedEnum) { - $item = $item->value; - } - }); - return $this->routeUrl()->to( - $route, $this->formatParameters($parameters), $absolute + $route, $parameters, $absolute ); } diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index cfce4d87962f..28bb67a49423 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -398,15 +398,8 @@ public function testRoutableInterfaceRoutingAsQueryString() $this->assertSame('/foo?foo=routable', $url->route('query-string', ['foo' => $model], false)); } - /** - * @todo Fix bug related to route keys - * - * @link https://github.com/laravel/framework/pull/42425 - */ public function testRoutableInterfaceRoutingWithSeparateBindingFieldOnlyForSecondParameter() { - $this->markTestSkipped('See https://github.com/laravel/framework/pull/43255'); - $url = new UrlGenerator( $routes = new RouteCollection, Request::create('http://www.foo.com/') @@ -956,6 +949,878 @@ public function testMissingNamedRouteResolution() $this->assertSame('test-url', $url->route('foo')); } + + public function testPassedParametersHavePrecedenceOverDefaults() + { + $url = new UrlGenerator( + $routes = new RouteCollection, + Request::create('https://www.foo.com/') + ); + + $url->defaults([ + 'tenant' => 'defaultTenant', + ]); + + $route = new Route(['GET'], 'bar/{tenant}/{post}', ['as' => 'bar', fn () => '']); + $routes->add($route); + + // Named parameters + $this->assertSame( + 'https://www.foo.com/bar/concreteTenant/concretePost', + $url->route('bar', [ + 'tenant' => tap(new RoutableInterfaceStub, fn ($x) => $x->key = 'concreteTenant'), + 'post' => tap(new RoutableInterfaceStub, fn ($x) => $x->key = 'concretePost'), + ]), + ); + + // Positional parameters + $this->assertSame( + 'https://www.foo.com/bar/concreteTenant/concretePost', + $url->route('bar', [ + tap(new RoutableInterfaceStub, fn ($x) => $x->key = 'concreteTenant'), + tap(new RoutableInterfaceStub, fn ($x) => $x->key = 'concretePost'), + ]), + ); + } + + public function testComplexRouteGenerationWithDefaultsAndBindingFields() + { + $url = new UrlGenerator( + $routes = new RouteCollection, + Request::create('https://www.foo.com/') + ); + + $url->defaults([ + 'tenant' => 'defaultTenant', + 'tenant:slug' => 'defaultTenantSlug', + 'team' => 'defaultTeam', + 'team:slug' => 'defaultTeamSlug', + 'user' => 'defaultUser', + 'user:slug' => 'defaultUserSlug', + ]); + + $keyParam = fn ($value) => tap(new RoutableInterfaceStub, fn ($routable) => $routable->key = $value); + $slugParam = fn ($value) => tap(new RoutableInterfaceStub, fn ($routable) => $routable->slug = $value); + + /** + * One parameter with a default value, one without a default value. + * + * No binding fields. + */ + $route = new Route(['GET'], 'tenantPost/{tenant}/{post}', ['as' => 'tenantPost', fn () => '']); + $routes->add($route); + + // tenantPost: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPost/concreteTenant/concretePost', + $url->route('tenantPost', [$keyParam('concreteTenant'), $keyParam('concretePost')]), + ); + + // tenantPost: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantPost/concreteTenant/concretePost', + $url->route('tenantPost', ['tenant' => $keyParam('concreteTenant'), 'post' => $keyParam('concretePost')]), + ); + + // tenantPost: Tenant (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPost/defaultTenant/concretePost', + $url->route('tenantPost', [$keyParam('concretePost')]), + ); + + // tenantPost: Tenant (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantPost/defaultTenant/concretePost', + $url->route('tenantPost', ['post' => $keyParam('concretePost')]), + ); + + /** + * One parameter with a default value, one without a default value. + * + * Binding field for the first {tenant} parameter with a default value. + */ + $route = new Route(['GET'], 'tenantSlugPost/{tenant:slug}/{post}', ['as' => 'tenantSlugPost', fn () => '']); + $routes->add($route); + + // tenantSlugPost: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/concreteTenantSlug/concretePost', + $url->route('tenantSlugPost', [$slugParam('concreteTenantSlug'), $keyParam('concretePost')]), + ); + + // tenantSlugPost: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/concreteTenantSlug/concretePost', + $url->route('tenantSlugPost', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost')]), + ); + + // tenantSlugPost: Tenant (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/defaultTenantSlug/concretePost', + $url->route('tenantSlugPost', [$keyParam('concretePost')]), + ); + + // tenantSlugPost: Tenant (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/defaultTenantSlug/concretePost', + $url->route('tenantSlugPost', ['post' => $keyParam('concretePost')]), + ); + + /** + * One parameter with a default value, one without a default value. + * + * Binding field for the second parameter without a default value. + * + * This is the only route in this test where we use a binding field + * for a parameter that does not have a default value and is not + * the first parameter. This is the simplest scenario so it doesn't + * need to be tested as repetitively as the other scenarios which are + * all special in some way. + */ + $route = new Route(['GET'], 'tenantPostSlug/{tenant}/{post:slug}', ['as' => 'tenantPostSlug', fn () => '']); + $routes->add($route); + + // tenantPostSlug: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostSlug/concreteTenant/concretePostSlug', + $url->route('tenantPostSlug', [$keyParam('concreteTenant'), $slugParam('concretePostSlug')]), + ); + + // tenantPostSlug: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantPostSlug/concreteTenant/concretePostSlug', + $url->route('tenantPostSlug', ['tenant' => $keyParam('concreteTenant'), 'post' => $slugParam('concretePostSlug')]), + ); + + // tenantPostSlug: Tenant (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostSlug/defaultTenant/concretePostSlug', + $url->route('tenantPostSlug', [$slugParam('concretePostSlug')]), + ); + + // tenantPostSlug: Tenant (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostSlug/defaultTenant/concretePostSlug', + $url->route('tenantPostSlug', ['post' => $slugParam('concretePostSlug')]), + ); + + /** + * Two parameters with a default value, one without. + * + * Having established that passing parameters by key works fine above, + * we mainly test positional parameters in variations of this route. + */ + $route = new Route(['GET'], 'tenantTeamPost/{tenant}/{team}/{post}', ['as' => 'tenantTeamPost', fn () => '']); + $routes->add($route); + + // tenantTeamPost: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamPost/concreteTenant/concreteTeam/concretePost', + $url->route('tenantTeamPost', [$keyParam('concreteTenant'), $keyParam('concreteTeam'), $keyParam('concretePost')]), + ); + + // tenantTeamPost: Tenant (with default) omitted, team and post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamPost/defaultTenant/concreteTeam/concretePost', + $url->route('tenantTeamPost', [$keyParam('concreteTeam'), $keyParam('concretePost')]), + ); + + // tenantTeamPost: Tenant and team (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamPost/defaultTenant/defaultTeam/concretePost', + $url->route('tenantTeamPost', [$keyParam('concretePost')]), + ); + + // tenantTeamPost: Tenant passed by key, team (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamPost/concreteTenant/defaultTeam/concretePost', + $url->route('tenantTeamPost', ['tenant' => $keyParam('concreteTenant'), $keyParam('concretePost')]), + ); + + /** + * Two parameters with a default value, one without. + * + * The first {tenant} parameter also has a binding field. + */ + $route = new Route(['GET'], 'tenantSlugTeamPost/{tenant:slug}/{team}/{post}', ['as' => 'tenantSlugTeamPost', fn () => '']); + $routes->add($route); + + // tenantSlugTeamPost: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamPost/concreteTenantSlug/concreteTeam/concretePost', + $url->route('tenantSlugTeamPost', [$slugParam('concreteTenantSlug'), $keyParam('concreteTeam'), $keyParam('concretePost')]), + ); + + // tenantSlugTeamPost: Tenant (with default) omitted, team and post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamPost/defaultTenantSlug/concreteTeam/concretePost', + $url->route('tenantSlugTeamPost', [$keyParam('concreteTeam'), $keyParam('concretePost')]), + ); + + // tenantSlugTeamPost: Tenant and team (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamPost/defaultTenantSlug/defaultTeam/concretePost', + $url->route('tenantSlugTeamPost', [$keyParam('concretePost')]), + ); + + // tenantSlugTeamPost: Tenant passed by key, team (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamPost/concreteTenantSlug/defaultTeam/concretePost', + $url->route('tenantSlugTeamPost', ['tenant' => $slugParam('concreteTenantSlug'), $keyParam('concretePost')]), + ); + + /** + * Two parameters with a default value, one without. + * + * The second {team} parameter also has a binding field. + */ + $route = new Route(['GET'], 'tenantTeamSlugPost/{tenant}/{team:slug}/{post}', ['as' => 'tenantTeamSlugPost', fn () => '']); + $routes->add($route); + + // tenantTeamSlugPost: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamSlugPost/concreteTenant/concreteTeamSlug/concretePost', + $url->route('tenantTeamSlugPost', [$keyParam('concreteTenant'), $slugParam('concreteTeamSlug'), $keyParam('concretePost')]), + ); + + // tenantTeamSlugPost: Tenant (with default) omitted, team and post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamSlugPost/defaultTenant/concreteTeamSlug/concretePost', + $url->route('tenantTeamSlugPost', [$slugParam('concreteTeamSlug'), $keyParam('concretePost')]), + ); + + // tenantTeamSlugPost: Tenant and team (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamSlugPost/defaultTenant/defaultTeamSlug/concretePost', + $url->route('tenantTeamSlugPost', [$keyParam('concretePost')]), + ); + + // tenantTeamSlugPost: Tenant passed by key, team (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantTeamSlugPost/concreteTenantSlug/defaultTeamSlug/concretePost', + $url->route('tenantTeamSlugPost', ['tenant' => $keyParam('concreteTenantSlug'), $keyParam('concretePost')]), + ); + + /** + * Two parameters with a default value, one without. + * + * Both parameters with default values, {tenant} and {team}, also have binding fields. + */ + $route = new Route(['GET'], 'tenantSlugTeamSlugPost/{tenant:slug}/{team:slug}/{post}', ['as' => 'tenantSlugTeamSlugPost', fn () => '']); + $routes->add($route); + + // tenantSlugTeamSlugPost: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamSlugPost/concreteTenantSlug/concreteTeamSlug/concretePost', + $url->route('tenantSlugTeamSlugPost', [$slugParam('concreteTenantSlug'), $slugParam('concreteTeamSlug'), $keyParam('concretePost')]), + ); + + // tenantSlugTeamSlugPost: Tenant (with default) omitted, team and post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamSlugPost/defaultTenantSlug/concreteTeamSlug/concretePost', + $url->route('tenantSlugTeamSlugPost', [$slugParam('concreteTeamSlug'), $keyParam('concretePost')]), + ); + + // tenantSlugTeamSlugPost: Tenant and team (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamSlugPost/defaultTenantSlug/defaultTeamSlug/concretePost', + $url->route('tenantSlugTeamSlugPost', [$keyParam('concretePost')]), + ); + + // tenantSlugTeamSlugPost: Tenant passed by key, team (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugTeamSlugPost/concreteTenantSlug/defaultTeamSlug/concretePost', + $url->route('tenantSlugTeamSlugPost', ['tenant' => $slugParam('concreteTenantSlug'), $keyParam('concretePost')]), + ); + + /** + * One parameter without a default value, one with a default value. + * + * Importantly, the parameter with the default value comes second. + */ + $route = new Route(['GET'], 'postUser/{post}/{user}', ['as' => 'postUser', fn () => '']); + $routes->add($route); + + // postUser: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/postUser/concretePost/concreteUser', + $url->route('postUser', [$keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // postUser: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/postUser/concretePost/concreteUser', + // Reversed order just to check it doesn't matter with named parameters + $url->route('postUser', ['user' => $keyParam('concreteUser'), 'post' => $keyParam('concretePost')]), + ); + + // postUser: User (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/postUser/concretePost/defaultUser', + $url->route('postUser', [$keyParam('concretePost')]), + ); + + // postUser: User (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/postUser/concretePost/defaultUser', + $url->route('postUser', ['post' => $keyParam('concretePost')]), + ); + + /** + * One parameter without a default value, one with a default value. + * + * Importantly, the parameter with the default value comes second. + * + * In this variation the first parameter, without a default value, + * also has a binding field. + */ + $route = new Route(['GET'], 'postSlugUser/{post:slug}/{user}', ['as' => 'postSlugUser', fn () => '']); + $routes->add($route); + + // postSlugUser: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/postSlugUser/concretePostSlug/concreteUser', + $url->route('postSlugUser', [$slugParam('concretePostSlug'), $keyParam('concreteUser')]), + ); + + // postSlugUser: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/postSlugUser/concretePostSlug/concreteUser', + $url->route('postSlugUser', ['post' => $slugParam('concretePostSlug'), 'user' => $keyParam('concreteUser')]), + ); + + // postSlugUser: User (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/postSlugUser/concretePostSlug/defaultUser', + $url->route('postSlugUser', [$slugParam('concretePostSlug')]), + ); + + // postSlugUser: User (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/postSlugUser/concretePostSlug/defaultUser', + $url->route('postSlugUser', ['post' => $slugParam('concretePostSlug')]), + ); + + /** + * One parameter without a default value, one with a default value. + * + * Importantly, the parameter with the default value comes second. + * + * In this variation the second parameter, with a default value, + * also has a binding field. + */ + $route = new Route(['GET'], 'postUserSlug/{post}/{user:slug}', ['as' => 'postUserSlug', fn () => '']); + $routes->add($route); + + // postUserSlug: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/postUserSlug/concretePost/concreteUserSlug', + $url->route('postUserSlug', [$keyParam('concretePost'), $slugParam('concreteUserSlug')]), + ); + + // postUserSlug: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/postUserSlug/concretePost/concreteUserSlug', + $url->route('postUserSlug', ['post' => $keyParam('concretePost'), 'user' => $slugParam('concreteUserSlug')]), + ); + + // postUserSlug: User (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/postUserSlug/concretePost/defaultUserSlug', + $url->route('postUserSlug', [$keyParam('concretePost')]), + ); + + // postUserSlug: User (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/postUserSlug/concretePost/defaultUserSlug', + $url->route('postUserSlug', ['post' => $keyParam('concretePost')]), + ); + + /** + * One parameter without a default value, one with a default value. + * + * Importantly, the parameter with the default value comes second. + * + * In this variation, both parameters have binding fields. + */ + $route = new Route(['GET'], 'postSlugUserSlug/{post:slug}/{user:slug}', ['as' => 'postSlugUserSlug', fn () => '']); + $routes->add($route); + + // postSlugUserSlug: Both parameters passed positionally + $this->assertSame( + 'https://www.foo.com/postSlugUserSlug/concretePostSlug/concreteUserSlug', + $url->route('postSlugUserSlug', [$slugParam('concretePostSlug'), $slugParam('concreteUserSlug')]), + ); + + // postSlugUserSlug: Both parameters passed with keys + $this->assertSame( + 'https://www.foo.com/postSlugUserSlug/concretePostSlug/concreteUserSlug', + $url->route('postSlugUserSlug', ['post' => $slugParam('concretePostSlug'), 'user' => $slugParam('concreteUserSlug')]), + ); + + // postSlugUserSlug: User (with default) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/postSlugUserSlug/concretePostSlug/defaultUserSlug', + $url->route('postSlugUserSlug', [$slugParam('concretePostSlug')]), + ); + + // postSlugUserSlug: User (with default) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/postSlugUserSlug/concretePostSlug/defaultUserSlug', + $url->route('postSlugUserSlug', ['post' => $slugParam('concretePostSlug')]), + ); + + /** + * Parameter without a default value in between two parameters with default values. + */ + $route = new Route(['GET'], 'tenantPostUser/{tenant}/{post}/{user}', ['as' => 'tenantPostUser', fn () => '']); + $routes->add($route); + + // tenantPostUser: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostUser/concreteTenant/concretePost/concreteUser', + $url->route('tenantPostUser', [$keyParam('concreteTenant'), $keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // tenantPostUser: Tenant parameter omitted, post and user passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/concreteUser', + $url->route('tenantPostUser', [$keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // tenantPostUser: Both tenant and user (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/defaultUser', + $url->route('tenantPostUser', [$keyParam('concretePost')]), + ); + + // tenantPostUser: All parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantPostUser/concreteTenant/concretePost/concreteUser', + $url->route('tenantPostUser', ['tenant' => $keyParam('concreteTenant'), 'post' => $keyParam('concretePost'), 'user' => $keyParam('concreteUser')]), + ); + + // tenantPostUser: Both tenant and user (with defaults) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/defaultUser', + $url->route('tenantPostUser', ['post' => $keyParam('concretePost')]), + ); + + // tenantPostUser: Tenant parameter (with default) omitted, post and user passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/concreteUser', + $url->route('tenantPostUser', ['post' => $keyParam('concretePost'), 'user' => $keyParam('concreteUser')]), + ); + + // tenantPostUser: User parameter (with default) omitted, tenant and post passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostUser/concreteTenant/concretePost/defaultUser', + $url->route('tenantPostUser', ['tenant' => $keyParam('concreteTenant'), 'post' => $keyParam('concretePost')]), + ); + + /** + * Parameter without a default value in between two parameters with a default value. + * + * In this variation of this route, the first {tenant} parameter, with a default value, + * also has a binding field. + */ + $route = new Route(['GET'], 'tenantSlugPostUser/{tenant:slug}/{post}/{user}', ['as' => 'tenantSlugPostUser', fn () => '']); + $routes->add($route); + + // tenantSlugPostUser: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/concreteTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', [$slugParam('concreteTenantSlug'), $keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: Tenant parameter omitted, post and user passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', [$keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: Both tenant and user (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/defaultUser', + $url->route('tenantSlugPostUser', [$keyParam('concretePost')]), + ); + + // tenantSlugPostUser: All parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/concreteTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost'), 'user' => $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: Both tenant and user (with defaults) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/defaultUser', + $url->route('tenantSlugPostUser', ['post' => $keyParam('concretePost')]), + ); + + // tenantSlugPostUser: Tenant parameter (with default) omitted, post and user passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', ['post' => $keyParam('concretePost'), 'user' => $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: User parameter (with default) omitted, tenant and post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/concreteTenantSlug/concretePost/defaultUser', + $url->route('tenantSlugPostUser', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost')]), + ); + + /** + * Parameter without a default value in between two parameters with a default value. + * + * In this variation of this route, the last {user} parameter, with a default value, + * also has a binding field. + */ + $route = new Route(['GET'], 'tenantPostUserSlug/{tenant}/{post}/{user:slug}', ['as' => 'tenantPostUserSlug', fn () => '']); + $routes->add($route); + + // tenantPostUserSlug: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/concreteTenant/concretePost/concreteUserSlug', + $url->route('tenantPostUserSlug', [$keyParam('concreteTenant'), $keyParam('concretePost'), $slugParam('concreteUserSlug')]), + ); + + // tenantPostUserSlug: Tenant parameter omitted, post and user passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/defaultTenant/concretePost/concreteUserSlug', + $url->route('tenantPostUserSlug', [$keyParam('concretePost'), $slugParam('concreteUserSlug')]), + ); + + // tenantPostUserSlug: Both tenant and user (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/defaultTenant/concretePost/defaultUserSlug', + $url->route('tenantPostUserSlug', [$keyParam('concretePost')]), + ); + + // tenantPostUserSlug: All parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/concreteTenant/concretePost/concreteUserSlug', + $url->route('tenantPostUserSlug', ['tenant' => $keyParam('concreteTenant'), 'post' => $keyParam('concretePost'), 'user' => $slugParam('concreteUserSlug')]), + ); + + // tenantPostUserSlug: Both tenant and user (with defaults) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/defaultTenant/concretePost/defaultUserSlug', + $url->route('tenantPostUserSlug', ['post' => $keyParam('concretePost')]), + ); + + // tenantPostUserSlug: Tenant parameter (with default) omitted, post and user passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/defaultTenant/concretePost/concreteUserSlug', + $url->route('tenantPostUserSlug', ['post' => $keyParam('concretePost'), 'user' => $slugParam('concreteUserSlug')]), + ); + + // tenantPostUserSlug: User parameter (with default) omitted, tenant and post passed using key + $this->assertSame( + 'https://www.foo.com/tenantPostUserSlug/concreteTenant/concretePost/defaultUserSlug', + $url->route('tenantPostUserSlug', ['tenant' => $keyParam('concreteTenant'), 'post' => $keyParam('concretePost')]), + ); + + /** + * Parameter without a default value in between two parameters with a default value. + * + * In this variation of this route, the first {tenant} parameter, with a default value, + * also has a binding field. + */ + $route = new Route(['GET'], 'tenantSlugPostUser/{tenant:slug}/{post}/{user}', ['as' => 'tenantSlugPostUser', fn () => '']); + $routes->add($route); + + // tenantSlugPostUser: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/concreteTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', [$slugParam('concreteTenantSlug'), $keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: Tenant parameter omitted, post and user passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', [$keyParam('concretePost'), $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: Both tenant and user (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/defaultUser', + $url->route('tenantSlugPostUser', [$keyParam('concretePost')]), + ); + + // tenantSlugPostUser: All parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/concreteTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost'), 'user' => $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: Both tenant and user (with defaults) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/defaultUser', + $url->route('tenantSlugPostUser', ['post' => $keyParam('concretePost')]), + ); + + // tenantSlugPostUser: Tenant parameter (with default) omitted, post and user passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/defaultTenantSlug/concretePost/concreteUser', + $url->route('tenantSlugPostUser', ['post' => $keyParam('concretePost'), 'user' => $keyParam('concreteUser')]), + ); + + // tenantSlugPostUser: User parameter (with default) omitted, tenant and post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUser/concreteTenantSlug/concretePost/defaultUser', + $url->route('tenantSlugPostUser', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost')]), + ); + + /** + * Parameter without a default value in between two parameters with a default value. + * + * In this variation of this route, both fields with a default value, {tenant} and + * {user}, also have binding fields. + */ + $route = new Route(['GET'], 'tenantSlugPostUserSlug/{tenant:slug}/{post}/{user:slug}', ['as' => 'tenantSlugPostUserSlug', fn () => '']); + $routes->add($route); + + // tenantSlugPostUserSlug: All parameters passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/concreteTenantSlug/concretePost/concreteUserSlug', + $url->route('tenantSlugPostUserSlug', [$slugParam('concreteTenantSlug'), $keyParam('concretePost'), $slugParam('concreteUserSlug')]), + ); + + // tenantSlugPostUserSlug: Tenant parameter omitted, post and user passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/defaultTenantSlug/concretePost/concreteUserSlug', + $url->route('tenantSlugPostUserSlug', [$keyParam('concretePost'), $slugParam('concreteUserSlug')]), + ); + + // tenantSlugPostUserSlug: Both tenant and user (with defaults) omitted, post passed positionally + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/defaultTenantSlug/concretePost/defaultUserSlug', + $url->route('tenantSlugPostUserSlug', [$keyParam('concretePost')]), + ); + + // tenantSlugPostUserSlug: All parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/concreteTenantSlug/concretePost/concreteUserSlug', + $url->route('tenantSlugPostUserSlug', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost'), 'user' => $slugParam('concreteUserSlug')]), + ); + + // tenantSlugPostUserSlug: Both tenant and user (with defaults) omitted, post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/defaultTenantSlug/concretePost/defaultUserSlug', + $url->route('tenantSlugPostUserSlug', ['post' => $keyParam('concretePost')]), + ); + + // tenantSlugPostUserSlug: Tenant parameter (with default) omitted, post and user passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/defaultTenantSlug/concretePost/concreteUserSlug', + $url->route('tenantSlugPostUserSlug', ['post' => $keyParam('concretePost'), 'user' => $slugParam('concreteUserSlug')]), + ); + + // tenantSlugPostUserSlug: User parameter (with default) omitted, tenant and post passed using key + $this->assertSame( + 'https://www.foo.com/tenantSlugPostUserSlug/concreteTenantSlug/concretePost/defaultUserSlug', + $url->route('tenantSlugPostUserSlug', ['tenant' => $slugParam('concreteTenantSlug'), 'post' => $keyParam('concretePost')]), + ); + } + + public function testComplexRouteGenerationWithDefaultsAndMixedParameterSyntax() + { + $url = new UrlGenerator( + $routes = new RouteCollection, + Request::create('https://www.foo.com/') + ); + + $url->defaults([ + 'tenant' => 'defaultTenant', + 'user' => 'defaultUser', + ]); + + /** + * Parameter without a default value in between two parameters with default values. + */ + $route = new Route(['GET'], 'tenantPostUser/{tenant}/{post}/{user}', ['as' => 'tenantPostUser', fn () => '']); + $routes->add($route); + + // If the required post parameter is specified using a key, + // the positional parameter is used for the user parameter. + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/concreteUser', + $url->route('tenantPostUser', ['post' => 'concretePost', 'concreteUser']), + ); + + /** + * Two parameters without default values in between two parameters with default values. + */ + $route = new Route(['GET'], 'tenantPostCommentUser/{tenant}/{post}/{comment}/{user}', ['as' => 'tenantPostCommentUser', fn () => '']); + $routes->add($route); + + // Pass first required parameter using a key, second positionally + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/defaultUser', + $url->route('tenantPostCommentUser', ['post' => 'concretePost', 'concreteComment']), + ); + + // Pass first required parameter positionally, second using a key + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/defaultUser', + $url->route('tenantPostCommentUser', ['concretePost', 'comment' => 'concreteComment']), + ); + + // Verify that this is order-independent + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/defaultUser', + $url->route('tenantPostCommentUser', ['comment' => 'concreteComment', 'concretePost']), + ); + + // Both required params passed with keys, positional parameter goes to the user param + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/concreteUser', + $url->route('tenantPostCommentUser', ['post' => 'concretePost', 'comment' => 'concreteComment', 'concreteUser']), + ); + + // First required param passed with a key, remaining params go to the last two route params + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/concreteUser', + $url->route('tenantPostCommentUser', ['post' => 'concretePost', 'concreteComment', 'concreteUser']), + ); + + // Comment parameter passed with a key, remaining params filled (last to last) + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/concreteUser', + $url->route('tenantPostCommentUser', ['concretePost', 'comment' => 'concreteComment', 'concreteUser']), + ); + + // Verify that this is order-independent + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/defaultTenant/concretePost/concreteComment/concreteUser', + $url->route('tenantPostCommentUser', ['comment' => 'concreteComment', 'concretePost', 'concreteUser']), + ); + + // Both default parameters passed positionally, required parameters passed with keys + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/concreteTenant/concretePost/concreteComment/concreteUser', + $url->route('tenantPostCommentUser', ['concreteTenant', 'post' => 'concretePost', 'comment' => 'concreteComment', 'concreteUser']), + ); + + // Verify that the positional parameters may come anywhere in the array + $this->assertSame( + 'https://www.foo.com/tenantPostCommentUser/concreteTenant/concretePost/concreteComment/concreteUser', + $url->route('tenantPostCommentUser', ['post' => 'concretePost', 'comment' => 'concreteComment', 'concreteTenant', 'concreteUser']), + ); + } + + public function testDefaultsCanBeCombinedWithExtraQueryParameters() + { + $url = new UrlGenerator( + $routes = new RouteCollection, + Request::create('https://www.foo.com/') + ); + + $url->defaults([ + 'tenant' => 'defaultTenant', + 'tenant:slug' => 'defaultTenantSlug', + 'user' => 'defaultUser', + ]); + + $slugParam = fn ($value) => tap(new RoutableInterfaceStub, fn ($routable) => $routable->slug = $value); + + /** + * One parameter with a default value, one parameter without a default value. + */ + $route = new Route(['GET'], 'tenantPost/{tenant}/{post}', ['as' => 'tenantPost', fn () => '']); + $routes->add($route); + + // tenantPost: Extra positional parameters without values are interpreted as query strings + $this->assertSame( + 'https://www.foo.com/tenantPost/concreteTenant/concretePost?extraQuery', + $url->route('tenantPost', ['concreteTenant', 'concretePost', 'extraQuery']), + ); + + // tenantPost: Query parameters without values go at the end + $this->assertSame( + 'https://www.foo.com/tenantPost/concreteTenant/concretePost?extra=query&extraQuery', + $url->route('tenantPost', ['concreteTenant', 'concretePost', 'extraQuery', 'extra' => 'query']), + ); + + // tenantPost: Defaults can be used with *named* query parameters + $this->assertSame( + 'https://www.foo.com/tenantPost/defaultTenant/concretePost?extra=query', + $url->route('tenantPost', ['concretePost', 'extra' => 'query']), + ); + + // tenantPost: Named query parameters can be placed anywhere in the parameters array + $this->assertSame( + 'https://www.foo.com/tenantPost/concreteTenant/concretePost?extra=query', + $url->route('tenantPost', ['concreteTenant', 'extra' => 'query', 'concretePost']), + ); + + /** + * One parameter with a default value, one parameter without a default value. + * + * The first parameter with a default value, {tenant}, also has a binding field. + */ + $route = new Route(['GET'], 'tenantSlugPost/{tenant:slug}/{post}', ['as' => 'tenantSlugPost', fn () => '']); + $routes->add($route); + + // tenantSlugPost: Extra positional parameters without values are interpreted as query strings + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/concreteTenantSlug/concretePost?extraQuery', + $url->route('tenantSlugPost', [$slugParam('concreteTenantSlug'), 'concretePost', 'extraQuery']), + ); + + // tenantSlugPost: Query parameters without values go at the end + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/concreteTenantSlug/concretePost?extra=query&extraQuery', + $url->route('tenantSlugPost', [$slugParam('concreteTenantSlug'), 'concretePost', 'extraQuery', 'extra' => 'query']), + ); + + // tenantSlugPost: Defaults can be used with *named* query parameters + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/defaultTenantSlug/concretePost?extra=query', + $url->route('tenantSlugPost', ['concretePost', 'extra' => 'query']), + ); + + // tenantSlugPost: Named query parameters can be placed anywhere in the parameters array + $this->assertSame( + 'https://www.foo.com/tenantSlugPost/concreteTenantSlug/concretePost?extra=query', + $url->route('tenantSlugPost', [$slugParam('concreteTenantSlug'), 'extra' => 'query', 'concretePost']), + ); + + /** + * Parameter without a default value in between two parameters with default values. + */ + $route = new Route(['GET'], 'tenantPostUser/{tenant}/{post}/{user}', ['as' => 'tenantPostUser', fn () => '']); + $routes->add($route); + + // tenantPostUser: Query string parameters may be passed positionally if + // all route parameters are passed as well, i.e. defaults are not used. + $this->assertSame( + 'https://www.foo.com/tenantPostUser/concreteTenant/concretePost/concreteUser?extraQuery', + $url->route('tenantPostUser', ['concreteTenant', 'concretePost', 'concreteUser', 'extraQuery']), + ); + + // tenantPostUser: Query string parameters can be passed as key-value + // pairs if all route params are passed as well, i.e. no defaults. + $this->assertSame( + 'https://www.foo.com/tenantPostUser/concreteTenant/concretePost/concreteUser?extraQuery', + $url->route('tenantPostUser', ['concreteTenant', 'concretePost', 'concreteUser', 'extraQuery']), + ); + + // tenantPostUser: With omitted default parameters, query string parameters + // can only be specified using key-value pairs. Positional query string + // parameters would be interpreted as route parameters instead. + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/concreteUser?extra=query', + $url->route('tenantPostUser', ['concretePost', 'concreteUser', 'extra' => 'query']), + ); + + // tenantPostUser: Use defaults for tenant and user, pass post positionally + // and add an extra query string parameter as a key-value pair. + $this->assertSame( + 'https://www.foo.com/tenantPostUser/defaultTenant/concretePost/defaultUser?extra=query', + $url->route('tenantPostUser', ['concretePost', 'extra' => 'query']), + ); + } } class RoutableInterfaceStub implements UrlRoutable From b3dc56cdade3537d849302aa8278daa4330b1da6 Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Sat, 22 Mar 2025 23:49:40 +0000 Subject: [PATCH 242/455] Add an optional `shouldRun` method to migrations. (#55011) * feat(migrations): shouldRun method on migration classes. * Add test. * styleCI fixes * Formatting change. * StyleCI * formatting * chore: refactor to avoid issues with changing how migrations are loaded - Refactored where the skip check is done - Added in a 'SKIPPED' status message for skipped migrations - Added in a new MigrationResult backed enum to store the new third 'state' of a migration ran. * fix: add back method * fix: removed unused method failing tests. * fix: tests. * StyleCI * fix: remove dd() * formatting --------- Co-authored-by: Taylor Otwell --- .../Console/View/Components/Task.php | 11 ++++-- .../Database/Migrations/Migration.php | 10 +++++ .../Database/Migrations/MigrationResult.php | 10 +++++ .../Database/Migrations/Migrator.php | 18 ++++++--- tests/Console/View/ComponentsTest.php | 10 ++++- ...2016_01_01_200000_create_flights_table.php | 36 ++++++++++++++++++ tests/Integration/Migration/MigratorTest.php | 5 ++- .../2017_10_04_000000_add_age_to_people.php | 37 +++++++++++++++++++ 8 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 src/Illuminate/Database/Migrations/MigrationResult.php create mode 100644 tests/Database/migrations/should_run/2016_01_01_200000_create_flights_table.php create mode 100644 tests/Integration/Migration/fixtures/2017_10_04_000000_add_age_to_people.php diff --git a/src/Illuminate/Console/View/Components/Task.php b/src/Illuminate/Console/View/Components/Task.php index ee743eaed028..a7dbf62df3c3 100644 --- a/src/Illuminate/Console/View/Components/Task.php +++ b/src/Illuminate/Console/View/Components/Task.php @@ -2,6 +2,7 @@ namespace Illuminate\Console\View\Components; +use Illuminate\Database\Migrations\MigrationResult; use Illuminate\Support\InteractsWithTime; use Symfony\Component\Console\Output\OutputInterface; use Throwable; @@ -34,10 +35,10 @@ public function render($description, $task = null, $verbosity = OutputInterface: $startTime = microtime(true); - $result = false; + $result = MigrationResult::Failure; try { - $result = ($task ?: fn () => true)(); + $result = ($task ?: fn () => MigrationResult::Success)(); } catch (Throwable $e) { throw $e; } finally { @@ -53,7 +54,11 @@ public function render($description, $task = null, $verbosity = OutputInterface: $this->output->write("$runTime", false, $verbosity); $this->output->writeln( - $result !== false ? ' DONE' : ' FAIL', + match ($result) { + MigrationResult::Failure => ' FAIL', + MigrationResult::Skipped => ' SKIPPED', + default => ' DONE' + }, $verbosity, ); } diff --git a/src/Illuminate/Database/Migrations/Migration.php b/src/Illuminate/Database/Migrations/Migration.php index a58f7848a7e1..35c8d43be388 100755 --- a/src/Illuminate/Database/Migrations/Migration.php +++ b/src/Illuminate/Database/Migrations/Migration.php @@ -27,4 +27,14 @@ public function getConnection() { return $this->connection; } + + /** + * Determine if this migration should run. + * + * @return bool + */ + public function shouldRun(): bool + { + return true; + } } diff --git a/src/Illuminate/Database/Migrations/MigrationResult.php b/src/Illuminate/Database/Migrations/MigrationResult.php new file mode 100644 index 000000000000..649eb5b269d3 --- /dev/null +++ b/src/Illuminate/Database/Migrations/MigrationResult.php @@ -0,0 +1,10 @@ +pretendToRun($migration, 'up'); } - $this->write(Task::class, $name, fn () => $this->runMigration($migration, 'up')); + $shouldRunMigration = $migration instanceof Migration + ? $migration->shouldRun() + : true; - // Once we have run a migrations class, we will log that it was run in this - // repository so that we don't try to run it next time we do a migration - // in the application. A migration repository keeps the migrate order. - $this->repository->log($name, $batch); + if (! $shouldRunMigration) { + $this->write(Task::class, $name, fn () => MigrationResult::Skipped); + } else { + $this->write(Task::class, $name, fn () => $this->runMigration($migration, 'up')); + + // Once we have run a migrations class, we will log that it was run in this + // repository so that we don't try to run it next time we do a migration + // in the application. A migration repository keeps the migrate order. + $this->repository->log($name, $batch); + } } /** diff --git a/tests/Console/View/ComponentsTest.php b/tests/Console/View/ComponentsTest.php index ef710e51effd..e10ff74a17d1 100644 --- a/tests/Console/View/ComponentsTest.php +++ b/tests/Console/View/ComponentsTest.php @@ -4,6 +4,7 @@ use Illuminate\Console\OutputStyle; use Illuminate\Console\View\Components; +use Illuminate\Database\Migrations\MigrationResult; use Mockery as m; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Output\BufferedOutput; @@ -108,15 +109,20 @@ public function testTask() { $output = new BufferedOutput(); - with(new Components\Task($output))->render('My task', fn () => true); + with(new Components\Task($output))->render('My task', fn () => MigrationResult::Success); $result = $output->fetch(); $this->assertStringContainsString('My task', $result); $this->assertStringContainsString('DONE', $result); - with(new Components\Task($output))->render('My task', fn () => false); + with(new Components\Task($output))->render('My task', fn () => MigrationResult::Failure); $result = $output->fetch(); $this->assertStringContainsString('My task', $result); $this->assertStringContainsString('FAIL', $result); + + with(new Components\Task($output))->render('My task', fn () => MigrationResult::Skipped); + $result = $output->fetch(); + $this->assertStringContainsString('My task', $result); + $this->assertStringContainsString('SKIPPED', $result); } public function testTwoColumnDetail() diff --git a/tests/Database/migrations/should_run/2016_01_01_200000_create_flights_table.php b/tests/Database/migrations/should_run/2016_01_01_200000_create_flights_table.php new file mode 100644 index 000000000000..edd6f747bf9a --- /dev/null +++ b/tests/Database/migrations/should_run/2016_01_01_200000_create_flights_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->string('name'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('flights'); + } +} diff --git a/tests/Integration/Migration/MigratorTest.php b/tests/Integration/Migration/MigratorTest.php index 15f79993dfd6..0ea2eafcc403 100644 --- a/tests/Integration/Migration/MigratorTest.php +++ b/tests/Integration/Migration/MigratorTest.php @@ -44,6 +44,7 @@ public function testMigrate() $this->expectTask('2014_10_12_000000_create_people_table', 'DONE'); $this->expectTask('2015_10_04_000000_modify_people_table', 'DONE'); $this->expectTask('2016_10_04_000000_modify_people_table', 'DONE'); + $this->expectTask('2017_10_04_000000_add_age_to_people', 'SKIPPED'); $this->output->shouldReceive('writeln')->once(); @@ -52,6 +53,7 @@ public function testMigrate() $this->assertTrue(DB::getSchemaBuilder()->hasTable('people')); $this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'first_name')); $this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'last_name')); + $this->assertFalse(DB::getSchemaBuilder()->hasColumn('people', 'age')); } public function testMigrateWithoutOutput() @@ -64,6 +66,7 @@ public function testMigrateWithoutOutput() $this->assertTrue(DB::getSchemaBuilder()->hasTable('people')); $this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'first_name')); $this->assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'last_name')); + $this->assertFalse(DB::getSchemaBuilder()->hasColumn('people', 'age')); } public function testWithSkippedMigrations() @@ -120,7 +123,7 @@ public function testPretendMigrate() $this->expectTwoColumnDetail('2016_10_04_000000_modify_people_table'); $this->expectBulletList(['alter table "people" add column "last_name" varchar']); - $this->output->shouldReceive('writeln')->once(); + $this->output->shouldReceive('writeln')->times(3); $this->subject->run([__DIR__.'/fixtures'], ['pretend' => true]); diff --git a/tests/Integration/Migration/fixtures/2017_10_04_000000_add_age_to_people.php b/tests/Integration/Migration/fixtures/2017_10_04_000000_add_age_to_people.php new file mode 100644 index 000000000000..ab42904f9082 --- /dev/null +++ b/tests/Integration/Migration/fixtures/2017_10_04_000000_add_age_to_people.php @@ -0,0 +1,37 @@ +unsignedInteger('age')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('people', function (Blueprint $table) { + $table->dropColumn('age'); + }); + } +}; From 1e1ed42e8ebcc6fc527567d34e6a78faf4d4c2b5 Mon Sep 17 00:00:00 2001 From: Roj Vroemen Date: Mon, 24 Mar 2025 04:36:00 +0100 Subject: [PATCH 243/455] [12.x] `Uri` prevent empty query string (#55146) * Add broken example * Fallback to `null` when query string is empty to remove it --- src/Illuminate/Support/Uri.php | 2 +- tests/Support/SupportUriTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Uri.php b/src/Illuminate/Support/Uri.php index c25814d54220..231ee3024445 100644 --- a/src/Illuminate/Support/Uri.php +++ b/src/Illuminate/Support/Uri.php @@ -235,7 +235,7 @@ public function withQuery(array $query, bool $merge = true): static } } - return new static($this->uri->withQuery(Arr::query($newQuery))); + return new static($this->uri->withQuery(Arr::query($newQuery) ?: null)); } /** diff --git a/tests/Support/SupportUriTest.php b/tests/Support/SupportUriTest.php index bd567817da45..ffdb870c9302 100644 --- a/tests/Support/SupportUriTest.php +++ b/tests/Support/SupportUriTest.php @@ -188,4 +188,12 @@ public function test_with_query_if_missing() ], ], $uri->query()->all()); } + + public function test_with_query_prevents_empty_query_string() + { + $uri = Uri::of('https://laravel.com'); + + $this->assertEquals('https://laravel.com', (string) $uri); + $this->assertEquals('https://laravel.com', (string) $uri->withQuery([])); + } } From 873cdba53786169751f32eb0af0710021e89d153 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Mon, 24 Mar 2025 00:46:06 -0300 Subject: [PATCH 244/455] Only call the ob_flush function if there is active buffer (#55141) When ob_flush() is called without first calling ob_start(), it fails saying there's no active buffer. To avoid this issue, we must check the buffer level before flushing it. --- src/Illuminate/Routing/ResponseFactory.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index a85b264daaeb..4a767e39482f 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -150,7 +150,10 @@ public function eventStream(Closure $callback, array $headers = [], StreamedEven echo 'data: '.$message; echo "\n\n"; - ob_flush(); + if (ob_get_level() > 0) { + ob_flush(); + } + flush(); } @@ -166,7 +169,10 @@ public function eventStream(Closure $callback, array $headers = [], StreamedEven echo 'data: '.$endStreamWith; echo "\n\n"; - ob_flush(); + if (ob_get_level() > 0) { + ob_flush(); + } + flush(); } }, 200, array_merge($headers, [ From ef3e8c2f4b5e9ad92571ff4df299c894630dcacf Mon Sep 17 00:00:00 2001 From: Tech Wolf Date: Mon, 24 Mar 2025 09:30:04 +0530 Subject: [PATCH 245/455] [12.x] Add CacheFlushed Event (#55142) * [12.x] Fix: Added CacheFlushed Event * [12.x] StyleCLI Resolved * [12.x] StyleCLI Resolved * [12.x] CacheFlushing Event added * [12.x] Created New Class for Key free CacheEvent for Flush * [12.x] Deleted New CacheFlush Event * [12.x] PR comments resolved --- src/Illuminate/Cache/Events/CacheFlushed.php | 24 +++++++++++ src/Illuminate/Cache/Events/CacheFlushing.php | 24 +++++++++++ src/Illuminate/Cache/Repository.php | 12 +++++- tests/Cache/CacheEventsTest.php | 40 +++++++++++++++++++ tests/Support/SupportFacadesEventTest.php | 13 ++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/Illuminate/Cache/Events/CacheFlushed.php create mode 100644 src/Illuminate/Cache/Events/CacheFlushing.php diff --git a/src/Illuminate/Cache/Events/CacheFlushed.php b/src/Illuminate/Cache/Events/CacheFlushed.php new file mode 100644 index 000000000000..fb0275f06e50 --- /dev/null +++ b/src/Illuminate/Cache/Events/CacheFlushed.php @@ -0,0 +1,24 @@ +storeName = $storeName; + } +} diff --git a/src/Illuminate/Cache/Events/CacheFlushing.php b/src/Illuminate/Cache/Events/CacheFlushing.php new file mode 100644 index 000000000000..21054c8b718a --- /dev/null +++ b/src/Illuminate/Cache/Events/CacheFlushing.php @@ -0,0 +1,24 @@ +storeName = $storeName; + } +} diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 9f34e4aa9679..da22ea7d4a8f 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -6,6 +6,8 @@ use BadMethodCallException; use Closure; use DateTimeInterface; +use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; use Illuminate\Cache\Events\ForgettingKey; @@ -576,7 +578,15 @@ public function deleteMultiple($keys): bool */ public function clear(): bool { - return $this->store->flush(); + $this->event(new CacheFlushing($this->getName())); + + $result = $this->store->flush(); + + if ($result) { + $this->event(new CacheFlushed($this->getName())); + } + + return $result; } /** diff --git a/tests/Cache/CacheEventsTest.php b/tests/Cache/CacheEventsTest.php index 04036db602fd..77a9173506eb 100755 --- a/tests/Cache/CacheEventsTest.php +++ b/tests/Cache/CacheEventsTest.php @@ -3,6 +3,8 @@ namespace Illuminate\Tests\Cache; use Illuminate\Cache\ArrayStore; +use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; use Illuminate\Cache\Events\ForgettingKey; @@ -221,6 +223,44 @@ public function testForgetDoesTriggerFailedEventOnFailure() $this->assertFalse($repository->forget('baz')); } + public function testFlushTriggersEvents() + { + $dispatcher = $this->getDispatcher(); + $repository = $this->getRepository($dispatcher); + + $dispatcher->shouldReceive('dispatch')->once()->with( + $this->assertEventMatches(CacheFlushing::class, [ + 'storeName' => 'array', + ]) + ); + + $dispatcher->shouldReceive('dispatch')->once()->with( + $this->assertEventMatches(CacheFlushed::class, [ + 'storeName' => 'array', + ]) + ); + $this->assertTrue($repository->clear()); + } + + public function testFlushFailureDoesNotDispatchEvent() + { + $dispatcher = $this->getDispatcher(); + + // Create a store that fails to flush + $failingStore = m::mock(Store::class); + $failingStore->shouldReceive('flush')->andReturn(false); + + $repository = new Repository($failingStore, ['store' => 'array']); + $repository->setEventDispatcher($dispatcher); + + $dispatcher->shouldReceive('dispatch')->once()->with( + $this->assertEventMatches(CacheFlushing::class, [ + 'storeName' => 'array', + ]) + ); + $this->assertFalse($repository->clear()); + } + protected function assertEventMatches($eventClass, $properties = []) { return m::on(function ($event) use ($eventClass, $properties) { diff --git a/tests/Support/SupportFacadesEventTest.php b/tests/Support/SupportFacadesEventTest.php index 3a438ff08ef3..928ce440e3f0 100644 --- a/tests/Support/SupportFacadesEventTest.php +++ b/tests/Support/SupportFacadesEventTest.php @@ -3,6 +3,8 @@ namespace Illuminate\Tests\Support; use Illuminate\Cache\CacheManager; +use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Cache\Events\CacheMissed; use Illuminate\Cache\Events\RetrievingKey; use Illuminate\Config\Repository as ConfigRepository; @@ -87,6 +89,17 @@ public function testFakeSwapsDispatchersInResolvedCacheRepositories() Event::assertDispatched(CacheMissed::class); } + public function testCacheFlushDispatchesEvent() + { + $arrayRepository = Cache::store('array'); + Event::fake(); + + $arrayRepository->clear(); + + Event::assertDispatched(CacheFlushing::class); + Event::assertDispatched(CacheFlushed::class); + } + protected function getCacheConfig() { return [ From 6ce873a2b00b85c66134da29fdf0eb2c86bcb34a Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 24 Mar 2025 12:03:28 +0000 Subject: [PATCH 246/455] Update .styleci.yml --- .styleci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.styleci.yml b/.styleci.yml index 079b642b8987..05af66632431 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,8 +1,6 @@ php: preset: laravel version: 8.2 - enabled: - - nullable_type_declarations finder: not-name: - bad-syntax-strategy.php From dd16215c362ca2a3f4146db0078afbfbe7e18cb2 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 24 Mar 2025 12:06:13 +0000 Subject: [PATCH 247/455] StyleCI fixes --- src/Illuminate/Http/Middleware/TrustProxies.php | 10 +++++----- src/Illuminate/Support/Uri.php | 2 +- tests/Database/DatabaseEloquentInverseRelationTest.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Http/Middleware/TrustProxies.php b/src/Illuminate/Http/Middleware/TrustProxies.php index 1dcaf1b81387..0e6936d56a54 100644 --- a/src/Illuminate/Http/Middleware/TrustProxies.php +++ b/src/Illuminate/Http/Middleware/TrustProxies.php @@ -20,11 +20,11 @@ class TrustProxies * @var int */ protected $headers = Request::HEADER_X_FORWARDED_FOR | - Request::HEADER_X_FORWARDED_HOST | - Request::HEADER_X_FORWARDED_PORT | - Request::HEADER_X_FORWARDED_PROTO | - Request::HEADER_X_FORWARDED_PREFIX | - Request::HEADER_X_FORWARDED_AWS_ELB; + Request::HEADER_X_FORWARDED_HOST | + Request::HEADER_X_FORWARDED_PORT | + Request::HEADER_X_FORWARDED_PROTO | + Request::HEADER_X_FORWARDED_PREFIX | + Request::HEADER_X_FORWARDED_AWS_ELB; /** * The proxies that have been configured to always be trusted. diff --git a/src/Illuminate/Support/Uri.php b/src/Illuminate/Support/Uri.php index 231ee3024445..9dfa50986320 100644 --- a/src/Illuminate/Support/Uri.php +++ b/src/Illuminate/Support/Uri.php @@ -195,7 +195,7 @@ public function withHost(Stringable|string $host): static /** * Specify the port of the URI. */ - public function withPort(int|null $port): static + public function withPort(?int $port): static { return new static($this->uri->withPort($port)); } diff --git a/tests/Database/DatabaseEloquentInverseRelationTest.php b/tests/Database/DatabaseEloquentInverseRelationTest.php index 7f6c9d1e9366..6f1e9606291e 100755 --- a/tests/Database/DatabaseEloquentInverseRelationTest.php +++ b/tests/Database/DatabaseEloquentInverseRelationTest.php @@ -379,7 +379,7 @@ public function exposeGetPossibleInverseRelations(): array return $this->getPossibleInverseRelations(); } - public function exposeGuessInverseRelation(): string|null + public function exposeGuessInverseRelation(): ?string { return $this->guessInverseRelation(); } From 964c4bb45d01f1b27d5ae91098400577d28fe935 Mon Sep 17 00:00:00 2001 From: "Kay W." Date: Mon, 24 Mar 2025 22:45:30 +0800 Subject: [PATCH 248/455] Update DateFactory method annotations for Carbon v3 compatibility (#55151) --- src/Illuminate/Support/DateFactory.php | 83 ++++++++++++++++---------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/src/Illuminate/Support/DateFactory.php b/src/Illuminate/Support/DateFactory.php index fbf918396d05..01cd16438448 100644 --- a/src/Illuminate/Support/DateFactory.php +++ b/src/Illuminate/Support/DateFactory.php @@ -9,77 +9,96 @@ * @see https://carbon.nesbot.com/docs/ * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php * - * @method \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method bool canBeCreatedFromFormat(?string $date, string $format) + * @method \Illuminate\Support\Carbon|null create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) * @method \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) - * @method \Illuminate\Support\Carbon|false createFromFormat($format, $time, $timezone = null) + * @method \Illuminate\Support\Carbon|null createFromFormat($format, $time, $timezone = null) + * @method \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null) + * @method \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) + * @method \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimeString($time, $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimestamp($timestamp, $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimestampUTC($timestamp) + * @method \Illuminate\Support\Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) + * @method \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) * @method \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) - * @method \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) + * @method \Illuminate\Support\Carbon|null createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) + * @method \Illuminate\Support\Carbon createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null) * @method void disableHumanDiffOption($humanDiffOption) * @method void enableHumanDiffOption($humanDiffOption) - * @method mixed executeWithLocale($locale, $func) + * @method mixed executeWithLocale(string $locale, callable $func) * @method \Illuminate\Support\Carbon fromSerialized($value) * @method array getAvailableLocales() + * @method array getAvailableLocalesInfo() * @method array getDays() + * @method ?string getFallbackLocale() + * @method array getFormatsToIsoReplacements() * @method int getHumanDiffOptions() * @method array getIsoUnits() - * @method array getLastErrors() + * @method array|false getLastErrors() * @method string getLocale() * @method int getMidDayAt() + * @method string getTimeFormatByPrecision(string $unitPrecision) + * @method string|Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) * @method \Illuminate\Support\Carbon|null getTestNow() * @method \Symfony\Contracts\Translation\TranslatorInterface getTranslator() - * @method int getWeekEndsAt() - * @method int getWeekStartsAt() + * @method int getWeekEndsAt(?string $locale = null) + * @method int getWeekStartsAt(?string $locale = null) * @method array getWeekendDays() - * @method bool hasFormat($date, $format) + * @method bool hasFormat(string $date, string $format) + * @method bool hasFormatWithModifiers(string $date, string $format) * @method bool hasMacro($name) - * @method bool hasRelativeKeywords($time) + * @method bool hasRelativeKeywords(?string $time) * @method bool hasTestNow() - * @method \Illuminate\Support\Carbon instance($date) + * @method \Illuminate\Support\Carbon instance(DateTimeInterface $date) * @method bool isImmutable() * @method bool isModifiableUnit($unit) * @method bool isMutable() * @method bool isStrictModeEnabled() - * @method bool localeHasDiffOneDayWords($locale) - * @method bool localeHasDiffSyntax($locale) - * @method bool localeHasDiffTwoDayWords($locale) + * @method bool localeHasDiffOneDayWords(string $locale) + * @method bool localeHasDiffSyntax(string $locale) + * @method bool localeHasDiffTwoDayWords(string $locale) * @method bool localeHasPeriodSyntax($locale) - * @method bool localeHasShortUnits($locale) - * @method void macro($name, $macro) - * @method \Illuminate\Support\Carbon|null make($var) - * @method \Illuminate\Support\Carbon maxValue() - * @method \Illuminate\Support\Carbon minValue() - * @method void mixin($mixin) - * @method \Illuminate\Support\Carbon now($timezone = null) - * @method \Illuminate\Support\Carbon parse($time = null, $timezone = null) + * @method bool localeHasShortUnits(string $locale) + * @method void macro(string $name, ?callable $macro) + * @method \Illuminate\Support\Carbon|null make($var, DateTimeZone|string|null $timezone = null) + * @method void mixin(object|string $mixin) + * @method \Illuminate\Support\Carbon now(DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) * @method string pluralUnit(string $unit) + * @method \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) + * @method \Illuminate\Support\Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) * @method void resetMonthsOverflow() * @method void resetToStringFormat() * @method void resetYearsOverflow() * @method void serializeUsing($callback) + * @method void setFallbackLocale(string $locale) * @method void setHumanDiffOptions($humanDiffOptions) - * @method bool setLocale($locale) + * @method void setLocale(string $locale) * @method void setMidDayAt($hour) - * @method void setTestNow($testNow = null) - * @method void setToStringFormat($format) + * @method void setTestNow(mixed $testNow = null) + * @method void setTestNowAndTimezone(mixed $testNow = null, $timezone = null) + * @method void setToStringFormat(string|Closure|null $format) * @method void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) - * @method void setUtf8($utf8) * @method void setWeekEndsAt($day) * @method void setWeekStartsAt($day) * @method void setWeekendDays($days) * @method bool shouldOverflowMonths() * @method bool shouldOverflowYears() * @method string singularUnit(string $unit) - * @method \Illuminate\Support\Carbon today($timezone = null) - * @method \Illuminate\Support\Carbon tomorrow($timezone = null) + * @method void sleep(int|float $seconds) + * @method \Illuminate\Support\Carbon today(DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) + * @method string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) + * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method void useMonthsOverflow($monthsOverflow = true) * @method void useStrictMode($strictModeEnabled = true) * @method void useYearsOverflow($yearsOverflow = true) - * @method \Illuminate\Support\Carbon yesterday($timezone = null) + * @method mixed withTestNow(mixed $testNow, callable $callback) + * @method static withTimeZone(DateTimeZone|string|int|null $timezone) + * @method \Illuminate\Support\Carbon yesterday(DateTimeZone|string|int|null $timezone = null) */ class DateFactory { From 0a554da84b7c2b8bdf9e8d6f04becf3bfd3d9864 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:45:59 +0000 Subject: [PATCH 249/455] Update facade docblocks --- src/Illuminate/Support/Facades/Date.php | 83 +++++++++++++++---------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index 462025508629..fb55ef29656f 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -13,77 +13,96 @@ * @method static void useCallable(callable $callable) * @method static void useClass(string $dateClass) * @method static void useFactory(object $factory) - * @method static \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static bool canBeCreatedFromFormat(?string $date, string $format) + * @method static \Illuminate\Support\Carbon|null create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) - * @method static \Illuminate\Support\Carbon|false createFromFormat($format, $time, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createFromFormat($format, $time, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null) + * @method static \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimeString($time, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestamp($timestamp, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestampUTC($timestamp) + * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) + * @method static \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) - * @method static \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) + * @method static \Illuminate\Support\Carbon createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null) * @method static void disableHumanDiffOption($humanDiffOption) * @method static void enableHumanDiffOption($humanDiffOption) - * @method static mixed executeWithLocale($locale, $func) + * @method static mixed executeWithLocale(string $locale, callable $func) * @method static \Illuminate\Support\Carbon fromSerialized($value) * @method static array getAvailableLocales() + * @method static array getAvailableLocalesInfo() * @method static array getDays() + * @method static ?string getFallbackLocale() + * @method static array getFormatsToIsoReplacements() * @method static int getHumanDiffOptions() * @method static array getIsoUnits() - * @method static array getLastErrors() + * @method static array|false getLastErrors() * @method static string getLocale() * @method static int getMidDayAt() + * @method static string getTimeFormatByPrecision(string $unitPrecision) + * @method static string|Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) * @method static \Illuminate\Support\Carbon|null getTestNow() * @method static \Symfony\Contracts\Translation\TranslatorInterface getTranslator() - * @method static int getWeekEndsAt() - * @method static int getWeekStartsAt() + * @method static int getWeekEndsAt(?string $locale = null) + * @method static int getWeekStartsAt(?string $locale = null) * @method static array getWeekendDays() - * @method static bool hasFormat($date, $format) + * @method static bool hasFormat(string $date, string $format) + * @method static bool hasFormatWithModifiers(string $date, string $format) * @method static bool hasMacro($name) - * @method static bool hasRelativeKeywords($time) + * @method static bool hasRelativeKeywords(?string $time) * @method static bool hasTestNow() - * @method static \Illuminate\Support\Carbon instance($date) + * @method static \Illuminate\Support\Carbon instance(DateTimeInterface $date) * @method static bool isImmutable() * @method static bool isModifiableUnit($unit) * @method static bool isMutable() * @method static bool isStrictModeEnabled() - * @method static bool localeHasDiffOneDayWords($locale) - * @method static bool localeHasDiffSyntax($locale) - * @method static bool localeHasDiffTwoDayWords($locale) + * @method static bool localeHasDiffOneDayWords(string $locale) + * @method static bool localeHasDiffSyntax(string $locale) + * @method static bool localeHasDiffTwoDayWords(string $locale) * @method static bool localeHasPeriodSyntax($locale) - * @method static bool localeHasShortUnits($locale) - * @method static void macro($name, $macro) - * @method static \Illuminate\Support\Carbon|null make($var) - * @method static \Illuminate\Support\Carbon maxValue() - * @method static \Illuminate\Support\Carbon minValue() - * @method static void mixin($mixin) - * @method static \Illuminate\Support\Carbon now($timezone = null) - * @method static \Illuminate\Support\Carbon parse($time = null, $timezone = null) + * @method static bool localeHasShortUnits(string $locale) + * @method static void macro(string $name, ?callable $macro) + * @method static \Illuminate\Support\Carbon|null make($var, DateTimeZone|string|null $timezone = null) + * @method static void mixin(object|string $mixin) + * @method static \Illuminate\Support\Carbon now(DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) * @method static string pluralUnit(string $unit) + * @method static \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) + * @method static \Illuminate\Support\Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() * @method static void serializeUsing($callback) + * @method static void setFallbackLocale(string $locale) * @method static void setHumanDiffOptions($humanDiffOptions) - * @method static bool setLocale($locale) + * @method static void setLocale(string $locale) * @method static void setMidDayAt($hour) - * @method static void setTestNow($testNow = null) - * @method static void setToStringFormat($format) + * @method static void setTestNow(mixed $testNow = null) + * @method static void setTestNowAndTimezone(mixed $testNow = null, $timezone = null) + * @method static void setToStringFormat(string|Closure|null $format) * @method static void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) - * @method static void setUtf8($utf8) * @method static void setWeekEndsAt($day) * @method static void setWeekStartsAt($day) * @method static void setWeekendDays($days) * @method static bool shouldOverflowMonths() * @method static bool shouldOverflowYears() * @method static string singularUnit(string $unit) - * @method static \Illuminate\Support\Carbon today($timezone = null) - * @method static \Illuminate\Support\Carbon tomorrow($timezone = null) + * @method static void sleep(int|float $seconds) + * @method static \Illuminate\Support\Carbon today(DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) + * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) + * @method static string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) - * @method static \Illuminate\Support\Carbon yesterday($timezone = null) + * @method static mixed withTestNow(mixed $testNow, callable $callback) + * @method static static withTimeZone(DateTimeZone|string|int|null $timezone) + * @method static \Illuminate\Support\Carbon yesterday(DateTimeZone|string|int|null $timezone = null) * * @see \Illuminate\Support\DateFactory */ From 4625a218c971b0582707f95367266c142d6aae3f Mon Sep 17 00:00:00 2001 From: Sander Muller Date: Mon, 24 Mar 2025 15:49:53 +0100 Subject: [PATCH 250/455] [12.x] Improve docblocks for file related methods of InteractsWithInput (#55156) * Improve docblocks for file related methods of InteractsWithInput * Update InteractsWithInput.php --- src/Illuminate/Http/Concerns/InteractsWithInput.php | 8 ++++---- src/Illuminate/Http/Request.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Http/Concerns/InteractsWithInput.php b/src/Illuminate/Http/Concerns/InteractsWithInput.php index 3cbeb947de7a..730ab9e7ade4 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithInput.php +++ b/src/Illuminate/Http/Concerns/InteractsWithInput.php @@ -175,7 +175,7 @@ public function cookie($key = null, $default = null) /** * Get an array of all of the files on the request. * - * @return array + * @return array */ public function allFiles() { @@ -187,8 +187,8 @@ public function allFiles() /** * Convert the given array of Symfony UploadedFiles to custom Laravel UploadedFiles. * - * @param array $files - * @return array + * @param array $files + * @return array */ protected function convertUploadedFiles(array $files) { @@ -240,7 +240,7 @@ protected function isValidFile($file) * * @param string|null $key * @param mixed $default - * @return \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|array|null + * @return ($key is null ? array : \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null) */ public function file($key = null, $default = null) { diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 995ed0865741..bee09601ef03 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -42,7 +42,7 @@ class Request extends SymfonyRequest implements Arrayable, ArrayAccess /** * All of the converted files for the request. * - * @var array + * @var array */ protected $convertedFiles; From 46ac7829eba556031fa5f540f3771d52fa4117a2 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:50:34 +0000 Subject: [PATCH 251/455] Update facade docblocks --- src/Illuminate/Support/Facades/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Request.php b/src/Illuminate/Support/Facades/Request.php index 8c782950b75f..8461fa41b1ee 100755 --- a/src/Illuminate/Support/Facades/Request.php +++ b/src/Illuminate/Support/Facades/Request.php @@ -151,7 +151,7 @@ * @method static string|array|null cookie(string|null $key = null, string|array|null $default = null) * @method static array allFiles() * @method static bool hasFile(string $key) - * @method static \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|array|null file(string|null $key = null, mixed $default = null) + * @method static array|(\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null file(string|null $key = null, mixed $default = null) * @method static \Illuminate\Http\Request dump(mixed $keys = []) * @method static never dd(mixed ...$args) * @method static bool exists(string|array $key) From 637124b1f99a0bfb89fc470d83f85d733b06e03d Mon Sep 17 00:00:00 2001 From: Iman Date: Thu, 27 Mar 2025 20:37:51 +0330 Subject: [PATCH 252/455] Enhance FileViewFinder doc-blocks (#55183) --- src/Illuminate/View/FileViewFinder.php | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 3f0ece8fa55b..b29c0088e3c2 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -17,21 +17,21 @@ class FileViewFinder implements ViewFinderInterface /** * The array of active view paths. * - * @var array + * @var string[] */ protected $paths; /** * The array of views that have been located. * - * @var array + * @var array */ protected $views = []; /** * The namespace to file path hints. * - * @var array + * @var array */ protected $hints = []; @@ -46,8 +46,8 @@ class FileViewFinder implements ViewFinderInterface * Create a new file view loader instance. * * @param \Illuminate\Filesystem\Filesystem $files - * @param array $paths - * @param array|null $extensions + * @param string[] $paths + * @param string[]|null $extensions */ public function __construct(Filesystem $files, array $paths, ?array $extensions = null) { @@ -95,7 +95,7 @@ protected function findNamespacedView($name) * Get the segments of a template with a named path. * * @param string $name - * @return array + * @return string[] * * @throws \InvalidArgumentException */ @@ -118,7 +118,7 @@ protected function parseNamespaceSegments($name) * Find the given view in the list of paths. * * @param string $name - * @param array $paths + * @param string|string[] $paths * @return string * * @throws \InvalidArgumentException @@ -142,7 +142,7 @@ protected function findInPaths($name, $paths) * Get an array of possible view files. * * @param string $name - * @return array + * @return string[] */ protected function getPossibleViewFiles($name) { @@ -186,7 +186,7 @@ protected function resolvePath($path) * Add a namespace hint to the finder. * * @param string $namespace - * @param string|array $hints + * @param string|string[] $hints * @return void */ public function addNamespace($namespace, $hints) @@ -204,7 +204,7 @@ public function addNamespace($namespace, $hints) * Prepend a namespace hint to the finder. * * @param string $namespace - * @param string|array $hints + * @param string|string[] $hints * @return void */ public function prependNamespace($namespace, $hints) @@ -222,7 +222,7 @@ public function prependNamespace($namespace, $hints) * Replace the namespace hints for the given namespace. * * @param string $namespace - * @param string|array $hints + * @param string|string[] $hints * @return void */ public function replaceNamespace($namespace, $hints) @@ -279,7 +279,7 @@ public function getFilesystem() /** * Set the active view paths. * - * @param array $paths + * @param string[] $paths * @return $this */ public function setPaths($paths) @@ -292,7 +292,7 @@ public function setPaths($paths) /** * Get the active view paths. * - * @return array + * @return string[] */ public function getPaths() { @@ -302,7 +302,7 @@ public function getPaths() /** * Get the views that have been located. * - * @return array + * @return array */ public function getViews() { @@ -312,7 +312,7 @@ public function getViews() /** * Get the namespace to file path hints. * - * @return array + * @return array */ public function getHints() { @@ -322,7 +322,7 @@ public function getHints() /** * Get registered extensions. * - * @return array + * @return string[] */ public function getExtensions() { From a9d8775315e04d8bc74057c24aae0c2ed36f22ba Mon Sep 17 00:00:00 2001 From: Will Rowe Date: Thu, 27 Mar 2025 13:11:21 -0400 Subject: [PATCH 253/455] Support using null-safe operator with `null` value (#55175) * Add test * Mark `<=>` operator as valid for `null` comparisons --- src/Illuminate/Database/Query/Builder.php | 4 ++-- tests/Database/DatabaseQueryBuilderTest.php | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index edf184d919f8..0ee40c971872 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -866,7 +866,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' // where null clause to the query. So, we will allow a short-cut here to // that method for convenience so the developer doesn't have to check. if (is_null($value)) { - return $this->whereNull($column, $boolean, $operator !== '='); + return $this->whereNull($column, $boolean, ! in_array($operator, ['=', '<=>'], true)); } $type = 'Basic'; @@ -958,7 +958,7 @@ public function prepareValueAndOperator($value, $operator, $useDefault = false) protected function invalidOperatorAndValue($operator, $value) { return is_null($value) && in_array($operator, $this->operators) && - ! in_array($operator, ['=', '<>', '!=']); + ! in_array($operator, ['=', '<=>', '<>', '!=']); } /** diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 95142e0b698c..0f205174ea37 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -5030,6 +5030,10 @@ public function testProvidingNullWithOperatorsBuildsCorrectly() $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('foo', '<>', null); $this->assertSame('select * from "users" where "foo" is not null', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('foo', '<=>', null); + $this->assertSame('select * from "users" where "foo" is null', $builder->toSql()); } public function testDynamicWhere() From 16ad0665581303ea01ef01c0f9b6000cf0728f0c Mon Sep 17 00:00:00 2001 From: Tom Moore Date: Thu, 27 Mar 2025 18:13:20 +0100 Subject: [PATCH 254/455] [12.x] Fix: Make Paginated Queries Consistent Across Pages (#55176) * Add failing tests * Make paginated queries more consistent across pages --- src/Illuminate/Database/Query/Builder.php | 8 ++++++-- tests/Database/DatabaseQueryBuilderTest.php | 22 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0ee40c971872..d62b7b247147 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2790,7 +2790,9 @@ public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') { $this->orders = $this->removeExistingOrdersFor($column); - if (! is_null($lastId)) { + if (is_null($lastId)) { + $this->whereNotNull($column); + } else { $this->where($column, '<', $lastId); } @@ -2810,7 +2812,9 @@ public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') { $this->orders = $this->removeExistingOrdersFor($column); - if (! is_null($lastId)) { + if (is_null($lastId)) { + $this->whereNotNull($column); + } else { $this->where($column, '>', $lastId); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 0f205174ea37..e93994ec748a 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2360,6 +2360,28 @@ public function testForPage() $this->assertSame('select * from "users" limit 0 offset 0', $builder->toSql()); } + public function testForPageBeforeId() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->forPageBeforeId(15, null); + $this->assertSame('select * from "users" where "id" is not null order by "id" desc limit 15', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->forPageBeforeId(15, 0); + $this->assertSame('select * from "users" where "id" < ? order by "id" desc limit 15', $builder->toSql()); + } + + public function testForPageAfterId() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->forPageAfterId(15, null); + $this->assertSame('select * from "users" where "id" is not null order by "id" asc limit 15', $builder->toSql()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->forPageAfterId(15, 0); + $this->assertSame('select * from "users" where "id" > ? order by "id" asc limit 15', $builder->toSql()); + } + public function testGetCountForPaginationWithBindings() { $builder = $this->getBuilder(); From 0b0a274cd46d3f2efcd9fe8dd459f77cce0945ce Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 28 Mar 2025 04:18:55 +1100 Subject: [PATCH 255/455] [12.x] Add `pipe` method query builders (#55171) * Update tap description * Add pipe method to query builder * Add eloquent query builder tests * Fix builder return type in type tests * Add eloquent builder type tests * Reorganise type tests * Fix broken return syntax * Improve types --- .../Database/Concerns/BuildsQueries.php | 15 ++++++++++- .../Database/DatabaseEloquentBuilderTest.php | 26 +++++++++++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 21 +++++++++++++++ types/Database/Eloquent/Builder.php | 6 +++++ types/Database/Query/Builder.php | 6 +++++ 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 253fe516d438..f78e13b2d500 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -587,7 +587,7 @@ protected function cursorPaginator($items, $perPage, $cursor, $options) } /** - * Pass the query to a given callback. + * Pass the query to a given callback and then return it. * * @param callable($this): mixed $callback * @return $this @@ -598,4 +598,17 @@ public function tap($callback) return $this; } + + /** + * Pass the query to a given callback and return the result. + * + * @template TReturn + * + * @param (callable($this): TReturn) $callback + * @return (TReturn is null|void ? $this : TReturn) + */ + public function pipe($callback) + { + return $callback($this) ?? $this; + } } diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index a3ba7837cc2d..41e5fa529877 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -21,6 +21,7 @@ use Illuminate\Support\Carbon; use Illuminate\Support\Collection as BaseCollection; use Mockery as m; +use PDO; use PHPUnit\Framework\TestCase; use stdClass; @@ -2615,6 +2616,31 @@ public function getPassthru(): array } } + public function testPipeCallback() + { + $query = new Builder(new BaseBuilder( + $connection = new Connection(new PDO('sqlite::memory:')), + new Grammar($connection), + new Processor, + )); + + $result = $query->pipe(fn (Builder $query) => 5); + $this->assertSame(5, $result); + + $result = $query->pipe(fn (Builder $query) => null); + $this->assertSame($query, $result); + + $result = $query->pipe(function (Builder $query) { + // + }); + $this->assertSame($query, $result); + + $this->assertCount(0, $query->getQuery()->wheres); + $result = $query->pipe(fn (Builder $query) => $query->where('foo', 'bar')); + $this->assertSame($query, $result); + $this->assertCount(1, $query->getQuery()->wheres); + } + protected function mockConnectionForModel($model, $database) { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index e93994ec748a..45d0e98a3c1c 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -301,6 +301,27 @@ public function testTapCallback() $this->assertSame('select * from "users" where "id" = ? and "email" = ?', $builder->toSql()); } + public function testPipeCallback() + { + $query = $this->getBuilder(); + + $result = $query->pipe(fn (Builder $query) => 5); + $this->assertSame(5, $result); + + $result = $query->pipe(fn (Builder $query) => null); + $this->assertSame($query, $result); + + $result = $query->pipe(function (Builder $query) { + // + }); + $this->assertSame($query, $result); + + $this->assertCount(0, $query->wheres); + $result = $query->pipe(fn (Builder $query) => $query->where('foo', 'bar')); + $this->assertSame($query, $result); + $this->assertCount(1, $query->wheres); + } + public function testBasicWheres() { $builder = $this->getBuilder(); diff --git a/types/Database/Eloquent/Builder.php b/types/Database/Eloquent/Builder.php index fe11459c1875..24f03fc71f99 100644 --- a/types/Database/Eloquent/Builder.php +++ b/types/Database/Eloquent/Builder.php @@ -223,6 +223,12 @@ function test( assertType('Illuminate\Types\Builder\CommentBuilder', $comment->newQuery()->where('foo', 'bar')); assertType('Illuminate\Types\Builder\CommentBuilder', $comment->newQuery()->foo()); assertType('Illuminate\Types\Builder\Comment', $comment->newQuery()->create(['name' => 'John'])); + assertType('Illuminate\Database\Eloquent\Builder', $query->pipe(function () { + // + })); + assertType('Illuminate\Database\Eloquent\Builder', $query->pipe(fn () => null)); + assertType('Illuminate\Database\Eloquent\Builder', $query->pipe(fn ($query) => $query)); + assertType('5', $query->pipe(fn ($query) => 5)); } class User extends Model diff --git a/types/Database/Query/Builder.php b/types/Database/Query/Builder.php index c5917edf6b20..780630bdd39c 100644 --- a/types/Database/Query/Builder.php +++ b/types/Database/Query/Builder.php @@ -60,4 +60,10 @@ function test(Builder $query, EloquentBuilder $userQuery): void assertType('object', $users); assertType('int', $page); }); + assertType('Illuminate\Database\Query\Builder', $query->pipe(function () { + // + })); + assertType('Illuminate\Database\Query\Builder', $query->pipe(fn () => null)); + assertType('Illuminate\Database\Query\Builder', $query->pipe(fn ($query) => $query)); + assertType('5', $query->pipe(fn ($query) => 5)); } From 91250d939b45644cdac5ce1e57b58676650a58b4 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Thu, 27 Mar 2025 12:23:23 -0500 Subject: [PATCH 256/455] [12.x] fix: one of many subquery constraints (#55168) * fix: one of many subquery constraints * fix: backout Relation::addConstraints signature change * Update HasOneThrough.php * Update HasOneOrManyThrough.php --------- Co-authored-by: Taylor Otwell --- .../Relations/Concerns/CanBeOneOfMany.php | 2 ++ .../Eloquent/Relations/HasOneOrManyThrough.php | 8 +++++--- .../Database/Eloquent/Relations/HasOneThrough.php | 5 ++++- .../Database/DatabaseEloquentHasOneOfManyTest.php | 15 +++++++++++---- .../DatabaseEloquentHasOneThroughOfManyTest.php | 10 +++++----- .../DatabaseEloquentMorphOneOfManyTest.php | 2 +- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php index 0240f7f59529..800999f86c78 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php @@ -131,6 +131,8 @@ public function ofMany($column = 'id', $aggregate = 'MAX', $relation = null) ]; } + $this->addConstraints(); + $columns = $this->query->getQuery()->columns; if (is_null($columns) || $columns === ['*']) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index 9b2ac58a3a50..97c011d6cefb 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -97,12 +97,14 @@ public function __construct(Builder $query, Model $farParent, Model $throughPare */ public function addConstraints() { + $query = $this->getRelationQuery(); + $localValue = $this->farParent[$this->localKey]; - $this->performJoin(); + $this->performJoin($query); if (static::$constraints) { - $this->query->where($this->getQualifiedFirstKeyName(), '=', $localValue); + $query->where($this->getQualifiedFirstKeyName(), '=', $localValue); } } @@ -114,7 +116,7 @@ public function addConstraints() */ protected function performJoin(?Builder $query = null) { - $query = $query ?: $this->query; + $query ??= $this->query; $farKey = $this->getQualifiedFarKeyName(); diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php index 5567124bde5b..4d42007f037f 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php @@ -78,7 +78,10 @@ public function addOneOfManySubQueryConstraints(Builder $query, $column = null, { $query->addSelect([$this->getQualifiedFirstKeyName()]); - $this->performJoin($query); + // We need to join subqueries that aren't the inner-most subquery which is joined in the CanBeOneOfMany::ofMany method... + if ($this->getOneOfManySubQuery() !== null) { + $this->performJoin($query); + } } /** @inheritDoc */ diff --git a/tests/Database/DatabaseEloquentHasOneOfManyTest.php b/tests/Database/DatabaseEloquentHasOneOfManyTest.php index dff1fdd9e79d..c47f0178c22a 100755 --- a/tests/Database/DatabaseEloquentHasOneOfManyTest.php +++ b/tests/Database/DatabaseEloquentHasOneOfManyTest.php @@ -99,12 +99,19 @@ public function testRelationNameCanBeSet() $this->assertSame('baz', $relation->getRelationName()); } + public function testCorrectLatestOfManyQuery(): void + { + $user = HasOneOfManyTestUser::create(); + $relation = $user->latest_login(); + $this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null group by "logins"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toSql()); + } + public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery() { $user = HasOneOfManyTestUser::create(); $relation = $user->latest_login(); $relation->addEagerConstraints([$user]); - $this->assertSame('select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" in (1) group by "logins"."user_id"', $relation->getOneOfManySubQuery()->toSql()); + $this->assertSame('select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id"', $relation->getOneOfManySubQuery()->toSql()); } public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalScope() @@ -116,7 +123,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco $user = HasOneOfManyTestUser::create(); $relation = $user->latest_login_without_global_scope(); $relation->addEagerConstraints([$user]); - $this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" in (1) group by "logins"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toSql()); + $this->assertSame('select "logins".* from "logins" inner join (select MAX("logins"."id") as "id_aggregate", "logins"."user_id" from "logins" where "logins"."user_id" = ? and "logins"."user_id" is not null and "logins"."user_id" in (1) group by "logins"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "logins"."user_id" where "logins"."user_id" = ? and "logins"."user_id" is not null', $relation->getQuery()->toSql()); HasOneOfManyTestLogin::addGlobalScope('test', function ($query) { }); @@ -130,7 +137,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco $user = HasOneOfManyTestUser::create(); $relation = $user->price_without_global_scope(); - $this->assertSame('select "prices".* from "prices" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" inner join (select max("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "prices"."user_id" = ? and "prices"."user_id" is not null', $relation->getQuery()->toSql()); + $this->assertSame('select "prices".* from "prices" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" inner join (select max("prices"."published_at") as "published_at_aggregate", "prices"."user_id" from "prices" where "published_at" < ? and "prices"."user_id" = ? and "prices"."user_id" is not null group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "published_at" < ? group by "prices"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "prices"."user_id" where "prices"."user_id" = ? and "prices"."user_id" is not null', $relation->getQuery()->toSql()); HasOneOfManyTestPrice::addGlobalScope('test', function ($query) { }); @@ -591,7 +598,7 @@ public function states() public function foo_state() { return $this->hasOne(HasOneOfManyTestState::class, 'user_id')->ofMany( - ['id' => 'max'], + [], // should automatically add 'id' => 'max' function ($q) { $q->where('type', 'foo'); } diff --git a/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php b/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php index 0d2e5d671ca5..b4959738a981 100755 --- a/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php +++ b/tests/Database/DatabaseEloquentHasOneThroughOfManyTest.php @@ -98,7 +98,7 @@ public function testCorrectLatestOfManyQuery(): void { $user = HasOneThroughOfManyTestUser::create(); $relation = $user->latest_login(); - $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" group by "intermediates"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" = ? group by "intermediates"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); } public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery(): void @@ -106,7 +106,7 @@ public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery(): void $user = HasOneThroughOfManyTestUser::create(); $relation = $user->latest_login(); $relation->addEagerConstraints([$user]); - $this->assertSame('select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" in (1) group by "intermediates"."user_id"', $relation->getOneOfManySubQuery()->toSql()); + $this->assertSame('select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" = ? and "intermediates"."user_id" in (1) group by "intermediates"."user_id"', $relation->getOneOfManySubQuery()->toSql()); } public function testEagerLoadingAppliesConstraintsToQuery(): void @@ -114,7 +114,7 @@ public function testEagerLoadingAppliesConstraintsToQuery(): void $user = HasOneThroughOfManyTestUser::create(); $relation = $user->latest_login(); $relation->addEagerConstraints([$user]); - $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" in (1) group by "intermediates"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" = ? and "intermediates"."user_id" in (1) group by "intermediates"."user_id") as "latest_login" on "latest_login"."id_aggregate" = "logins"."id" and "latest_login"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); } public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalScope(): void @@ -126,7 +126,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco $user = HasOneThroughOfManyTestUser::create(); $relation = $user->latest_login_without_global_scope(); $relation->addEagerConstraints([$user]); - $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" in (1) group by "intermediates"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + $this->assertSame('select "logins".* from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" inner join (select MAX("logins"."id") as "id_aggregate", "intermediates"."user_id" from "logins" inner join "intermediates" on "intermediates"."id" = "logins"."intermediate_id" where "intermediates"."user_id" = ? and "intermediates"."user_id" in (1) group by "intermediates"."user_id") as "latestOfMany" on "latestOfMany"."id_aggregate" = "logins"."id" and "latestOfMany"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); HasOneThroughOfManyTestLogin::addGlobalScope('test', function ($query) { }); @@ -140,7 +140,7 @@ public function testGlobalScopeIsNotAppliedWhenRelationIsDefinedWithoutGlobalSco $user = HasOneThroughOfManyTestUser::create(); $relation = $user->price_without_global_scope(); - $this->assertSame('select "prices".* from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "intermediates"."user_id" from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" inner join (select max("prices"."published_at") as "published_at_aggregate", "intermediates"."user_id" from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" where "published_at" < ? group by "intermediates"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "intermediates"."user_id" where "published_at" < ? group by "intermediates"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); + $this->assertSame('select "prices".* from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" inner join (select max("prices"."id") as "id_aggregate", min("prices"."published_at") as "published_at_aggregate", "intermediates"."user_id" from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" inner join (select max("prices"."published_at") as "published_at_aggregate", "intermediates"."user_id" from "prices" inner join "intermediates" on "intermediates"."id" = "prices"."intermediate_id" where "published_at" < ? and "intermediates"."user_id" = ? group by "intermediates"."user_id") as "price_without_global_scope" on "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "intermediates"."user_id" where "published_at" < ? group by "intermediates"."user_id") as "price_without_global_scope" on "price_without_global_scope"."id_aggregate" = "prices"."id" and "price_without_global_scope"."published_at_aggregate" = "prices"."published_at" and "price_without_global_scope"."user_id" = "intermediates"."user_id" where "intermediates"."user_id" = ?', $relation->getQuery()->toSql()); HasOneThroughOfManyTestPrice::addGlobalScope('test', function ($query) { }); diff --git a/tests/Database/DatabaseEloquentMorphOneOfManyTest.php b/tests/Database/DatabaseEloquentMorphOneOfManyTest.php index 9f04afe3ab86..f565819dd7cf 100644 --- a/tests/Database/DatabaseEloquentMorphOneOfManyTest.php +++ b/tests/Database/DatabaseEloquentMorphOneOfManyTest.php @@ -58,7 +58,7 @@ public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery() $product = MorphOneOfManyTestProduct::create(); $relation = $product->current_state(); $relation->addEagerConstraints([$product]); - $this->assertSame('select MAX("states"."id") as "id_aggregate", "states"."stateful_id", "states"."stateful_type" from "states" where "states"."stateful_id" in (1) and "states"."stateful_type" = ? group by "states"."stateful_id", "states"."stateful_type"', $relation->getOneOfManySubQuery()->toSql()); + $this->assertSame('select MAX("states"."id") as "id_aggregate", "states"."stateful_id", "states"."stateful_type" from "states" where "states"."stateful_type" = ? and "states"."stateful_id" = ? and "states"."stateful_id" is not null and "states"."stateful_id" in (1) and "states"."stateful_type" = ? group by "states"."stateful_id", "states"."stateful_type"', $relation->getOneOfManySubQuery()->toSql()); } public function testReceivingModel() From 386d1680616437f532a3770de7fdb6e779b96e78 Mon Sep 17 00:00:00 2001 From: saibotk Date: Thu, 27 Mar 2025 18:28:53 +0100 Subject: [PATCH 257/455] fix(postgres): missing parentheses in whereDate/whereTime for json columns (#55159) In https://github.com/laravel/framework/pull/12341, the cast to `::date` was added to `whereDate`. This leads to an error with PostgreSQL when passing in json column selectors. For example: `->whereDate('result->created_at', DB::raw('NOW()'))` will throw a syntax error for type date. The same is true for the `whereTime` function with its `::time` cast. To fix this, we need to wrap the column identifier in parentheses, when they are json paths. Current SQL output: ```SQL select * from "users" where "result"->>'created_at'::date = NOW() ``` Correct SQL output with this commit: ```SQL select * from "users" where ("result"->>'created_at')::date = NOW() ``` --- .../Database/Query/Grammars/PostgresGrammar.php | 14 ++++++++++++-- tests/Database/DatabaseQueryBuilderTest.php | 9 +++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index 2103f6c906fe..9726de5aec2c 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -109,8 +109,13 @@ protected function whereLike(Builder $query, $where) protected function whereDate(Builder $query, $where) { $value = $this->parameter($where['value']); + $column = $this->wrap($where['column']); - return $this->wrap($where['column']).'::date '.$where['operator'].' '.$value; + if ($this->isJsonSelector($where['column'])) { + $column = '('.$column.')'; + } + + return $column.'::date '.$where['operator'].' '.$value; } /** @@ -123,8 +128,13 @@ protected function whereDate(Builder $query, $where) protected function whereTime(Builder $query, $where) { $value = $this->parameter($where['value']); + $column = $this->wrap($where['column']); + + if ($this->isJsonSelector($where['column'])) { + $column = '('.$column.')'; + } - return $this->wrap($where['column']).'::time '.$where['operator'].' '.$value; + return $column.'::time '.$where['operator'].' '.$value; } /** diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 45d0e98a3c1c..9c89ef66eac9 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -614,6 +614,10 @@ public function testWhereDatePostgres() $builder = $this->getPostgresBuilder(); $builder->select('*')->from('users')->whereDate('created_at', new Raw('NOW()')); $this->assertSame('select * from "users" where "created_at"::date = NOW()', $builder->toSql()); + + $builder = $this->getPostgresBuilder(); + $builder->select('*')->from('users')->whereDate('result->created_at', new Raw('NOW()')); + $this->assertSame('select * from "users" where ("result"->>\'created_at\')::date = NOW()', $builder->toSql()); } public function testWhereDayPostgres() @@ -646,6 +650,11 @@ public function testWhereTimePostgres() $builder->select('*')->from('users')->whereTime('created_at', '>=', '22:00'); $this->assertSame('select * from "users" where "created_at"::time >= ?', $builder->toSql()); $this->assertEquals([0 => '22:00'], $builder->getBindings()); + + $builder = $this->getPostgresBuilder(); + $builder->select('*')->from('users')->whereTime('result->created_at', '>=', '22:00'); + $this->assertSame('select * from "users" where ("result"->>\'created_at\')::time >= ?', $builder->toSql()); + $this->assertEquals([0 => '22:00'], $builder->getBindings()); } public function testWherePast() From fff733f43751838dbc17a58af3f5684f552b50ff Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 27 Mar 2025 10:29:36 -0700 Subject: [PATCH 258/455] formatting --- src/Illuminate/Database/Query/Grammars/PostgresGrammar.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index 9726de5aec2c..14bac8da75e9 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -108,8 +108,8 @@ protected function whereLike(Builder $query, $where) */ protected function whereDate(Builder $query, $where) { - $value = $this->parameter($where['value']); $column = $this->wrap($where['column']); + $value = $this->parameter($where['value']); if ($this->isJsonSelector($where['column'])) { $column = '('.$column.')'; @@ -127,8 +127,8 @@ protected function whereDate(Builder $query, $where) */ protected function whereTime(Builder $query, $where) { - $value = $this->parameter($where['value']); $column = $this->wrap($where['column']); + $value = $this->parameter($where['value']); if ($this->isJsonSelector($where['column'])) { $column = '('.$column.')'; From aa1128c0e887e7c75d17bbae643fa8a86b9c33dc Mon Sep 17 00:00:00 2001 From: David Stoker Date: Thu, 27 Mar 2025 14:57:01 -0400 Subject: [PATCH 259/455] Fix creation of a Factory via attribute so that configure method is called (#55190) --- src/Illuminate/Database/Eloquent/Factories/HasFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/HasFactory.php b/src/Illuminate/Database/Eloquent/Factories/HasFactory.php index ca37657def04..d2747cc93c30 100644 --- a/src/Illuminate/Database/Eloquent/Factories/HasFactory.php +++ b/src/Illuminate/Database/Eloquent/Factories/HasFactory.php @@ -52,7 +52,7 @@ protected static function getUseFactoryAttribute() if ($attributes !== []) { $useFactory = $attributes[0]->newInstance(); - $factory = new $useFactory->factoryClass; + $factory = $useFactory->factoryClass::new(); $factory->guessModelNamesUsing(fn () => static::class); From d4776ffd8f0e33c9eec26ac4d09a0858a7d64ea9 Mon Sep 17 00:00:00 2001 From: Danylo Kolodij <46485085+chaker2710@users.noreply.github.com> Date: Thu, 27 Mar 2025 20:57:31 +0200 Subject: [PATCH 260/455] [12.x] Fix Concurrency::run to preserve callback result order (#55161) * Fix Concurrency::run to preserve result order matching the input callbacks * CS fix * CS fix --- src/Illuminate/Concurrency/ForkDriver.php | 2 + .../Concurrency/ConcurrencyTest.php | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Illuminate/Concurrency/ForkDriver.php b/src/Illuminate/Concurrency/ForkDriver.php index 4460449c78e4..732873a72ee9 100644 --- a/src/Illuminate/Concurrency/ForkDriver.php +++ b/src/Illuminate/Concurrency/ForkDriver.php @@ -25,6 +25,8 @@ public function run(Closure|array $tasks): array /** @phpstan-ignore class.notFound */ $results = Fork::new()->run(...$values); + ksort($results); + return array_combine($keys, $results); } diff --git a/tests/Integration/Concurrency/ConcurrencyTest.php b/tests/Integration/Concurrency/ConcurrencyTest.php index 6fd3a5bdfd0f..6de1ac4bbb6f 100644 --- a/tests/Integration/Concurrency/ConcurrencyTest.php +++ b/tests/Integration/Concurrency/ConcurrencyTest.php @@ -8,6 +8,7 @@ use Illuminate\Process\Factory as ProcessFactory; use Illuminate\Support\Facades\Concurrency; use Orchestra\Testbench\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\RequiresOperatingSystem; #[RequiresOperatingSystem('Linux|DAR')] @@ -119,6 +120,42 @@ public function testRunHandlerProcessErrorWithCustomExceptionWithParam() ), ]); } + + public static function getConcurrencyDrivers(): array + { + return [ + ['sync'], + ['process'], + // spatie/fork package is not included by default + // ['fork'], + ]; + } + + #[DataProvider('getConcurrencyDrivers')] + public function testRunPreservesCallbackOrder(string $driver) + { + [$first, $second, $third] = Concurrency::driver($driver)->run([ + function () { + usleep(1000000); + + return 'first'; + }, + function () { + usleep(500000); + + return 'second'; + }, + function () { + usleep(200000); + + return 'third'; + }, + ]); + + $this->assertEquals('first', $first); + $this->assertEquals('second', $second); + $this->assertEquals('third', $third); + } } class ExceptionWithoutParam extends Exception From 87e43e6d6404a3f519f0d710f21c1a1f8c7ef51c Mon Sep 17 00:00:00 2001 From: Matt Roy Lloyd Date: Thu, 27 Mar 2025 19:06:10 +0000 Subject: [PATCH 261/455] [12.x] Log: Add optional keys parameter to `Log::withoutContext` to remove selected context from future logs (#55181) * feat(log): pass context keys to withoutContext to forget * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Log/LogManager.php | 5 +++-- src/Illuminate/Log/Logger.php | 11 ++++++++--- src/Illuminate/Support/Facades/Log.php | 2 +- tests/Log/LogLoggerTest.php | 11 +++++++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index f6a8b7cf0765..da69039adcb1 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -514,13 +514,14 @@ public function sharedContext() /** * Flush the log context on all currently resolved channels. * + * @param string[]|null $keys * @return $this */ - public function withoutContext() + public function withoutContext(?array $keys = null) { foreach ($this->channels as $channel) { if (method_exists($channel, 'withoutContext')) { - $channel->withoutContext(); + $channel->withoutContext($keys); } } diff --git a/src/Illuminate/Log/Logger.php b/src/Illuminate/Log/Logger.php index f14536c7ccd7..c378d9dbbc69 100755 --- a/src/Illuminate/Log/Logger.php +++ b/src/Illuminate/Log/Logger.php @@ -202,13 +202,18 @@ public function withContext(array $context = []) } /** - * Flush the existing context array. + * Flush the log context on all currently resolved channels. * + * @param string[]|null $keys * @return $this */ - public function withoutContext() + public function withoutContext(?array $keys = null) { - $this->context = []; + if (is_array($keys)) { + $this->context = array_diff_key($this->context, array_flip($keys)); + } else { + $this->context = []; + } return $this; } diff --git a/src/Illuminate/Support/Facades/Log.php b/src/Illuminate/Support/Facades/Log.php index 88c04028dc0c..fad58f3698f9 100755 --- a/src/Illuminate/Support/Facades/Log.php +++ b/src/Illuminate/Support/Facades/Log.php @@ -9,7 +9,7 @@ * @method static \Psr\Log\LoggerInterface driver(string|null $driver = null) * @method static \Illuminate\Log\LogManager shareContext(array $context) * @method static array sharedContext() - * @method static \Illuminate\Log\LogManager withoutContext() + * @method static \Illuminate\Log\LogManager withoutContext(string[]|null $keys = null) * @method static \Illuminate\Log\LogManager flushSharedContext() * @method static string|null getDefaultDriver() * @method static void setDefaultDriver(string $name) diff --git a/tests/Log/LogLoggerTest.php b/tests/Log/LogLoggerTest.php index 41163d6d25ee..85cc1799cf0e 100755 --- a/tests/Log/LogLoggerTest.php +++ b/tests/Log/LogLoggerTest.php @@ -47,6 +47,17 @@ public function testContextIsFlushed() $writer->error('foo'); } + public function testContextKeysCanBeRemovedForSubsequentLogs() + { + $writer = new Logger($monolog = m::mock(Monolog::class)); + $writer->withContext(['bar' => 'baz', 'forget' => 'me']); + $writer->withoutContext(['forget']); + + $monolog->shouldReceive('error')->once()->with('foo', ['bar' => 'baz']); + + $writer->error('foo'); + } + public function testLoggerFiresEventsDispatcher() { $writer = new Logger($monolog = m::mock(Monolog::class), $events = new Dispatcher); From 543867d60be0e268fee60f094101447fa73eaf8a Mon Sep 17 00:00:00 2001 From: Faissal Wahabali Date: Sat, 29 Mar 2025 16:55:55 +0000 Subject: [PATCH 262/455] [12.x] Add `Expression` type to param `$value` of `QueryBuilder` `having()` method (#55200) * add Expression type to QueryBuilder having() * Update Builder.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Query/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index d62b7b247147..cb509f8ffebd 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2399,7 +2399,7 @@ public function groupByRaw($sql, array $bindings = []) * * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column * @param \DateTimeInterface|string|int|float|null $operator - * @param \DateTimeInterface|string|int|float|null $value + * @param \Illuminate\Contracts\Database\Query\Expression|\DateTimeInterface|string|int|float|null $value * @param string $boolean * @return $this */ From 4b9c9a49059275593f5f2645ad0009ad58cf95fc Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Sat, 29 Mar 2025 12:16:48 -0500 Subject: [PATCH 263/455] [12.x] Add flag to disable where clauses for `withAttributes` method on Eloquent Builder (#55199) * feat: add pending attributes to withAttributes method on Eloquent relationships * feat: add ability to disable where clauses when calling withAttributes * formatting * update tests --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Eloquent/Builder.php | 9 +- ...BelongsToManyWithAttributesPendingTest.php | 256 +++++++++++++++ ...tHasOneOrManyWithAttributesPendingTest.php | 307 ++++++++++++++++++ ...abaseEloquentWithAttributesPendingTest.php | 153 +++++++++ 4 files changed, 722 insertions(+), 3 deletions(-) create mode 100644 tests/Database/DatabaseEloquentBelongsToManyWithAttributesPendingTest.php create mode 100644 tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php create mode 100644 tests/Database/DatabaseEloquentWithAttributesPendingTest.php diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 192a707235bd..8d29884faf0b 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1819,16 +1819,19 @@ protected function addNestedWiths($name, $results) * * @param \Illuminate\Contracts\Database\Query\Expression|array|string $attributes * @param mixed $value + * @param bool $asConditions * @return $this */ - public function withAttributes(Expression|array|string $attributes, $value = null) + public function withAttributes(Expression|array|string $attributes, $value = null, $asConditions = true) { if (! is_array($attributes)) { $attributes = [$attributes => $value]; } - foreach ($attributes as $column => $value) { - $this->where($this->qualifyColumn($column), $value); + if ($asConditions) { + foreach ($attributes as $column => $value) { + $this->where($this->qualifyColumn($column), $value); + } } $this->pendingAttributes = array_merge($this->pendingAttributes, $attributes); diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithAttributesPendingTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithAttributesPendingTest.php new file mode 100644 index 000000000000..673cbc525f70 --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManyWithAttributesPendingTest.php @@ -0,0 +1,256 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->bootEloquent(); + $db->setAsGlobal(); + $this->createSchema(); + } + + public function testCreatesPendingAttributesAndPivotValues(): void + { + $post = ManyToManyPendingAttributesPost::create(); + $tag = $post->metaTags()->create(['name' => 'long article']); + + $this->assertSame('long article', $tag->name); + $this->assertTrue($tag->visible); + + $pivot = DB::table('pending_attributes_pivot')->first(); + $this->assertSame('meta', $pivot->type); + $this->assertSame($post->id, $pivot->post_id); + $this->assertSame($tag->id, $pivot->tag_id); + } + + public function testQueriesPendingAttributesAndPivotValues(): void + { + $post = new ManyToManyPendingAttributesPost(['id' => 2]); + $wheres = $post->metaTags()->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_pivot.tag_id', + 'operator' => '=', + 'value' => 2, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_pivot.type', + 'operator' => '=', + 'value' => 'meta', + 'boolean' => 'and', + ], $wheres); + + // Ensure no other wheres exist + $this->assertCount(2, $wheres); + } + + public function testMorphToManyPendingAttributes(): void + { + $post = new ManyToManyPendingAttributesPost(['id' => 2]); + $wheres = $post->morphedTags()->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_taggables.type', + 'operator' => '=', + 'value' => 'meta', + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_taggables.taggable_type', + 'operator' => '=', + 'value' => ManyToManyPendingAttributesPost::class, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_taggables.taggable_id', + 'operator' => '=', + 'value' => 2, + 'boolean' => 'and', + ], $wheres); + + // Ensure no other wheres exist + $this->assertCount(3, $wheres); + + $tag = $post->morphedTags()->create(['name' => 'new tag']); + + $this->assertTrue($tag->visible); + $this->assertSame('new tag', $tag->name); + $this->assertSame($tag->id, $post->morphedTags()->first()->id); + } + + public function testMorphedByManyPendingAttributes(): void + { + $tag = new ManyToManyPendingAttributesTag(['id' => 4]); + $wheres = $tag->morphedPosts()->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_taggables.type', + 'operator' => '=', + 'value' => 'meta', + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_taggables.taggable_type', + 'operator' => '=', + 'value' => ManyToManyPendingAttributesPost::class, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'pending_attributes_taggables.tag_id', + 'operator' => '=', + 'value' => 4, + 'boolean' => 'and', + ], $wheres); + + // Ensure no other wheres exist + $this->assertCount(3, $wheres); + + $post = $tag->morphedPosts()->create(); + $this->assertSame('Title!', $post->title); + $this->assertSame($post->id, $tag->morphedPosts()->first()->id); + } + + protected function createSchema() + { + $this->schema()->create('pending_attributes_posts', function ($table) { + $table->increments('id'); + $table->string('title')->nullable(); + $table->timestamps(); + }); + + $this->schema()->create('pending_attributes_tags', function ($table) { + $table->increments('id'); + $table->string('name'); + $table->boolean('visible')->nullable(); + $table->timestamps(); + }); + + $this->schema()->create('pending_attributes_pivot', function ($table) { + $table->integer('post_id'); + $table->integer('tag_id'); + $table->string('type'); + }); + + $this->schema()->create('pending_attributes_taggables', function ($table) { + $table->integer('tag_id'); + $table->integer('taggable_id'); + $table->string('taggable_type'); + $table->string('type'); + }); + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + $this->schema()->drop('pending_attributes_posts'); + $this->schema()->drop('pending_attributes_tags'); + $this->schema()->drop('pending_attributes_pivot'); + } + + /** + * Get a database connection instance. + * + * @return \Illuminate\Database\Connection + */ + protected function connection($connection = 'default') + { + return Model::getConnectionResolver()->connection($connection); + } + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema($connection = 'default') + { + return $this->connection($connection)->getSchemaBuilder(); + } +} + +class ManyToManyPendingAttributesPost extends Model +{ + protected $guarded = []; + protected $table = 'pending_attributes_posts'; + + public function tags(): BelongsToMany + { + return $this->belongsToMany( + ManyToManyPendingAttributesTag::class, + 'pending_attributes_pivot', + 'tag_id', + 'post_id', + ); + } + + public function metaTags(): BelongsToMany + { + return $this->tags() + ->withAttributes('visible', true, asConditions: false) + ->withPivotValue('type', 'meta'); + } + + public function morphedTags(): MorphToMany + { + return $this + ->morphToMany( + ManyToManyPendingAttributesTag::class, + 'taggable', + 'pending_attributes_taggables', + relatedPivotKey: 'tag_id' + ) + ->withAttributes('visible', true, asConditions: false) + ->withPivotValue('type', 'meta'); + } +} + +class ManyToManyPendingAttributesTag extends Model +{ + protected $guarded = []; + protected $table = 'pending_attributes_tags'; + + public function morphedPosts(): MorphToMany + { + return $this + ->morphedByMany( + ManyToManyPendingAttributesPost::class, + 'taggable', + 'pending_attributes_taggables', + 'tag_id', + ) + ->withAttributes('title', 'Title!', asConditions: false) + ->withPivotValue('type', 'meta'); + } +} diff --git a/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php new file mode 100644 index 000000000000..dac4e83de226 --- /dev/null +++ b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php @@ -0,0 +1,307 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->bootEloquent(); + $db->setAsGlobal(); + } + + public function testHasManyAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value], asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testHasOneAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasOne(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value], asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testMorphManyAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->morphMany(RelatedPendingAttributesModel::class, 'relatable') + ->withAttributes([$key => $value], asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->relatable_id); + $this->assertSame($parent::class, $relatedModel->relatable_type); + $this->assertSame($value, $relatedModel->$key); + } + + public function testMorphOneAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->morphOne(RelatedPendingAttributesModel::class, 'relatable') + ->withAttributes([$key => $value], asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->relatable_id); + $this->assertSame($parent::class, $relatedModel->relatable_type); + $this->assertSame($value, $relatedModel->$key); + } + + public function testPendingAttributesCanBeOverriden(): void + { + $key = 'a key'; + $defaultValue = 'a value'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'relatable') + ->withAttributes([$key => $defaultValue], asConditions: false); + + $relatedModel = $relationship->make([$key => $value]); + + $this->assertSame($value, $relatedModel->$key); + } + + public function testQueryingDoesNotBreakWither(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->where($key, $value) + ->withAttributes([$key => $value], asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testAttributesCanBeAppended(): void + { + $parent = new RelatedPendingAttributesModel; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes(['a' => 'A'], asConditions: false) + ->withAttributes(['b' => 'B'], asConditions: false) + ->withAttributes(['a' => 'AA'], asConditions: false); + + $relatedModel = $relationship->make([ + 'b' => 'BB', + 'c' => 'C', + ]); + + $this->assertSame('AA', $relatedModel->a); + $this->assertSame('BB', $relatedModel->b); + $this->assertSame('C', $relatedModel->c); + } + + public function testSingleAttributeApi(): void + { + $parent = new RelatedPendingAttributesModel; + $key = 'attr'; + $value = 'Value'; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes($key, $value, asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($value, $relatedModel->$key); + } + + public function testWheresAreNotSet(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value], asConditions: false); + + $wheres = $relationship->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => $parent->qualifyColumn('parent_id'), + 'operator' => '=', + 'value' => $parentId, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'NotNull', + 'column' => $parent->qualifyColumn('parent_id'), + 'boolean' => 'and', + ], $wheres); + + // Ensure no other wheres exist + $this->assertCount(2, $wheres); + } + + public function testNullValueIsAccepted(): void + { + $parentId = 123; + $key = 'a key'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes([$key => null], asConditions: false); + + $wheres = $relationship->toBase()->wheres; + $relatedModel = $relationship->make(); + + $this->assertNull($relatedModel->$key); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => $parent->qualifyColumn('parent_id'), + 'operator' => '=', + 'value' => $parentId, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'NotNull', + 'column' => $parent->qualifyColumn('parent_id'), + 'boolean' => 'and', + ], $wheres); + + // Ensure no other wheres exist + $this->assertCount(2, $wheres); + } + + public function testOneKeepsAttributesFromHasMany(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value], asConditions: false) + ->one(); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testOneKeepsAttributesFromMorphMany(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->morphMany(RelatedPendingAttributesModel::class, 'relatable') + ->withAttributes([$key => $value], asConditions: false) + ->one(); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->relatable_id); + $this->assertSame($parent::class, $relatedModel->relatable_type); + $this->assertSame($value, $relatedModel->$key); + } + + public function testHasManyAddsCastedAttributes(): void + { + $parentId = 123; + + $parent = new RelatedPendingAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedPendingAttributesModel::class, 'parent_id') + ->withAttributes(['is_admin' => 1], asConditions: false); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame(true, $relatedModel->is_admin); + } +} + +class RelatedPendingAttributesModel extends Model +{ + protected $guarded = []; + + protected $casts = [ + 'is_admin' => 'boolean', + ]; +} diff --git a/tests/Database/DatabaseEloquentWithAttributesPendingTest.php b/tests/Database/DatabaseEloquentWithAttributesPendingTest.php new file mode 100644 index 000000000000..a416e7702cdc --- /dev/null +++ b/tests/Database/DatabaseEloquentWithAttributesPendingTest.php @@ -0,0 +1,153 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->bootEloquent(); + $db->setAsGlobal(); + } + + protected function tearDown(): void + { + $this->schema()->dropIfExists((new PendingAttributesModel)->getTable()); + } + + public function testAddsAttributes(): void + { + $key = 'a key'; + $value = 'the value'; + + $query = PendingAttributesModel::query() + ->withAttributes([$key => $value], asConditions: false); + + $model = $query->make(); + + $this->assertSame($value, $model->$key); + } + + public function testDoesNotAddWheres(): void + { + $key = 'a key'; + $value = 'the value'; + + $query = PendingAttributesModel::query() + ->withAttributes([$key => $value], asConditions: false); + + $wheres = $query->toBase()->wheres; + + // Ensure no wheres exist + $this->assertEmpty($wheres); + } + + public function testAddsWithCasts(): void + { + $query = PendingAttributesModel::query() + ->withAttributes([ + 'is_admin' => 1, + 'first_name' => 'FIRST', + 'last_name' => 'LAST', + 'type' => PendingAttributesEnum::internal, + ], asConditions: false); + + $model = $query->make(); + + $this->assertSame(true, $model->is_admin); + $this->assertSame('First', $model->first_name); + $this->assertSame('Last', $model->last_name); + $this->assertSame(PendingAttributesEnum::internal, $model->type); + + $this->assertEqualsCanonicalizing([ + 'is_admin' => 1, + 'first_name' => 'first', + 'last_name' => 'last', + 'type' => 'int', + ], $model->getAttributes()); + } + + public function testAddsWithCastsViaDb(): void + { + $this->bootTable(); + + $query = PendingAttributesModel::query() + ->withAttributes([ + 'is_admin' => 1, + 'first_name' => 'FIRST', + 'last_name' => 'LAST', + 'type' => PendingAttributesEnum::internal, + ], asConditions: false); + + $query->create(); + + $model = PendingAttributesModel::first(); + + $this->assertSame(true, $model->is_admin); + $this->assertSame('First', $model->first_name); + $this->assertSame('Last', $model->last_name); + $this->assertSame(PendingAttributesEnum::internal, $model->type); + } + + protected function bootTable(): void + { + $this->schema()->create((new PendingAttributesModel)->getTable(), function ($table) { + $table->id(); + $table->boolean('is_admin'); + $table->string('first_name'); + $table->string('last_name'); + $table->string('type'); + $table->timestamps(); + }); + } + + protected function schema(): Builder + { + return PendingAttributesModel::getConnectionResolver()->connection()->getSchemaBuilder(); + } +} + +class PendingAttributesModel extends Model +{ + protected $guarded = []; + + protected $casts = [ + 'is_admin' => 'boolean', + 'type' => PendingAttributesEnum::class, + ]; + + public function setFirstNameAttribute(string $value): void + { + $this->attributes['first_name'] = strtolower($value); + } + + public function getFirstNameAttribute(?string $value): string + { + return ucfirst($value); + } + + protected function lastName(): Attribute + { + return Attribute::make( + get: fn (string $value) => ucfirst($value), + set: fn (string $value) => strtolower($value), + ); + } +} + +enum PendingAttributesEnum: string +{ + case internal = 'int'; +} From 9e39df5f865f40f6c582dc2345bb93a20c503f95 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Sat, 29 Mar 2025 17:27:28 +0000 Subject: [PATCH 264/455] Update version to v12.4.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 8758596dc519..c6cd03743511 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.3.0'; + const VERSION = '12.4.0'; /** * The base path for the Laravel installation. From 450f8803ce022b3b73c7b97f45e2cea82e10e0bf Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Sat, 29 Mar 2025 17:29:05 +0000 Subject: [PATCH 265/455] Update CHANGELOG --- CHANGELOG.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd6c6b13a39..7b3c166277b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,51 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.3.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.4.0...12.x) + +## [v12.4.0](https://github.com/laravel/framework/compare/v12.3.0...v12.4.0) - 2025-03-29 + +* [12.x] Reset PHP’s peak memory usage when resetting scope for queue worker by [@TimWolla](https://github.com/TimWolla) in https://github.com/laravel/framework/pull/55069 +* [12.x] Add `AsHtmlString` cast by [@ralphjsmit](https://github.com/ralphjsmit) in https://github.com/laravel/framework/pull/55071 +* [12.x] Add `Arr::sole()` method by [@ralphjsmit](https://github.com/ralphjsmit) in https://github.com/laravel/framework/pull/55070 +* Improve warning message in `ApiInstallCommand` by [@sajjadhossainshohag](https://github.com/sajjadhossainshohag) in https://github.com/laravel/framework/pull/55081 +* [12.x] use already determined `related` property by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55075 +* [12.x] use "class-string" where appropriate in relations by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55074 +* [12.x] `QueueFake::listenersPushed()` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55063 +* [12.x] Added except() method to Model class for excluding attributes by [@vishal2931](https://github.com/vishal2931) in https://github.com/laravel/framework/pull/55072 +* [12.x] fix: add TPivotModel default and define pivot property in {Belongs,Morph}ToMany by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/55086 +* [12.x] remove `@return` docblocks on constructors by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/55076 +* [12.x] Add NamedScope attribute by [@shaedrich](https://github.com/shaedrich) in https://github.com/laravel/framework/pull/54450 +* [12.x] Improve syntax highlighting for stub type files by [@kayw-geek](https://github.com/kayw-geek) in https://github.com/laravel/framework/pull/55094 +* [12.x] Prefer `new Collection` over `Collection::make` by [@AhmedAlaa4611](https://github.com/AhmedAlaa4611) in https://github.com/laravel/framework/pull/55091 +* [12.x] Fix except() method to support casted values by [@vishal2931](https://github.com/vishal2931) in https://github.com/laravel/framework/pull/55124 +* [12.x] Add testcase for findSole method by [@mrvipchien](https://github.com/mrvipchien) in https://github.com/laravel/framework/pull/55115 +* [12.x] Types: PasswordBroker::reset by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/55109 +* [12.x] assertThrowsNothing by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/55100 +* [12.x] Fix type nullability on PasswordBroker.events property by [@jnoordsij](https://github.com/jnoordsij) in https://github.com/laravel/framework/pull/55097 +* [12.x] Fix return type annotation in decrementPendingJobs method by [@shane-zeng](https://github.com/shane-zeng) in https://github.com/laravel/framework/pull/55133 +* [12.x] Fix return type annotation in compile method by [@shane-zeng](https://github.com/shane-zeng) in https://github.com/laravel/framework/pull/55132 +* [12.x] feat: Add `whereNull` and `whereNotNull` to `Assertablejson` by [@faissaloux](https://github.com/faissaloux) in https://github.com/laravel/framework/pull/55131 +* [12.x] fix: use contextual bindings in class dependency resolution by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/55090 +* Better return types for `Illuminate\Queue\Jobs\Job::getJobId()` and `Illuminate\Queue\Jobs\DatabaseJob::getJobId()` methods by [@petrknap](https://github.com/petrknap) in https://github.com/laravel/framework/pull/55138 +* Remove remaining [@return](https://github.com/return) tags from constructors by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55136 +* [12.x] Various URL generation bugfixes by [@stancl](https://github.com/stancl) in https://github.com/laravel/framework/pull/54811 +* Add an optional `shouldRun` method to migrations. by [@danmatthews](https://github.com/danmatthews) in https://github.com/laravel/framework/pull/55011 +* [12.x] `Uri` prevent empty query string by [@rojtjo](https://github.com/rojtjo) in https://github.com/laravel/framework/pull/55146 +* [12.x] Only call the ob_flush function if there is active buffer in eventStream by [@tonysm](https://github.com/tonysm) in https://github.com/laravel/framework/pull/55141 +* [12.x] Add CacheFlushed Event by [@tech-wolf-tw](https://github.com/tech-wolf-tw) in https://github.com/laravel/framework/pull/55142 +* [12.x] Update DateFactory method annotations for Carbon v3 compatibility by [@kayw-geek](https://github.com/kayw-geek) in https://github.com/laravel/framework/pull/55151 +* [12.x] Improve docblocks for file related methods of InteractsWithInput by [@SanderMuller](https://github.com/SanderMuller) in https://github.com/laravel/framework/pull/55156 +* [12.x] Enhance `FileViewFinder` doc-blocks by [@imanghafoori1](https://github.com/imanghafoori1) in https://github.com/laravel/framework/pull/55183 +* Support using null-safe operator with `null` value by [@willrowe](https://github.com/willrowe) in https://github.com/laravel/framework/pull/55175 +* [12.x] Fix: Make Paginated Queries Consistent Across Pages by [@tomchkk](https://github.com/tomchkk) in https://github.com/laravel/framework/pull/55176 +* [12.x] Add `pipe` method query builders by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/55171 +* [12.x] fix: one of many subquery constraints by [@calebdw](https://github.com/calebdw) in https://github.com/laravel/framework/pull/55168 +* [12.x] fix(postgres): missing parentheses in whereDate/whereTime for json columns by [@saibotk](https://github.com/saibotk) in https://github.com/laravel/framework/pull/55159 +* Fix factory creation through attributes by [@davidstoker](https://github.com/davidstoker) in https://github.com/laravel/framework/pull/55190 +* [12.x] Fix Concurrency::run to preserve callback result order by [@chaker2710](https://github.com/chaker2710) in https://github.com/laravel/framework/pull/55161 +* [12.x] Log: Add optional keys parameter to `Log::withoutContext` to remove selected context from future logs by [@mattroylloyd](https://github.com/mattroylloyd) in https://github.com/laravel/framework/pull/55181 +* [12.x] Add `Expression` type to param `$value` of `QueryBuilder` `having()` method by [@faissaloux](https://github.com/faissaloux) in https://github.com/laravel/framework/pull/55200 +* [12.x] Add flag to disable where clauses for `withAttributes` method on Eloquent Builder by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/55199 ## [v12.3.0](https://github.com/laravel/framework/compare/v12.2.0...v12.3.0) - 2025-03-18 From f2f55a2d657057c3e833d0cbe419e77fed812906 Mon Sep 17 00:00:00 2001 From: Faissal Wahabali Date: Sat, 29 Mar 2025 17:44:28 +0000 Subject: [PATCH 266/455] add Expression type to QueryBuilder orHaving() (#55202) --- src/Illuminate/Database/Query/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index cb509f8ffebd..c1fa22a9d7f8 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2451,7 +2451,7 @@ public function having($column, $operator = null, $value = null, $boolean = 'and * * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column * @param \DateTimeInterface|string|int|float|null $operator - * @param \DateTimeInterface|string|int|float|null $value + * @param \Illuminate\Contracts\Database\Query\Expression|\DateTimeInterface|string|int|float|null $value * @return $this */ public function orHaving($column, $operator = null, $value = null) From 27301406c7457e65476c04a61ef321aae5a81a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Sun, 30 Mar 2025 18:24:13 +0200 Subject: [PATCH 267/455] [12.x] Fix URL generation with optional parameters (regression in #54811) (#55213) * Fix URL generation with optional parameters (regression in #54811) This reworks the logic from conditionally reversing passed parameters to instead computing an offset and filling parameters left-to-right from there. * Apply StyleCI diff * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Routing/Route.php | 4 +- src/Illuminate/Routing/RouteUrlGenerator.php | 73 +++++++-- tests/Routing/RoutingUrlGeneratorTest.php | 161 +++++++++++++++++++ 3 files changed, 220 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 22008aa091de..7dd19b552ddc 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -1321,9 +1321,9 @@ public function toSymfonyRoute() /** * Get the optional parameter names for the route. * - * @return array + * @return array */ - protected function getOptionalParameterNames() + public function getOptionalParameterNames() { preg_match_all('/\{(\w+?)\?\}/', $this->uri(), $matches); diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index c82324363418..cd23162c015f 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -183,13 +183,12 @@ protected function formatParameters(Route $route, $parameters) { $parameters = Arr::wrap($parameters); - $passedParameterCount = count($parameters); - $namedParameters = []; $namedQueryParameters = []; - $routeParametersWithoutDefaultsOrNamedParameters = []; + $requiredRouteParametersWithoutDefaultsOrNamedParameters = []; $routeParameters = $route->parameterNames(); + $optionalParameters = $route->getOptionalParameterNames(); foreach ($routeParameters as $name) { if (isset($parameters[$name])) { @@ -198,9 +197,9 @@ protected function formatParameters(Route $route, $parameters) unset($parameters[$name]); continue; - } elseif (! isset($this->defaultParameters[$name])) { - // No named parameter or default value, try to match to positional parameter below... - array_push($routeParametersWithoutDefaultsOrNamedParameters, $name); + } elseif (! isset($this->defaultParameters[$name]) && ! isset($optionalParameters[$name])) { + // No named parameter or default value for a required parameter, try to match to positional parameter below... + array_push($requiredRouteParametersWithoutDefaultsOrNamedParameters, $name); } $namedParameters[$name] = ''; @@ -216,8 +215,8 @@ protected function formatParameters(Route $route, $parameters) } // Match positional parameters to the route parameters that didn't have a value in order... - if (count($parameters) == count($routeParametersWithoutDefaultsOrNamedParameters)) { - foreach (array_reverse($routeParametersWithoutDefaultsOrNamedParameters) as $name) { + if (count($parameters) == count($requiredRouteParametersWithoutDefaultsOrNamedParameters)) { + foreach (array_reverse($requiredRouteParametersWithoutDefaultsOrNamedParameters) as $name) { if (count($parameters) === 0) { break; } @@ -226,19 +225,61 @@ protected function formatParameters(Route $route, $parameters) } } - // If there are extra parameters, just fill left to right... if not, fill right to left and try to use defaults... - $extraParameters = $passedParameterCount > count($routeParameters); + $offset = 0; + $emptyParameters = array_filter($namedParameters, static fn ($val) => $val === ''); - foreach ($extraParameters ? $namedParameters : array_reverse($namedParameters) as $key => $value) { - $bindingField = $route->bindingFieldFor($key); + if (count($requiredRouteParametersWithoutDefaultsOrNamedParameters) !== 0 && + count($parameters) !== count($emptyParameters)) { + // Find the index of the first required parameter... + $offset = array_search($requiredRouteParametersWithoutDefaultsOrNamedParameters[0], array_keys($namedParameters)); - $defaultParameterKey = $bindingField ? "$key:$bindingField" : $key; + // If more empty parameters remain, adjust the offset... + $remaining = count($emptyParameters) - $offset - count($parameters); + + if ($remaining < 0) { + // Effectively subtract the remaining count since it's negative... + $offset += $remaining; + } - if ($value !== '') { + // Correct offset if it goes below zero... + if ($offset < 0) { + $offset = 0; + } + } elseif (count($requiredRouteParametersWithoutDefaultsOrNamedParameters) === 0 && count($parameters) !== 0) { + // Handle the case where all passed parameters are for parameters that have default values... + $remainingCount = count($parameters); + + // Loop over empty parameters backwards and stop when we run out of passed parameters... + for ($i = count($namedParameters) - 1; $i >= 0; $i--) { + if ($namedParameters[array_keys($namedParameters)[$i]] === '') { + $offset = $i; + $remainingCount--; + + if ($remainingCount === 0) { + // If there are no more passed parameters, we stop here... + break; + } + } + } + } + + // Starting from the offset, match any passed parameters from left to right... + for ($i = $offset; $i < count($namedParameters); $i++) { + $key = array_keys($namedParameters)[$i]; + + if ($namedParameters[$key] !== '') { continue; } elseif (! empty($parameters)) { - $namedParameters[$key] = $extraParameters ? array_shift($parameters) : array_pop($parameters); - } elseif (isset($this->defaultParameters[$defaultParameterKey])) { + $namedParameters[$key] = array_shift($parameters); + } + } + + // Fill leftmost parameters with defaults if the loop above was offset... + foreach ($namedParameters as $key => $value) { + $bindingField = $route->bindingFieldFor($key); + $defaultParameterKey = $bindingField ? "$key:$bindingField" : $key; + + if ($value === '' && isset($this->defaultParameters[$defaultParameterKey])) { $namedParameters[$key] = $this->defaultParameters[$defaultParameterKey]; } } diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index 28bb67a49423..f03e4b10bb8c 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -1821,6 +1821,167 @@ public function testDefaultsCanBeCombinedWithExtraQueryParameters() $url->route('tenantPostUser', ['concretePost', 'extra' => 'query']), ); } + + public function testUrlGenerationWithOptionalParameters(): void + { + $url = new UrlGenerator( + $routes = new RouteCollection, + Request::create('https://www.foo.com/') + ); + + $url->defaults([ + 'tenant' => 'defaultTenant', + 'user' => 'defaultUser', + ]); + + /** + * Route with one required parameter and one optional parameter. + */ + $route = new Route(['GET'], 'postOptionalMethod/{post}/{method?}', ['as' => 'postOptionalMethod', fn () => '']); + $routes->add($route); + + $this->assertSame( + 'https://www.foo.com/postOptionalMethod/1', + $url->route('postOptionalMethod', 1), + ); + + $this->assertSame( + 'https://www.foo.com/postOptionalMethod/1/2', + $url->route('postOptionalMethod', [1, 2]), + ); + + /** + * Route with two optional parameters. + */ + $route = new Route(['GET'], 'optionalPostOptionalMethod/{post}/{method?}', ['as' => 'optionalPostOptionalMethod', fn () => '']); + $routes->add($route); + + $this->assertSame( + 'https://www.foo.com/optionalPostOptionalMethod/1', + $url->route('optionalPostOptionalMethod', 1), + ); + + $this->assertSame( + 'https://www.foo.com/optionalPostOptionalMethod/1/2', + $url->route('optionalPostOptionalMethod', [1, 2]), + ); + + /** + * Route with one default parameter, one required parameter, and one optional parameter. + */ + $route = new Route(['GET'], 'tenantPostOptionalMethod/{tenant}/{post}/{method?}', ['as' => 'tenantPostOptionalMethod', fn () => '']); + $routes->add($route); + + // Passing one parameter + $this->assertSame( + 'https://www.foo.com/tenantPostOptionalMethod/defaultTenant/concretePost', + $url->route('tenantPostOptionalMethod', ['concretePost']), + ); + + // Passing two parameters: optional parameter is prioritized over parameter with a default value + $this->assertSame( + 'https://www.foo.com/tenantPostOptionalMethod/defaultTenant/concretePost/concreteMethod', + $url->route('tenantPostOptionalMethod', ['concretePost', 'concreteMethod']), + ); + + // Passing all three parameters + $this->assertSame( + 'https://www.foo.com/tenantPostOptionalMethod/concreteTenant/concretePost/concreteMethod', + $url->route('tenantPostOptionalMethod', ['concreteTenant', 'concretePost', 'concreteMethod']), + ); + + /** + * Route with two default parameters, one required parameter, and one optional parameter. + */ + $route = new Route(['GET'], 'tenantUserPostOptionalMethod/{tenant}/{user}/{post}/{method?}', ['as' => 'tenantUserPostOptionalMethod', fn () => '']); + $routes->add($route); + + // Passing one parameter + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/defaultTenant/defaultUser/concretePost', + $url->route('tenantUserPostOptionalMethod', ['concretePost']), + ); + + // Passing two parameters: optional parameter is prioritized over parameters with default values + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/defaultTenant/defaultUser/concretePost/concreteMethod', + $url->route('tenantUserPostOptionalMethod', ['concretePost', 'concreteMethod']), + ); + + // Passing three parameters: only the leftmost parameter with a default value uses its default value + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/defaultTenant/concreteUser/concretePost/concreteMethod', + $url->route('tenantUserPostOptionalMethod', ['concreteUser', 'concretePost', 'concreteMethod']), + ); + + // Same as the assertion above, but using some named parameters + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/defaultTenant/concreteUser/concretePost/concreteMethod', + $url->route('tenantUserPostOptionalMethod', ['user' => 'concreteUser', 'concretePost', 'concreteMethod']), + ); + + // Also using a named parameter, but this time for the post parameter + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/defaultTenant/concreteUser/concretePost/concreteMethod', + $url->route('tenantUserPostOptionalMethod', ['concreteUser', 'post' => 'concretePost', 'concreteMethod']), + ); + + // Also using a named parameter, but this time for the optional method parameter + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/defaultTenant/concreteUser/concretePost/concreteMethod', + $url->route('tenantUserPostOptionalMethod', ['concreteUser', 'concretePost', 'method' => 'concreteMethod']), + ); + + // Passing all four parameters + $this->assertSame( + 'https://www.foo.com/tenantUserPostOptionalMethod/concreteTenant/concreteUser/concretePost/concreteMethod', + $url->route('tenantUserPostOptionalMethod', ['concreteTenant', 'concreteUser', 'concretePost', 'concreteMethod']), + ); + + /** + * Route with a default parameter, a required parameter, another default parameter, and finally an optional parameter. + * + * This tests interleaved default parameters when combined with optional parameters. + */ + $route = new Route(['GET'], 'tenantPostUserOptionalMethod/{tenant}/{post}/{user}/{method?}', ['as' => 'tenantPostUserOptionalMethod', fn () => '']); + $routes->add($route); + + // Passing one parameter + $this->assertSame( + 'https://www.foo.com/tenantPostUserOptionalMethod/defaultTenant/concretePost/defaultUser', + $url->route('tenantPostUserOptionalMethod', ['concretePost']), + ); + + // Passing two parameters: optional parameter is prioritized over parameters with default values + $this->assertSame( + 'https://www.foo.com/tenantPostUserOptionalMethod/defaultTenant/concretePost/defaultUser/concreteMethod', + $url->route('tenantPostUserOptionalMethod', ['concretePost', 'concreteMethod']), + ); + + // Same as the assertion above, but using some named parameters + $this->assertSame( + 'https://www.foo.com/tenantPostUserOptionalMethod/defaultTenant/concretePost/defaultUser/concreteMethod', + $url->route('tenantPostUserOptionalMethod', ['post' => 'concretePost', 'concreteMethod']), + ); + + // Also using a named parameter, but this time for the optional parameter + $this->assertSame( + 'https://www.foo.com/tenantPostUserOptionalMethod/defaultTenant/concretePost/defaultUser/concreteMethod', + $url->route('tenantPostUserOptionalMethod', ['concretePost', 'method' => 'concreteMethod']), + ); + + // Passing three parameters: only the leftmost parameter with a default value uses its default value + $this->assertSame( + 'https://www.foo.com/tenantPostUserOptionalMethod/defaultTenant/concretePost/concreteUser/concreteMethod', + $url->route('tenantPostUserOptionalMethod', ['concretePost', 'concreteUser', 'concreteMethod']), + ); + + // Passing all four parameters + $this->assertSame( + 'https://www.foo.com/tenantPostUserOptionalMethod/concreteTenant/concretePost/concreteUser/concreteMethod', + $url->route('tenantPostUserOptionalMethod', ['concreteTenant', 'concretePost', 'concreteUser', 'concreteMethod']), + ); + } } class RoutableInterfaceStub implements UrlRoutable From 33c7c9443626bc6c25c02f272ef57775b13c0e6b Mon Sep 17 00:00:00 2001 From: Iman Date: Sun, 30 Mar 2025 19:54:54 +0330 Subject: [PATCH 268/455] fix failing tests on windows OS (#55210) --- tests/View/Blade/BladeExtendsTest.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/View/Blade/BladeExtendsTest.php b/tests/View/Blade/BladeExtendsTest.php index a4dcf8c64e38..d09d996c6950 100644 --- a/tests/View/Blade/BladeExtendsTest.php +++ b/tests/View/Blade/BladeExtendsTest.php @@ -6,8 +6,7 @@ class BladeExtendsTest extends AbstractBladeTestCase { public function testExtendsAreCompiled() { - $string = '@extends(\'foo\') -test'; + $string = "@extends('foo')\ntest"; $expected = "test\n".'make(\'foo\', array_diff_key(get_defined_vars(), [\'__data\' => 1, \'__path\' => 1]))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); @@ -18,8 +17,7 @@ public function testExtendsAreCompiled() public function testSequentialCompileStringCalls() { - $string = '@extends(\'foo\') -test'; + $string = "@extends('foo')\ntest"; $expected = "test\n".'make(\'foo\', array_diff_key(get_defined_vars(), [\'__data\' => 1, \'__path\' => 1]))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); @@ -31,8 +29,7 @@ public function testSequentialCompileStringCalls() public function testExtendsFirstAreCompiled() { - $string = '@extendsFirst([\'foo\', \'milwad\']) -test'; + $string = "@extendsFirst(['foo', 'milwad'])\ntest"; $expected = "test\n".'first([\'foo\', \'milwad\'], array_diff_key(get_defined_vars(), [\'__data\' => 1, \'__path\' => 1]))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); From cdefd852ecb459a65392cd6ccb578c92a15b8e2b Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Sun, 30 Mar 2025 16:27:26 +0000 Subject: [PATCH 269/455] Update version to v12.4.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index c6cd03743511..139fdfb74618 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.4.0'; + const VERSION = '12.4.1'; /** * The base path for the Laravel installation. From 1409a7b287294ca5f76a164118a7da98a0570f05 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Sun, 30 Mar 2025 16:29:03 +0000 Subject: [PATCH 270/455] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3c166277b9..2ec0619bc693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.4.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.4.1...12.x) + +## [v12.4.1](https://github.com/laravel/framework/compare/v12.4.0...v12.4.1) - 2025-03-30 + +* [12.x] Add `Expression` type to param `$value` of `QueryBuilder` `orHaving()` method by [@faissaloux](https://github.com/faissaloux) in https://github.com/laravel/framework/pull/55202 +* [12.x] Fix URL generation with optional parameters (regression in #54811) by [@stancl](https://github.com/stancl) in https://github.com/laravel/framework/pull/55213 +* [12.x] Fix failing tests on windows OS by [@imanghafoori1](https://github.com/imanghafoori1) in https://github.com/laravel/framework/pull/55210 ## [v12.4.0](https://github.com/laravel/framework/compare/v12.3.0...v12.4.0) - 2025-03-29 From 8dfc3d4cd2a6a5ed1d0d33d5e02425f8e023f42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Mon, 31 Mar 2025 16:05:51 +0200 Subject: [PATCH 271/455] Correct misspellings (#55218) * Correct misspellings * Add BC method --- .../Database/Query/Grammars/PostgresGrammar.php | 10 +++++++++- ...seEloquentHasOneOrManyWithAttributesPendingTest.php | 2 +- .../DatabaseEloquentHasOneOrManyWithAttributesTest.php | 2 +- tests/Database/DatabasePostgresQueryGrammarTest.php | 4 ++-- .../DatabaseEloquentModelAttributeCastingTest.php | 2 +- ...uteTest.php => EloquentNamedScopeAttributeTest.php} | 2 +- tests/Validation/ValidationImageFileRuleTest.php | 8 ++++---- 7 files changed, 19 insertions(+), 11 deletions(-) rename tests/Integration/Database/{EloquentNamedScopeAttibuteTest.php => EloquentNamedScopeAttributeTest.php} (94%) diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index 14bac8da75e9..c43a253cd1e2 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -831,8 +831,16 @@ public static function customOperators(array $operators) * @param bool $value * @return void */ - public static function cascadeOnTrucate(bool $value = true) + public static function cascadeOnTruncate(bool $value = true) { static::$cascadeTruncate = $value; } + + /** + * @deprecated use cascadeOnTruncate + */ + public static function cascadeOnTrucate(bool $value = true) + { + self::cascadeOnTruncate($value); + } } diff --git a/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php index dac4e83de226..77fc715a4274 100644 --- a/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php +++ b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php @@ -98,7 +98,7 @@ public function testMorphOneAddsAttributes(): void $this->assertSame($value, $relatedModel->$key); } - public function testPendingAttributesCanBeOverriden(): void + public function testPendingAttributesCanBeOverridden(): void { $key = 'a key'; $defaultValue = 'a value'; diff --git a/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php index ed686e594121..93ff90f29fc5 100755 --- a/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php +++ b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php @@ -98,7 +98,7 @@ public function testMorphOneAddsAttributes(): void $this->assertSame($value, $relatedModel->$key); } - public function testWithAttributesCanBeOverriden(): void + public function testWithAttributesCanBeOverridden(): void { $key = 'a key'; $defaultValue = 'a value'; diff --git a/tests/Database/DatabasePostgresQueryGrammarTest.php b/tests/Database/DatabasePostgresQueryGrammarTest.php index 718ee9d9cd12..46b39e991f72 100755 --- a/tests/Database/DatabasePostgresQueryGrammarTest.php +++ b/tests/Database/DatabasePostgresQueryGrammarTest.php @@ -60,13 +60,13 @@ public function testCompileTruncate() 'truncate "users" restart identity cascade' => [], ], $postgres->compileTruncate($builder)); - PostgresGrammar::cascadeOnTrucate(false); + PostgresGrammar::cascadeOnTruncate(false); $this->assertEquals([ 'truncate "users" restart identity' => [], ], $postgres->compileTruncate($builder)); - PostgresGrammar::cascadeOnTrucate(); + PostgresGrammar::cascadeOnTruncate(); $this->assertEquals([ 'truncate "users" restart identity cascade' => [], diff --git a/tests/Integration/Database/DatabaseEloquentModelAttributeCastingTest.php b/tests/Integration/Database/DatabaseEloquentModelAttributeCastingTest.php index 060031684a0b..48c79acad305 100644 --- a/tests/Integration/Database/DatabaseEloquentModelAttributeCastingTest.php +++ b/tests/Integration/Database/DatabaseEloquentModelAttributeCastingTest.php @@ -184,7 +184,7 @@ public function testSettingRawAttributesClearsTheCastCache() $this->assertSame('117 Spencer St.', $model->address->lineOne); } - public function testCastsThatOnlyHaveGetterDoNotPeristAnythingToModelOnSave() + public function testCastsThatOnlyHaveGetterDoNotPersistAnythingToModelOnSave() { $model = new TestEloquentModelWithAttributeCast; diff --git a/tests/Integration/Database/EloquentNamedScopeAttibuteTest.php b/tests/Integration/Database/EloquentNamedScopeAttributeTest.php similarity index 94% rename from tests/Integration/Database/EloquentNamedScopeAttibuteTest.php rename to tests/Integration/Database/EloquentNamedScopeAttributeTest.php index 4eb58a7930bc..1ad2576ae411 100644 --- a/tests/Integration/Database/EloquentNamedScopeAttibuteTest.php +++ b/tests/Integration/Database/EloquentNamedScopeAttributeTest.php @@ -6,7 +6,7 @@ use Orchestra\Testbench\TestCase; #[WithMigration] -class EloquentNamedScopeAttibuteTest extends TestCase +class EloquentNamedScopeAttributeTest extends TestCase { protected $query = 'select * from "named_scope_users" where "email_verified_at" is not null'; diff --git a/tests/Validation/ValidationImageFileRuleTest.php b/tests/Validation/ValidationImageFileRuleTest.php index 63786a8fc61e..78a743436719 100644 --- a/tests/Validation/ValidationImageFileRuleTest.php +++ b/tests/Validation/ValidationImageFileRuleTest.php @@ -44,7 +44,7 @@ public function testDimensionsWithCustomImageSizeMethod() ); } - public function testDimentionWithTheRatioMethod() + public function testDimensionWithTheRatioMethod() { $this->fails( File::image()->dimensions(Rule::dimensions()->ratio(1)), @@ -58,7 +58,7 @@ public function testDimentionWithTheRatioMethod() ); } - public function testDimentionWithTheMinRatioMethod() + public function testDimensionWithTheMinRatioMethod() { $this->fails( File::image()->dimensions(Rule::dimensions()->minRatio(1 / 2)), @@ -72,7 +72,7 @@ public function testDimentionWithTheMinRatioMethod() ); } - public function testDimentionWithTheMaxRatioMethod() + public function testDimensionWithTheMaxRatioMethod() { $this->fails( File::image()->dimensions(Rule::dimensions()->maxRatio(1 / 2)), @@ -86,7 +86,7 @@ public function testDimentionWithTheMaxRatioMethod() ); } - public function testDimentionWithTheRatioBetweenMethod() + public function testDimensionWithTheRatioBetweenMethod() { $this->fails( File::image()->dimensions(Rule::dimensions()->ratioBetween(1 / 2, 1 / 3)), From d315745942314ba78fc3011650d1f26155f698f0 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Wed, 2 Apr 2025 01:17:25 +1100 Subject: [PATCH 272/455] Add ability to flush state on Vite helper (#55228) --- src/Illuminate/Foundation/Vite.php | 10 ++++++++++ tests/Foundation/FoundationViteTest.php | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Illuminate/Foundation/Vite.php b/src/Illuminate/Foundation/Vite.php index b77ea8ed0e51..7b7de434c27a 100644 --- a/src/Illuminate/Foundation/Vite.php +++ b/src/Illuminate/Foundation/Vite.php @@ -1023,4 +1023,14 @@ public function toHtml() { return $this->__invoke($this->entryPoints)->toHtml(); } + + /** + * Flush state. + * + * @return void + */ + public function flush() + { + $this->preloadedAssets = []; + } } diff --git a/tests/Foundation/FoundationViteTest.php b/tests/Foundation/FoundationViteTest.php index 4a113f107cc9..b54f018d9c83 100644 --- a/tests/Foundation/FoundationViteTest.php +++ b/tests/Foundation/FoundationViteTest.php @@ -1693,6 +1693,18 @@ public function testItCanConfigureThePrefetchTriggerEvent() $this->cleanViteManifest($buildDir); } + public function testItCanFlushState() + { + $this->makeViteManifest(); + + app(Vite::class)('resources/js/app.js'); + app()->forgetScopedInstances(); + $this->assertCount(1, app(Vite::class)->preloadedAssets()); + + app(Vite::class)->flush(); + $this->assertCount(0, app(Vite::class)->preloadedAssets()); + } + protected function cleanViteManifest($path = 'build') { if (file_exists(public_path("{$path}/manifest.json"))) { From 06052588b24b0df8d25d40638964caa8fc9f56b6 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:17:57 +0000 Subject: [PATCH 273/455] Update facade docblocks --- src/Illuminate/Support/Facades/Vite.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php index 7cdde4f5eece..6f727c89c77d 100644 --- a/src/Illuminate/Support/Facades/Vite.php +++ b/src/Illuminate/Support/Facades/Vite.php @@ -27,6 +27,7 @@ * @method static string|null manifestHash(string|null $buildDirectory = null) * @method static bool isRunningHot() * @method static string toHtml() + * @method static void flush() * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) * @method static bool hasMacro(string $name) From ba7aa734217d60d4c25e922f4cfc31ec95ac190a Mon Sep 17 00:00:00 2001 From: erikn69 Date: Tue, 1 Apr 2025 09:27:12 -0500 Subject: [PATCH 274/455] Support taggeable store flushed cache events (#55223) --- src/Illuminate/Cache/TaggedCache.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Illuminate/Cache/TaggedCache.php b/src/Illuminate/Cache/TaggedCache.php index 62adff972249..27889a18baf5 100644 --- a/src/Illuminate/Cache/TaggedCache.php +++ b/src/Illuminate/Cache/TaggedCache.php @@ -2,6 +2,8 @@ namespace Illuminate\Cache; +use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Contracts\Cache\Store; class TaggedCache extends Repository @@ -77,8 +79,12 @@ public function decrement($key, $value = 1) */ public function flush() { + parent::event(new CacheFlushing($this->getName())); + $this->tags->reset(); + parent::event(new CacheFlushed($this->getName())); + return true; } From 136361c7033b73b0fc871d78781515ff2026e10d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 1 Apr 2025 09:27:30 -0500 Subject: [PATCH 275/455] Revert "Support taggeable store flushed cache events (#55223)" (#55232) This reverts commit ba7aa734217d60d4c25e922f4cfc31ec95ac190a. --- src/Illuminate/Cache/TaggedCache.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Illuminate/Cache/TaggedCache.php b/src/Illuminate/Cache/TaggedCache.php index 27889a18baf5..62adff972249 100644 --- a/src/Illuminate/Cache/TaggedCache.php +++ b/src/Illuminate/Cache/TaggedCache.php @@ -2,8 +2,6 @@ namespace Illuminate\Cache; -use Illuminate\Cache\Events\CacheFlushed; -use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Contracts\Cache\Store; class TaggedCache extends Repository @@ -79,12 +77,8 @@ public function decrement($key, $value = 1) */ public function flush() { - parent::event(new CacheFlushing($this->getName())); - $this->tags->reset(); - parent::event(new CacheFlushed($this->getName())); - return true; } From e9f18fc9fe0e866ca46e8855b6b8e0fede375329 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Tue, 1 Apr 2025 16:35:59 +0200 Subject: [PATCH 276/455] [12.x] Allow configuration of retry period for RoundRobin and Failover mail transports (#55222) * Replace RoundRobinTransport integration test with 'regular' test Consistent with FailoverTransport * Use single function for creating Failover and RoundRobin (mail) transports * Allow configuring of retry period on RoundRobin and Failover mail transports * formatting --------- Co-authored-by: Taylor Otwell --- config/mail.php | 2 + src/Illuminate/Mail/MailManager.php | 35 ++++++------- .../Mail/MailRoundRobinTransportTest.php | 27 ---------- tests/Mail/MailRoundRobinTransportTest.php | 51 +++++++++++++++++++ 4 files changed, 69 insertions(+), 46 deletions(-) delete mode 100644 tests/Integration/Mail/MailRoundRobinTransportTest.php create mode 100644 tests/Mail/MailRoundRobinTransportTest.php diff --git a/config/mail.php b/config/mail.php index 7ed4812780e0..ff140eb439f8 100644 --- a/config/mail.php +++ b/config/mail.php @@ -85,6 +85,7 @@ 'smtp', 'log', ], + 'retry_after' => 60, ], 'roundrobin' => [ @@ -93,6 +94,7 @@ 'ses', 'postmark', ], + 'retry_after' => 60, ], ], diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index 2fc790361b80..078630fa0968 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -385,24 +385,7 @@ protected function createPostmarkTransport(array $config) */ protected function createFailoverTransport(array $config) { - $transports = []; - - foreach ($config['mailers'] as $name) { - $config = $this->getConfig($name); - - if (is_null($config)) { - throw new InvalidArgumentException("Mailer [{$name}] is not defined."); - } - - // Now, we will check if the "driver" key exists and if it does we will set - // 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->createSymfonyTransport(array_merge($config, ['transport' => $name])) - : $this->createSymfonyTransport($config); - } - - return new FailoverTransport($transports); + return $this->createRoundrobinTransportOfClass($config, FailoverTransport::class); } /** @@ -412,6 +395,20 @@ protected function createFailoverTransport(array $config) * @return \Symfony\Component\Mailer\Transport\RoundRobinTransport */ protected function createRoundrobinTransport(array $config) + { + return $this->createRoundrobinTransportOfClass($config, RoundRobinTransport::class); + } + + /** + * Create an instance of supplied class extending the Symfony Roundrobin Transport driver. + * + * @template TClass of \Symfony\Component\Mailer\Transport\RoundRobinTransport + * + * @param array $config + * @param class-string $class + * @return TClass + */ + protected function createRoundrobinTransportOfClass(array $config, string $class) { $transports = []; @@ -430,7 +427,7 @@ protected function createRoundrobinTransport(array $config) : $this->createSymfonyTransport($config); } - return new RoundRobinTransport($transports); + return new $class($transports, $config['retry_after'] ?? 60); } /** diff --git a/tests/Integration/Mail/MailRoundRobinTransportTest.php b/tests/Integration/Mail/MailRoundRobinTransportTest.php deleted file mode 100644 index cb1bd3c05222..000000000000 --- a/tests/Integration/Mail/MailRoundRobinTransportTest.php +++ /dev/null @@ -1,27 +0,0 @@ - 'roundrobin', 'mailers' => ['sendmail', 'array']])] - public function testGetRoundRobinTransportWithConfiguredTransports() - { - $transport = app('mailer')->getSymfonyTransport(); - $this->assertInstanceOf(RoundRobinTransport::class, $transport); - } - - #[WithConfig('mail.driver', 'roundrobin')] - #[WithConfig('mail.mailers', ['sendmail', 'array'])] - #[WithConfig('mail.sendmail', '/usr/sbin/sendmail -bs')] - public function testGetRoundRobinTransportWithLaravel6StyleMailConfiguration() - { - $transport = app('mailer')->getSymfonyTransport(); - $this->assertInstanceOf(RoundRobinTransport::class, $transport); - } -} diff --git a/tests/Mail/MailRoundRobinTransportTest.php b/tests/Mail/MailRoundRobinTransportTest.php new file mode 100644 index 000000000000..5b45f720faf0 --- /dev/null +++ b/tests/Mail/MailRoundRobinTransportTest.php @@ -0,0 +1,51 @@ +app['config']->set('mail.default', 'roundrobin'); + + $this->app['config']->set('mail.mailers', [ + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'sendmail', + 'array', + ], + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => '/usr/sbin/sendmail -bs', + ], + + 'array' => [ + 'transport' => 'array', + ], + ]); + + $transport = app('mailer')->getSymfonyTransport(); + $this->assertInstanceOf(RoundRobinTransport::class, $transport); + } + + public function testGetRoundRobinTransportWithLaravel6StyleMailConfiguration() + { + $this->app['config']->set('mail.driver', 'roundrobin'); + + $this->app['config']->set('mail.mailers', [ + 'sendmail', + 'array', + ]); + + $this->app['config']->set('mail.sendmail', '/usr/sbin/sendmail -bs'); + + $transport = app('mailer')->getSymfonyTransport(); + $this->assertInstanceOf(RoundRobinTransport::class, $transport); + } +} From 191cd91192d0f729e46a20e08f590ee6763c971c Mon Sep 17 00:00:00 2001 From: Jakob Crowder Date: Tue, 1 Apr 2025 10:38:52 -0400 Subject: [PATCH 277/455] [12.x] Add --json option to EventListCommand (#55207) * Add --json option to EventListCommand with tests * formatting --------- Co-authored-by: Taylor Otwell --- .../Foundation/Console/EventListCommand.php | 43 +++++++++++++++- .../Console/Events/EventListCommandTest.php | 49 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index d9e5c8f89b24..b6dfd9f63065 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -18,7 +18,9 @@ class EventListCommand extends Command * * @var string */ - protected $signature = 'event:list {--event= : Filter the events by name}'; + protected $signature = 'event:list + {--event= : Filter the events by name} + {--json : Output the events and listeners as JSON}'; /** * The console command description. @@ -44,11 +46,48 @@ public function handle() $events = $this->getEvents()->sortKeys(); if ($events->isEmpty()) { - $this->components->info("Your application doesn't have any events matching the given criteria."); + if ($this->option('json')) { + $this->output->writeln('[]'); + } else { + $this->components->info("Your application doesn't have any events matching the given criteria."); + } return; } + if ($this->option('json')) { + $this->displayJson($events); + } else { + $this->displayForCli($events); + } + } + + /** + * Display events and their listeners in JSON. + * + * @param \Illuminate\Support\Collection $events + * @return void + */ + protected function displayJson(Collection $events) + { + $data = $events->map(function ($listeners, $event) { + return [ + 'event' => strip_tags($this->appendEventInterfaces($event)), + 'listeners' => collect($listeners)->map(fn ($listener) => strip_tags($listener))->values()->all(), + ]; + })->values(); + + $this->output->writeln($data->toJson()); + } + + /** + * Display the events and their listeners for the CLI. + * + * @param \Illuminate\Support\Collection $events + * @return void + */ + protected function displayForCli(Collection $events) + { $this->newLine(); $events->each(function ($listeners, $event) { diff --git a/tests/Integration/Console/Events/EventListCommandTest.php b/tests/Integration/Console/Events/EventListCommandTest.php index 200f8df3c80b..9409d77e3075 100644 --- a/tests/Integration/Console/Events/EventListCommandTest.php +++ b/tests/Integration/Console/Events/EventListCommandTest.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Events\Dispatcher; use Illuminate\Foundation\Console\EventListCommand; +use Illuminate\Support\Facades\Artisan; use Orchestra\Testbench\TestCase; class EventListCommandTest extends TestCase @@ -58,6 +59,54 @@ public function testDisplayFilteredEvent() ->expectsOutputToContain('ExampleEvent'); } + public function testDisplayEmptyListAsJson() + { + $this->withoutMockingConsoleOutput()->artisan(EventListCommand::class, ['--json' => true]); + $output = Artisan::output(); + + $this->assertJson($output); + $this->assertJsonStringEqualsJsonString('[]', $output); + } + + public function testDisplayEventsAsJson() + { + $this->dispatcher->subscribe(ExampleSubscriber::class); + $this->dispatcher->listen(ExampleEvent::class, ExampleListener::class); + $this->dispatcher->listen(ExampleEvent::class, ExampleQueueListener::class); + $this->dispatcher->listen(ExampleBroadcastEvent::class, ExampleBroadcastListener::class); + $this->dispatcher->listen(ExampleEvent::class, fn () => ''); + $closureLineNumber = __LINE__ - 1; + $unixFilePath = str_replace('\\', '/', __FILE__); + + $this->withoutMockingConsoleOutput()->artisan(EventListCommand::class, ['--json' => true]); + $output = Artisan::output(); + + $this->assertJson($output); + $this->assertStringContainsString('ExampleSubscriberEventName', $output); + $this->assertStringContainsString(json_encode('Illuminate\Tests\Integration\Console\Events\ExampleSubscriber@a'), $output); + $this->assertStringContainsString(json_encode('Illuminate\Tests\Integration\Console\Events\ExampleBroadcastEvent (ShouldBroadcast)'), $output); + $this->assertStringContainsString(json_encode('Illuminate\Tests\Integration\Console\Events\ExampleBroadcastListener'), $output); + $this->assertStringContainsString(json_encode('Illuminate\Tests\Integration\Console\Events\ExampleEvent'), $output); + $this->assertStringContainsString(json_encode('Closure at: '.$unixFilePath.':'.$closureLineNumber), $output); + } + + public function testDisplayFilteredEventAsJson() + { + $this->dispatcher->subscribe(ExampleSubscriber::class); + $this->dispatcher->listen(ExampleEvent::class, ExampleListener::class); + + $this->withoutMockingConsoleOutput()->artisan(EventListCommand::class, [ + '--event' => 'ExampleEvent', + '--json' => true, + ]); + $output = Artisan::output(); + + $this->assertJson($output); + $this->assertStringContainsString('ExampleEvent', $output); + $this->assertStringContainsString('ExampleListener', $output); + $this->assertStringNotContainsString('ExampleSubscriberEventName', $output); + } + protected function tearDown(): void { parent::tearDown(); From 0ab4791b2c5f405f8728e4481265599803564c02 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:40:42 +0000 Subject: [PATCH 278/455] Update version to v12.5.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 139fdfb74618..9861c5fe58eb 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.4.1'; + const VERSION = '12.5.0'; /** * The base path for the Laravel installation. From 11948174215013f405cc923e7f761b9649d90b72 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:42:36 +0000 Subject: [PATCH 279/455] Update CHANGELOG --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ec0619bc693..74e56a7c8327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.4.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.5.0...12.x) + +## [v12.5.0](https://github.com/laravel/framework/compare/v12.4.1...v12.5.0) - 2025-04-01 + +* Correct misspellings by [@szepeviktor](https://github.com/szepeviktor) in https://github.com/laravel/framework/pull/55218 +* [12.x] Add ability to flush state on Vite helper by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/55228 +* [12.x] Support taggeable store flushed cache events by [@erikn69](https://github.com/erikn69) in https://github.com/laravel/framework/pull/55223 +* Revert "[12.x] Support taggeable store flushed cache events" by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/framework/pull/55232 +* [12.x] Allow configuration of retry period for RoundRobin and Failover mail transports by [@jnoordsij](https://github.com/jnoordsij) in https://github.com/laravel/framework/pull/55222 +* [12.x] Add --json option to EventListCommand by [@hotsaucejake](https://github.com/hotsaucejake) in https://github.com/laravel/framework/pull/55207 ## [v12.4.1](https://github.com/laravel/framework/compare/v12.4.0...v12.4.1) - 2025-03-30 From c420ccb2231488ef2af2df3acf09f9dbba89bc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Tue, 1 Apr 2025 17:51:59 +0200 Subject: [PATCH 280/455] Dont stop pruning if pruning one model fails (#55237) --- src/Illuminate/Database/Eloquent/Prunable.php | 18 +++++++- .../Database/EloquentPrunableTest.php | 41 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Prunable.php b/src/Illuminate/Database/Eloquent/Prunable.php index f36e1dc5c8f9..b1314af362e5 100644 --- a/src/Illuminate/Database/Eloquent/Prunable.php +++ b/src/Illuminate/Database/Eloquent/Prunable.php @@ -2,8 +2,10 @@ namespace Illuminate\Database\Eloquent; +use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Database\Events\ModelsPruned; use LogicException; +use Throwable; trait Prunable { @@ -21,9 +23,21 @@ public function pruneAll(int $chunkSize = 1000) ->when(in_array(SoftDeletes::class, class_uses_recursive(static::class)), function ($query) { $query->withTrashed(); })->chunkById($chunkSize, function ($models) use (&$total) { - $models->each->prune(); + $models->each(function ($model) use (&$total) { + try { + $model->prune(); - $total += $models->count(); + $total++; + } catch (Throwable $e) { + $handler = app(ExceptionHandler::class); + + if ($handler) { + $handler->report($e); + } else { + throw $e; + } + } + }); event(new ModelsPruned(static::class, $total)); }); diff --git a/tests/Integration/Database/EloquentPrunableTest.php b/tests/Integration/Database/EloquentPrunableTest.php index 22f48e9464fc..495b3f53dfdb 100644 --- a/tests/Integration/Database/EloquentPrunableTest.php +++ b/tests/Integration/Database/EloquentPrunableTest.php @@ -2,12 +2,14 @@ namespace Illuminate\Tests\Integration\Database; +use Exception; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Events\ModelsPruned; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Exceptions; use Illuminate\Support\Facades\Schema; use LogicException; @@ -20,6 +22,7 @@ protected function afterRefreshingDatabase() 'prunable_soft_delete_test_models', 'prunable_test_model_missing_prunable_methods', 'prunable_with_custom_prune_method_test_models', + 'prunable_with_exceptions', ])->each(function ($table) { Schema::create($table, function (Blueprint $table) { $table->increments('id'); @@ -97,6 +100,27 @@ public function testPruneWithCustomPruneMethod() Event::assertDispatched(ModelsPruned::class, 1); } + + public function testPruneWithExceptionAtOneOfModels() + { + Event::fake(); + Exceptions::fake(); + + collect(range(1, 5000))->map(function ($id) { + return ['name' => 'foo']; + })->chunk(200)->each(function ($chunk) { + PrunableWithException::insert($chunk->all()); + }); + + $count = (new PrunableWithException)->pruneAll(); + + $this->assertEquals(999, $count); + + Event::assertDispatched(ModelsPruned::class, 1); + Event::assertDispatched(fn (ModelsPruned $event) => $event->count === 999); + Exceptions::assertReportedCount(1); + Exceptions::assertReported(fn (Exception $exception) => $exception->getMessage() === 'foo bar'); + } } class PrunableTestModel extends Model @@ -136,6 +160,23 @@ public function prune() } } +class PrunableWithException extends Model +{ + use Prunable; + + public function prunable() + { + return $this->where('id', '<=', 1000); + } + + public function prune() + { + if ($this->id === 500) { + throw new Exception('foo bar'); + } + } +} + class PrunableTestModelMissingPrunableMethod extends Model { use Prunable; From 3301640003cd9f49943b3f0cd8bcc7b3d0d1b801 Mon Sep 17 00:00:00 2001 From: Felipe Dalcin Date: Tue, 1 Apr 2025 11:53:02 -0400 Subject: [PATCH 281/455] Update Date Facade docblocks (#55235) --- src/Illuminate/Support/Facades/Date.php | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index fb55ef29656f..09aea90c8152 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -21,9 +21,9 @@ * @method static \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) * @method static \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) * @method static \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) @@ -55,7 +55,7 @@ * @method static bool hasMacro($name) * @method static bool hasRelativeKeywords(?string $time) * @method static bool hasTestNow() - * @method static \Illuminate\Support\Carbon instance(DateTimeInterface $date) + * @method static \Illuminate\Support\Carbon instance(\DateTimeInterface $date) * @method static bool isImmutable() * @method static bool isModifiableUnit($unit) * @method static bool isMutable() @@ -66,14 +66,14 @@ * @method static bool localeHasPeriodSyntax($locale) * @method static bool localeHasShortUnits(string $locale) * @method static void macro(string $name, ?callable $macro) - * @method static \Illuminate\Support\Carbon|null make($var, DateTimeZone|string|null $timezone = null) + * @method static \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) * @method static void mixin(object|string $mixin) - * @method static \Illuminate\Support\Carbon now(DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) * @method static string pluralUnit(string $unit) * @method static \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) - * @method static \Illuminate\Support\Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon rawParse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() @@ -93,16 +93,16 @@ * @method static bool shouldOverflowYears() * @method static string singularUnit(string $unit) * @method static void sleep(int|float $seconds) - * @method static \Illuminate\Support\Carbon today(DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) * @method static string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) * @method static mixed withTestNow(mixed $testNow, callable $callback) - * @method static static withTimeZone(DateTimeZone|string|int|null $timezone) - * @method static \Illuminate\Support\Carbon yesterday(DateTimeZone|string|int|null $timezone = null) + * @method static static withTimeZone(\DateTimeZone|string|int|null $timezone) + * @method static \Illuminate\Support\Carbon yesterday(\DateTimeZone|string|int|null $timezone = null) * * @see \Illuminate\Support\DateFactory */ From 1d658958cbc99fa58c0a253d30ba8f831974dacf Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:53:32 +0000 Subject: [PATCH 282/455] Update facade docblocks --- src/Illuminate/Support/Facades/Date.php | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index 09aea90c8152..fb55ef29656f 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -21,9 +21,9 @@ * @method static \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, \DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) * @method static \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) * @method static \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) @@ -55,7 +55,7 @@ * @method static bool hasMacro($name) * @method static bool hasRelativeKeywords(?string $time) * @method static bool hasTestNow() - * @method static \Illuminate\Support\Carbon instance(\DateTimeInterface $date) + * @method static \Illuminate\Support\Carbon instance(DateTimeInterface $date) * @method static bool isImmutable() * @method static bool isModifiableUnit($unit) * @method static bool isMutable() @@ -66,14 +66,14 @@ * @method static bool localeHasPeriodSyntax($locale) * @method static bool localeHasShortUnits(string $locale) * @method static void macro(string $name, ?callable $macro) - * @method static \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) + * @method static \Illuminate\Support\Carbon|null make($var, DateTimeZone|string|null $timezone = null) * @method static void mixin(object|string $mixin) - * @method static \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon now(DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) * @method static string pluralUnit(string $unit) * @method static \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) - * @method static \Illuminate\Support\Carbon rawParse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() @@ -93,16 +93,16 @@ * @method static bool shouldOverflowYears() * @method static string singularUnit(string $unit) * @method static void sleep(int|float $seconds) - * @method static \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon today(DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) * @method static string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) * @method static mixed withTestNow(mixed $testNow, callable $callback) - * @method static static withTimeZone(\DateTimeZone|string|int|null $timezone) - * @method static \Illuminate\Support\Carbon yesterday(\DateTimeZone|string|int|null $timezone = null) + * @method static static withTimeZone(DateTimeZone|string|int|null $timezone) + * @method static \Illuminate\Support\Carbon yesterday(DateTimeZone|string|int|null $timezone = null) * * @see \Illuminate\Support\DateFactory */ From c74e7e39220203673dc2e46555513b37431768b5 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Tue, 1 Apr 2025 20:08:08 +0200 Subject: [PATCH 283/455] Make `db:seed` command prohibitable (#55238) I think it is generally undesirable and potentially unsafe to execute seeders in production databases. This change allows users fine-grained control to prohibit `db:seed` from running. --- .../Database/Console/Seeds/SeedCommand.php | 8 +++-- tests/Database/SeedCommandTest.php | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Console/Seeds/SeedCommand.php b/src/Illuminate/Database/Console/Seeds/SeedCommand.php index 5ea590493eb2..515ff410b30c 100644 --- a/src/Illuminate/Database/Console/Seeds/SeedCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeedCommand.php @@ -4,6 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; +use Illuminate\Console\Prohibitable; use Illuminate\Database\ConnectionResolverInterface as Resolver; use Illuminate\Database\Eloquent\Model; use Symfony\Component\Console\Attribute\AsCommand; @@ -13,7 +14,7 @@ #[AsCommand(name: 'db:seed')] class SeedCommand extends Command { - use ConfirmableTrait; + use ConfirmableTrait, Prohibitable; /** * The console command name. @@ -55,8 +56,9 @@ public function __construct(Resolver $resolver) */ public function handle() { - if (! $this->confirmToProceed()) { - return 1; + if ($this->isProhibited() || + ! $this->confirmToProceed()) { + return Command::FAILURE; } $this->components->info('Seeding database.'); diff --git a/tests/Database/SeedCommandTest.php b/tests/Database/SeedCommandTest.php index 2c01b91dc3ea..aa9a8d25aa63 100644 --- a/tests/Database/SeedCommandTest.php +++ b/tests/Database/SeedCommandTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Database; +use Illuminate\Console\Command; use Illuminate\Console\OutputStyle; use Illuminate\Console\View\Components\Factory; use Illuminate\Container\Container; @@ -103,8 +104,39 @@ public function testWithoutModelEvents() $container->shouldHaveReceived('call')->with([$command, 'handle']); } + public function testProhibitable() + { + $input = new ArrayInput([]); + $output = new NullOutput; + $outputStyle = new OutputStyle($input, $output); + + $resolver = m::mock(ConnectionResolverInterface::class); + + $container = m::mock(Container::class); + $container->shouldReceive('call'); + $container->shouldReceive('runningUnitTests')->andReturn('true'); + $container->shouldReceive('make')->with(OutputStyle::class, m::any())->andReturn( + $outputStyle + ); + $container->shouldReceive('make')->with(Factory::class, m::any())->andReturn( + new Factory($outputStyle) + ); + + $command = new SeedCommand($resolver); + $command->setLaravel($container); + + // call run to set up IO, then fire manually. + $command->run($input, $output); + + SeedCommand::prohibit(); + + Assert::assertSame(Command::FAILURE, $command->handle()); + } + protected function tearDown(): void { + SeedCommand::prohibit(false); + Model::unsetEventDispatcher(); m::close(); From 19fc5b2626709fe89f3d64e7bc7a0351fb28327e Mon Sep 17 00:00:00 2001 From: AJ <60591772+devajmeireles@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:28:47 -0300 Subject: [PATCH 284/455] [12.x] Introducing `Rules\Password::appliedRules` Method (#55206) * introducing the method * introducing basic tests and rewriting the docblock * Update Password.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Validation/Rules/Password.php | 20 +++++++++++ .../Validation/ValidationPasswordRuleTest.php | 36 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/Illuminate/Validation/Rules/Password.php b/src/Illuminate/Validation/Rules/Password.php index 7b89672dc923..1c131149c54a 100644 --- a/src/Illuminate/Validation/Rules/Password.php +++ b/src/Illuminate/Validation/Rules/Password.php @@ -379,4 +379,24 @@ protected function fail($messages) return false; } + + /** + * Get information about the current state of the password validation rules. + * + * @return array + */ + public function appliedRules() + { + return [ + 'min' => $this->min, + 'max' => $this->max, + 'mixedCase' => $this->mixedCase, + 'letters' => $this->letters, + 'numbers' => $this->numbers, + 'symbols' => $this->symbols, + 'uncompromised' => $this->uncompromised, + 'compromisedThreshold' => $this->compromisedThreshold, + 'customRules' => $this->customRules, + ]; + } } diff --git a/tests/Validation/ValidationPasswordRuleTest.php b/tests/Validation/ValidationPasswordRuleTest.php index 8fb9673ebff9..dec04626b3e1 100644 --- a/tests/Validation/ValidationPasswordRuleTest.php +++ b/tests/Validation/ValidationPasswordRuleTest.php @@ -339,6 +339,42 @@ public function message() ]); } + public function testCanRetrieveAllRulesApplied() + { + $password = Password::min(2) + ->max(4) + ->mixedCase() + ->numbers() + ->letters() + ->symbols(); + + $this->assertSame($password->appliedRules(), [ + 'min' => 2, + 'max' => 4, + 'mixedCase' => true, + 'letters' => true, + 'numbers' => true, + 'symbols' => true, + 'uncompromised' => false, + 'compromisedThreshold' => 0, + 'customRules' => [], + ]); + + $password = Password::min(2); + + $this->assertSame($password->appliedRules(), [ + 'min' => 2, + 'max' => null, + 'mixedCase' => false, + 'letters' => false, + 'numbers' => false, + 'symbols' => false, + 'uncompromised' => false, + 'compromisedThreshold' => 0, + 'customRules' => [], + ]); + } + protected function passes($rule, $values) { $this->assertValidationRules($rule, $values, true, []); From 9b98cecc8a5c1cf2c5170a7225520c7aa759f749 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:29:00 -0400 Subject: [PATCH 285/455] [12.x] Allowing merging model attributes before insert via `Model::fillAndInsert()` (#55038) * wip * docblock * wip * different approach * unused * add back passthru * fix failing test * tear down * clean up * wip * there we go * welcome hydrateAndInsert * revert unneeded change * change to fill* * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Eloquent/Builder.php | 61 ++++++ .../DatabaseEloquentIntegrationTest.php | 193 ++++++++++++++++++ 2 files changed, 254 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 8d29884faf0b..4e22b9ae9fa2 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -446,6 +446,67 @@ public function hydrate(array $items) }, $items)); } + /** + * Insert into the database after merging the model's default attributes, setting timestamps, and casting values. + * + * @param array> $values + * @return bool + */ + public function fillAndInsert(array $values) + { + return $this->insert($this->fillForInsert($values)); + } + + /** + * Insert (ignoring errors) into the database after merging the model's default attributes, setting timestamps, and casting values. + * + * @param array> $values + * @return int + */ + public function fillAndInsertOrIgnore(array $values) + { + return $this->insertOrIgnore($this->fillForInsert($values)); + } + + /** + * Insert a record into the database and get its ID after merging the model's default attributes, setting timestamps, and casting values. + * + * @param array $values + * @return int + */ + public function fillAndInsertGetId(array $values) + { + return $this->insertGetId($this->fillForInsert([$values])[0]); + } + + /** + * Enrich the given values by merging in the model's default attributes, adding timestamps, and casting values. + * + * @param array> $values + * @return array> + */ + public function fillForInsert(array $values) + { + if (empty($values)) { + return []; + } + + if (! is_array(reset($values))) { + $values = [$values]; + } + + $this->model->unguarded(function () use (&$values) { + foreach ($values as $key => $rowValues) { + $values[$key] = tap( + $this->newModelInstance($rowValues), + fn ($model) => $model->setUniqueIds() + )->getAttributes(); + } + }); + + return $this->addTimestampsToUpsertValues($values); + } + /** * Create a collection of models from a raw query. * diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index cbb33e760d2e..914feff0f993 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\Concerns\HasUuids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Eloquent\ModelNotFoundException; @@ -16,6 +17,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Database\QueryException; +use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\UniqueConstraintViolationException; use Illuminate\Pagination\AbstractPaginator as Paginator; use Illuminate\Pagination\Cursor; @@ -23,6 +25,7 @@ use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Date; +use Illuminate\Support\Str; use Illuminate\Tests\Integration\Database\Fixtures\Post; use Illuminate\Tests\Integration\Database\Fixtures\User; use PHPUnit\Framework\TestCase; @@ -80,6 +83,14 @@ protected function createSchema() $table->timestamps(); }); + $this->schema()->create('users_having_uuids', function (Blueprint $table) { + $table->id(); + $table->uuid(); + $table->string('name'); + $table->tinyInteger('role'); + $table->string('role_string'); + }); + foreach (['default', 'second_connection'] as $connection) { $this->schema($connection)->create('users', function ($table) { $table->increments('id'); @@ -187,6 +198,8 @@ protected function tearDown(): void Eloquent::unsetConnectionResolver(); Carbon::setTestNow(null); + Str::createUuidsNormally(); + DB::flushQueryLog(); } /** @@ -2461,6 +2474,147 @@ public function testTouchingBiDirectionalChaperonedModelUpdatesAllRelatedTimesta } } + public function testCanFillAndInsert() + { + DB::enableQueryLog(); + Carbon::setTestNow('2025-03-15T07:32:00Z'); + + $this->assertTrue(EloquentTestUser::fillAndInsert([ + ['email' => 'taylor@laravel.com', 'birthday' => null], + ['email' => 'nuno@laravel.com', 'birthday' => new Carbon('1980-01-01')], + ['email' => 'tim@laravel.com', 'birthday' => '1987-11-01', 'created_at' => '2025-01-02T02:00:55', 'updated_at' => Carbon::parse('2025-02-19T11:41:13')], + ])); + + $this->assertCount(1, DB::getQueryLog()); + + $this->assertCount(3, $users = EloquentTestUser::get()); + + $users->take(2)->each(function (EloquentTestUser $user) { + $this->assertEquals(Carbon::parse('2025-03-15T07:32:00Z'), $user->created_at); + $this->assertEquals(Carbon::parse('2025-03-15T07:32:00Z'), $user->updated_at); + }); + + $tim = $users->firstWhere('email', 'tim@laravel.com'); + $this->assertEquals(Carbon::parse('2025-01-02T02:00:55'), $tim->created_at); + $this->assertEquals(Carbon::parse('2025-02-19T11:41:13'), $tim->updated_at); + + $this->assertNull($users[0]->birthday); + $this->assertInstanceOf(\DateTime::class, $users[1]->birthday); + $this->assertInstanceOf(\DateTime::class, $users[2]->birthday); + $this->assertEquals('1987-11-01', $users[2]->birthday->format('Y-m-d')); + + DB::flushQueryLog(); + + $this->assertTrue(EloquentTestWithJSON::fillAndInsert([ + ['id' => 1, 'json' => ['album' => 'Keep It Like a Secret', 'release_date' => '1999-02-02']], + ['id' => 2, 'json' => (object) ['album' => 'You In Reverse', 'release_date' => '2006-04-11']], + ])); + + $this->assertCount(1, DB::getQueryLog()); + + $this->assertCount(2, $testsWithJson = EloquentTestWithJSON::get()); + + $testsWithJson->each(function (EloquentTestWithJSON $testWithJson) { + $this->assertIsArray($testWithJson->json); + $this->assertArrayHasKey('album', $testWithJson->json); + }); + } + + public function testCanFillAndInsertWithUniqueStringIds() + { + Str::createUuidsUsingSequence([ + '00000000-0000-7000-0000-000000000000', + '11111111-0000-7000-0000-000000000000', + '22222222-0000-7000-0000-000000000000', + ]); + + $this->assertTrue(ModelWithUniqueStringIds::fillAndInsert([ + [ + 'name' => 'Taylor', 'role' => IntBackedRole::Admin, 'role_string' => StringBackedRole::Admin, + ], + [ + 'name' => 'Nuno', 'role' => 3, 'role_string' => 'admin', + ], + [ + 'name' => 'Dries', 'uuid' => 'bbbb0000-0000-7000-0000-000000000000', + ], + [ + 'name' => 'Chris', + ], + ])); + + $models = ModelWithUniqueStringIds::get(); + + $taylor = $models->firstWhere('name', 'Taylor'); + $nuno = $models->firstWhere('name', 'Nuno'); + $dries = $models->firstWhere('name', 'Dries'); + $chris = $models->firstWhere('name', 'Chris'); + + $this->assertEquals(IntBackedRole::Admin, $taylor->role); + $this->assertEquals(StringBackedRole::Admin, $taylor->role_string); + $this->assertSame('00000000-0000-7000-0000-000000000000', $taylor->uuid); + + $this->assertEquals(IntBackedRole::Admin, $nuno->role); + $this->assertEquals(StringBackedRole::Admin, $nuno->role_string); + $this->assertSame('11111111-0000-7000-0000-000000000000', $nuno->uuid); + + $this->assertEquals(IntBackedRole::User, $dries->role); + $this->assertEquals(StringBackedRole::User, $dries->role_string); + $this->assertSame('bbbb0000-0000-7000-0000-000000000000', $dries->uuid); + + $this->assertEquals(IntBackedRole::User, $chris->role); + $this->assertEquals(StringBackedRole::User, $chris->role_string); + $this->assertSame('22222222-0000-7000-0000-000000000000', $chris->uuid); + } + + public function testFillAndInsertOrIgnore() + { + Str::createUuidsUsingSequence([ + '00000000-0000-7000-0000-000000000000', + '11111111-0000-7000-0000-000000000000', + '22222222-0000-7000-0000-000000000000', + ]); + + $this->assertEquals(1, ModelWithUniqueStringIds::fillAndInsertOrIgnore([ + [ + 'id' => 1, 'name' => 'Taylor', 'role' => IntBackedRole::Admin, 'role_string' => StringBackedRole::Admin, + ], + ])); + + $this->assertSame(1, ModelWithUniqueStringIds::fillAndInsertOrIgnore([ + [ + 'id' => 1, 'name' => 'Taylor', 'role' => IntBackedRole::Admin, 'role_string' => StringBackedRole::Admin, + ], + [ + 'id' => 2, 'name' => 'Nuno', + ], + ])); + + $models = ModelWithUniqueStringIds::get(); + $this->assertSame('00000000-0000-7000-0000-000000000000', $models->firstWhere('name', 'Taylor')->uuid); + $this->assertSame( + ['uuid' => '22222222-0000-7000-0000-000000000000', 'role' => IntBackedRole::User], + $models->firstWhere('name', 'Nuno')->only('uuid', 'role') + ); + } + + public function testFillAndInsertGetId() + { + Str::createUuidsUsingSequence([ + '00000000-0000-7000-0000-000000000000', + ]); + + DB::enableQueryLog(); + + $this->assertIsInt($newId = ModelWithUniqueStringIds::fillAndInsertGetId([ + 'name' => 'Taylor', + 'role' => IntBackedRole::Admin, + 'role_string' => StringBackedRole::Admin, + ])); + $this->assertCount(1, DB::getRawQueryLog()); + $this->assertSame($newId, ModelWithUniqueStringIds::sole()->id); + } + /** * Helpers... */ @@ -2786,3 +2940,42 @@ public function children() return $this->hasMany(EloquentTouchingCategory::class, 'parent_id')->chaperone(); } } + +class ModelWithUniqueStringIds extends Eloquent +{ + use HasUuids; + + public $timestamps = false; + + protected $table = 'users_having_uuids'; + + protected function casts() + { + return [ + 'role' => IntBackedRole::class, + 'role_string' => StringBackedRole::class, + ]; + } + + protected $attributes = [ + 'role' => IntBackedRole::User, + 'role_string' => StringBackedRole::User, + ]; + + public function uniqueIds() + { + return ['uuid']; + } +} + +enum IntBackedRole: int +{ + case User = 1; + case Admin = 3; +} + +enum StringBackedRole: string +{ + case User = 'user'; + case Admin = 'admin'; +} From 995e25152b69b6e4284b4195a404924e550ade78 Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Tue, 1 Apr 2025 15:26:46 -0500 Subject: [PATCH 286/455] feat(docs): fix type hints for DateTimeZone and DateTimeInterface (#55243) --- src/Illuminate/Support/DateFactory.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Support/DateFactory.php b/src/Illuminate/Support/DateFactory.php index 01cd16438448..d3595f84f734 100644 --- a/src/Illuminate/Support/DateFactory.php +++ b/src/Illuminate/Support/DateFactory.php @@ -17,9 +17,9 @@ * @method \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) * @method \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) - * @method \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimeString(string $time, \DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) * @method \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) * @method \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) * @method \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) @@ -51,7 +51,7 @@ * @method bool hasMacro($name) * @method bool hasRelativeKeywords(?string $time) * @method bool hasTestNow() - * @method \Illuminate\Support\Carbon instance(DateTimeInterface $date) + * @method \Illuminate\Support\Carbon instance(\DateTimeInterface $date) * @method bool isImmutable() * @method bool isModifiableUnit($unit) * @method bool isMutable() @@ -62,14 +62,14 @@ * @method bool localeHasPeriodSyntax($locale) * @method bool localeHasShortUnits(string $locale) * @method void macro(string $name, ?callable $macro) - * @method \Illuminate\Support\Carbon|null make($var, DateTimeZone|string|null $timezone = null) + * @method \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) * @method void mixin(object|string $mixin) - * @method \Illuminate\Support\Carbon now(DateTimeZone|string|int|null $timezone = null) - * @method \Illuminate\Support\Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) - * @method \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon parse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) * @method string pluralUnit(string $unit) * @method \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) - * @method \Illuminate\Support\Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon rawParse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method void resetMonthsOverflow() * @method void resetToStringFormat() * @method void resetYearsOverflow() @@ -89,16 +89,16 @@ * @method bool shouldOverflowYears() * @method string singularUnit(string $unit) * @method void sleep(int|float $seconds) - * @method \Illuminate\Support\Carbon today(DateTimeZone|string|int|null $timezone = null) - * @method \Illuminate\Support\Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) * @method string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method void useMonthsOverflow($monthsOverflow = true) * @method void useStrictMode($strictModeEnabled = true) * @method void useYearsOverflow($yearsOverflow = true) * @method mixed withTestNow(mixed $testNow, callable $callback) - * @method static withTimeZone(DateTimeZone|string|int|null $timezone) - * @method \Illuminate\Support\Carbon yesterday(DateTimeZone|string|int|null $timezone = null) + * @method static withTimeZone(\DateTimeZone|string|int|null $timezone) + * @method \Illuminate\Support\Carbon yesterday(\DateTimeZone|string|int|null $timezone = null) */ class DateFactory { From 5849cbb40020aef81f9994ea2c3188708609aad1 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 1 Apr 2025 20:27:12 +0000 Subject: [PATCH 287/455] Update facade docblocks --- src/Illuminate/Support/Facades/Date.php | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index fb55ef29656f..09aea90c8152 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -21,9 +21,9 @@ * @method static \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) * @method static \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) * @method static \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) @@ -55,7 +55,7 @@ * @method static bool hasMacro($name) * @method static bool hasRelativeKeywords(?string $time) * @method static bool hasTestNow() - * @method static \Illuminate\Support\Carbon instance(DateTimeInterface $date) + * @method static \Illuminate\Support\Carbon instance(\DateTimeInterface $date) * @method static bool isImmutable() * @method static bool isModifiableUnit($unit) * @method static bool isMutable() @@ -66,14 +66,14 @@ * @method static bool localeHasPeriodSyntax($locale) * @method static bool localeHasShortUnits(string $locale) * @method static void macro(string $name, ?callable $macro) - * @method static \Illuminate\Support\Carbon|null make($var, DateTimeZone|string|null $timezone = null) + * @method static \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) * @method static void mixin(object|string $mixin) - * @method static \Illuminate\Support\Carbon now(DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) * @method static string pluralUnit(string $unit) * @method static \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) - * @method static \Illuminate\Support\Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon rawParse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() @@ -93,16 +93,16 @@ * @method static bool shouldOverflowYears() * @method static string singularUnit(string $unit) * @method static void sleep(int|float $seconds) - * @method static \Illuminate\Support\Carbon today(DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) * @method static string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) * @method static mixed withTestNow(mixed $testNow, callable $callback) - * @method static static withTimeZone(DateTimeZone|string|int|null $timezone) - * @method static \Illuminate\Support\Carbon yesterday(DateTimeZone|string|int|null $timezone = null) + * @method static static withTimeZone(\DateTimeZone|string|int|null $timezone) + * @method static \Illuminate\Support\Carbon yesterday(\DateTimeZone|string|int|null $timezone = null) * * @see \Illuminate\Support\DateFactory */ From e561ef80984a87cea4650b8b7a0277603415c31d Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Tue, 1 Apr 2025 16:40:34 -0500 Subject: [PATCH 288/455] Fix DateFactory docblock type hints (#55244) --- src/Illuminate/Support/DateFactory.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Support/DateFactory.php b/src/Illuminate/Support/DateFactory.php index d3595f84f734..5a2feb599f9f 100644 --- a/src/Illuminate/Support/DateFactory.php +++ b/src/Illuminate/Support/DateFactory.php @@ -13,7 +13,7 @@ * @method \Illuminate\Support\Carbon|null create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) * @method \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) * @method \Illuminate\Support\Carbon|null createFromFormat($format, $time, $timezone = null) - * @method \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null) + * @method \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?\Symfony\Contracts\Translation\TranslatorInterface $translator = null) * @method \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) * @method \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) @@ -40,7 +40,7 @@ * @method string getLocale() * @method int getMidDayAt() * @method string getTimeFormatByPrecision(string $unitPrecision) - * @method string|Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) + * @method string|\Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) * @method \Illuminate\Support\Carbon|null getTestNow() * @method \Symfony\Contracts\Translation\TranslatorInterface getTranslator() * @method int getWeekEndsAt(?string $locale = null) @@ -65,11 +65,11 @@ * @method \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) * @method void mixin(object|string $mixin) * @method \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) - * @method \Illuminate\Support\Carbon parse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon parse(\DateTimeInterface|\Carbon\WeekDay|\Carbon\Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) * @method string pluralUnit(string $unit) * @method \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) - * @method \Illuminate\Support\Carbon rawParse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method \Illuminate\Support\Carbon rawParse(\DateTimeInterface|\Carbon\WeekDay|\Carbon\Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method void resetMonthsOverflow() * @method void resetToStringFormat() * @method void resetYearsOverflow() @@ -80,7 +80,7 @@ * @method void setMidDayAt($hour) * @method void setTestNow(mixed $testNow = null) * @method void setTestNowAndTimezone(mixed $testNow = null, $timezone = null) - * @method void setToStringFormat(string|Closure|null $format) + * @method void setToStringFormat(string|\Closure|null $format) * @method void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) * @method void setWeekEndsAt($day) * @method void setWeekStartsAt($day) @@ -91,8 +91,8 @@ * @method void sleep(int|float $seconds) * @method \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) * @method \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) - * @method string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) - * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) + * @method string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = \Carbon\CarbonInterface::TRANSLATE_ALL) + * @method string translateWith(\Symfony\Contracts\Translation\TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method void useMonthsOverflow($monthsOverflow = true) * @method void useStrictMode($strictModeEnabled = true) * @method void useYearsOverflow($yearsOverflow = true) From a60c75a96a7a53e886ecf9c4579e5e11ca5548ee Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 1 Apr 2025 21:41:08 +0000 Subject: [PATCH 289/455] Update facade docblocks --- src/Illuminate/Support/Facades/Date.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index 09aea90c8152..4f62930ac285 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -17,7 +17,7 @@ * @method static \Illuminate\Support\Carbon|null create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) * @method static \Illuminate\Support\Carbon|null createFromFormat($format, $time, $timezone = null) - * @method static \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null) + * @method static \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?\Symfony\Contracts\Translation\TranslatorInterface $translator = null) * @method static \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) @@ -44,7 +44,7 @@ * @method static string getLocale() * @method static int getMidDayAt() * @method static string getTimeFormatByPrecision(string $unitPrecision) - * @method static string|Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) + * @method static string|\Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) * @method static \Illuminate\Support\Carbon|null getTestNow() * @method static \Symfony\Contracts\Translation\TranslatorInterface getTranslator() * @method static int getWeekEndsAt(?string $locale = null) @@ -69,11 +69,11 @@ * @method static \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) * @method static void mixin(object|string $mixin) * @method static \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) - * @method static \Illuminate\Support\Carbon parse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parse(\DateTimeInterface|\Carbon\WeekDay|\Carbon\Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) * @method static string pluralUnit(string $unit) * @method static \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) - * @method static \Illuminate\Support\Carbon rawParse(\DateTimeInterface|WeekDay|Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon rawParse(\DateTimeInterface|\Carbon\WeekDay|\Carbon\Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) * @method static void resetMonthsOverflow() * @method static void resetToStringFormat() * @method static void resetYearsOverflow() @@ -84,7 +84,7 @@ * @method static void setMidDayAt($hour) * @method static void setTestNow(mixed $testNow = null) * @method static void setTestNowAndTimezone(mixed $testNow = null, $timezone = null) - * @method static void setToStringFormat(string|Closure|null $format) + * @method static void setToStringFormat(string|\Closure|null $format) * @method static void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) * @method static void setWeekEndsAt($day) * @method static void setWeekStartsAt($day) @@ -95,8 +95,8 @@ * @method static void sleep(int|float $seconds) * @method static \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) * @method static \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) - * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) - * @method static string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) + * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = \Carbon\CarbonInterface::TRANSLATE_ALL) + * @method static string translateWith(\Symfony\Contracts\Translation\TranslatorInterface $translator, string $key, array $parameters = [], $number = null) * @method static void useMonthsOverflow($monthsOverflow = true) * @method static void useStrictMode($strictModeEnabled = true) * @method static void useYearsOverflow($yearsOverflow = true) From c8363f60020b73360435ce90f5edcd3946e5040c Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Wed, 2 Apr 2025 16:04:57 +0200 Subject: [PATCH 290/455] List missing `migrate:rollback` in DB::prohibitDestructiveCommands PhpDoc (#55252) * List missing `migrate:rollback` in DB::prohibitDestructiveCommands PhpDoc * Fix alphabetical order --- src/Illuminate/Support/Facades/DB.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 3ddeae76298a..f1c41bc0abb4 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -122,7 +122,7 @@ class DB extends Facade /** * Indicate if destructive Artisan commands should be prohibited. * - * Prohibits: db:wipe, migrate:fresh, migrate:refresh, and migrate:reset + * Prohibits: db:wipe, migrate:fresh, migrate:refresh, migrate:reset, and migrate:rollback * * @param bool $prohibit * @return void From 0a48401cd7f4b608220a73622572485f2eeeb618 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Wed, 2 Apr 2025 10:09:00 -0400 Subject: [PATCH 291/455] [12.x] Add `Http::requestException()` (#55241) * add helper * test * Update Factory.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Http/Client/Factory.php | 30 ++++++++++++++++++++++++-- tests/Http/HttpClientTest.php | 10 +++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 559868655519..0371a8add718 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -153,6 +153,21 @@ public function globalOptions($options) * @return \GuzzleHttp\Promise\PromiseInterface */ public static function response($body = null, $status = 200, $headers = []) + { + return Create::promiseFor( + static::psr7Response($body, $status, $headers) + ); + } + + /** + * Create a new PSR-7 response instance for use during stubbing. + * + * @param array|string|null $body + * @param int $status + * @param array $headers + * @return \GuzzleHttp\Psr7\Response + */ + public static function psr7Response($body = null, $status = 200, $headers = []) { if (is_array($body)) { $body = json_encode($body); @@ -160,9 +175,20 @@ public static function response($body = null, $status = 200, $headers = []) $headers['Content-Type'] = 'application/json'; } - $response = new Psr7Response($status, $headers, $body); + return new Psr7Response($status, $headers, $body); + } - return Create::promiseFor($response); + /** + * Create a new RequestException instance for use during stubbing. + * + * @param array|string|null $body + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Client\RequestException + */ + public static function requestException($body = null, $status = 200, $headers = []) + { + return new RequestException(new Response(static::psr7Response($body, $status, $headers))); } /** diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index af4618fb357b..7f3a17ed43c5 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -2362,6 +2362,16 @@ public function testRequestsWillBeWaitingSleepMillisecondsReceivedInBackoffArray ]); } + public function testRequestException() + { + $requestException = $this->factory->requestException(['code' => 'not_found'], 404, ['X-RateLimit-Remaining' => 199]); + + $this->assertInstanceOf(RequestException::class, $requestException); + $this->assertEqualsCanonicalizing(['code' => 'not_found'], $requestException->response->json()); + $this->assertEquals(404, $requestException->response->status()); + $this->assertEquals(199, $requestException->response->header('X-RateLimit-Remaining')); + } + public function testFakeConnectionException() { $this->factory->fake($this->factory->failedConnection('Fake')); From f8c4d572d07cc76c8aff60be5e00aac9aff251af Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 2 Apr 2025 14:09:39 +0000 Subject: [PATCH 292/455] Update facade docblocks --- src/Illuminate/Support/Facades/Http.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index dc7843f932e7..7be14c45f6b8 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -10,6 +10,8 @@ * @method static \Illuminate\Http\Client\Factory globalResponseMiddleware(callable $middleware) * @method static \Illuminate\Http\Client\Factory globalOptions(\Closure|array $options) * @method static \GuzzleHttp\Promise\PromiseInterface response(array|string|null $body = null, int $status = 200, array $headers = []) + * @method static \GuzzleHttp\Psr7\Response psr7Response(array|string|null $body = null, int $status = 200, array $headers = []) + * @method static \Illuminate\Http\Client\RequestException requestException(array|string|null $body = null, int $status = 200, array $headers = []) * @method static \GuzzleHttp\Promise\PromiseInterface failedConnection(string|null $message = null) * @method static \Illuminate\Http\Client\ResponseSequence sequence(array $responses = []) * @method static bool preventingStrayRequests() From 15ea7cf1d7c70d501397c92bf5feb80a5d1f7cbb Mon Sep 17 00:00:00 2001 From: Chester Sykes Date: Wed, 2 Apr 2025 22:29:18 +0800 Subject: [PATCH 293/455] New: Uri `pathSegments()` helper method (#55250) * Added `pathSegments` helper function on the `Uri` class * Added doc block * pint * Refactored to return the segments as a collection instead of just an array * add more tests * dont use helper --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Uri.php | 12 ++++++++++++ tests/Support/SupportUriTest.php | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/Illuminate/Support/Uri.php b/src/Illuminate/Support/Uri.php index 9dfa50986320..0a9333de35e5 100644 --- a/src/Illuminate/Support/Uri.php +++ b/src/Illuminate/Support/Uri.php @@ -152,6 +152,18 @@ public function path(): ?string return $path === '' ? '/' : $path; } + /** + * Get the URI's path segments. + * + * Empty or missing paths are returned as an empty collection. + */ + public function pathSegments(): Collection + { + $path = $this->path(); + + return $path === '/' ? new Collection : new Collection(explode('/', $path)); + } + /** * Get the URI's query string. */ diff --git a/tests/Support/SupportUriTest.php b/tests/Support/SupportUriTest.php index ffdb870c9302..fe1c9ba60498 100644 --- a/tests/Support/SupportUriTest.php +++ b/tests/Support/SupportUriTest.php @@ -196,4 +196,28 @@ public function test_with_query_prevents_empty_query_string() $this->assertEquals('https://laravel.com', (string) $uri); $this->assertEquals('https://laravel.com', (string) $uri->withQuery([])); } + + public function test_path_segments() + { + $uri = Uri::of('https://laravel.com'); + + $this->assertEquals([], $uri->pathSegments()->toArray()); + + $uri = Uri::of('https://laravel.com/one/two/three'); + + $this->assertEquals(['one', 'two', 'three'], $uri->pathSegments()->toArray()); + $this->assertEquals('one', $uri->pathSegments()->first()); + + $uri = Uri::of('https://laravel.com/one/two/three?foo=bar'); + + $this->assertEquals(3, $uri->pathSegments()->count()); + + $uri = Uri::of('https://laravel.com/one/two/three/?foo=bar'); + + $this->assertEquals(3, $uri->pathSegments()->count()); + + $uri = Uri::of('https://laravel.com/one/two/three/#foo=bar'); + + $this->assertEquals(3, $uri->pathSegments()->count()); + } } From b8f7003222eda24f150f114fe5397213b991586b Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Wed, 2 Apr 2025 12:24:05 -0400 Subject: [PATCH 294/455] [12.x] Do not require returning a Builder instance from a local scope method (#55246) * always return query instance from named scope * remove incorrect docblock * newton's suggestion * call query statically --- .../Database/Eloquent/Attributes/Scope.php | 3 --- src/Illuminate/Database/Eloquent/Model.php | 2 +- .../EloquentNamedScopeAttributeTest.php | 19 +++++++++++++++---- .../Database/Fixtures/NamedScopeUser.php | 6 ++++++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Attributes/Scope.php b/src/Illuminate/Database/Eloquent/Attributes/Scope.php index ff7d1048cbad..d340db490f98 100644 --- a/src/Illuminate/Database/Eloquent/Attributes/Scope.php +++ b/src/Illuminate/Database/Eloquent/Attributes/Scope.php @@ -9,9 +9,6 @@ class Scope { /** * Create a new attribute instance. - * - * @param array|string $classes - * @return void */ public function __construct() { diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index b4c1c449d17f..8137fa1233a6 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -2402,7 +2402,7 @@ public function __call($method, $parameters) public static function __callStatic($method, $parameters) { if (static::isScopeMethodWithAttribute($method)) { - $parameters = [static::query(), ...$parameters]; + return static::query()->$method(...$parameters); } return (new static)->$method(...$parameters); diff --git a/tests/Integration/Database/EloquentNamedScopeAttributeTest.php b/tests/Integration/Database/EloquentNamedScopeAttributeTest.php index 1ad2576ae411..5d1441a43e3a 100644 --- a/tests/Integration/Database/EloquentNamedScopeAttributeTest.php +++ b/tests/Integration/Database/EloquentNamedScopeAttributeTest.php @@ -4,6 +4,7 @@ use Orchestra\Testbench\Attributes\WithMigration; use Orchestra\Testbench\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; #[WithMigration] class EloquentNamedScopeAttributeTest extends TestCase @@ -20,17 +21,27 @@ protected function setUp(): void ); } - public function test_it_can_query_named_scoped_from_the_query_builder() + #[DataProvider('namedScopeDataProvider')] + public function test_it_can_query_named_scoped_from_the_query_builder(string $methodName) { - $query = Fixtures\NamedScopeUser::query()->verified(true); + $query = Fixtures\NamedScopeUser::query()->{$methodName}(true); $this->assertSame($this->query, $query->toRawSql()); } - public function test_it_can_query_named_scoped_from_static_query() + #[DataProvider('namedScopeDataProvider')] + public function test_it_can_query_named_scoped_from_static_query(string $methodName) { - $query = Fixtures\NamedScopeUser::verified(true); + $query = Fixtures\NamedScopeUser::{$methodName}(true); $this->assertSame($this->query, $query->toRawSql()); } + + public static function namedScopeDataProvider(): array + { + return [ + 'scope with return' => ['verified'], + 'scope without return' => ['verifiedWithoutReturn'], + ]; + } } diff --git a/tests/Integration/Database/Fixtures/NamedScopeUser.php b/tests/Integration/Database/Fixtures/NamedScopeUser.php index 111258eb3489..b33b8823dc2e 100644 --- a/tests/Integration/Database/Fixtures/NamedScopeUser.php +++ b/tests/Integration/Database/Fixtures/NamedScopeUser.php @@ -27,6 +27,12 @@ protected function verified(Builder $builder, bool $email = true) ); } + #[NamedScope] + protected function verifiedWithoutReturn(Builder $builder, bool $email = true) + { + $this->verified($builder, $email); + } + public function scopeVerifiedUser(Builder $builder, bool $email = true) { return $builder->when( From 0219fdf28b749460e2f9ebd4e283a00d58b8f758 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 2 Apr 2025 16:25:03 +0000 Subject: [PATCH 295/455] Update version to v12.6.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 9861c5fe58eb..3015cd02781f 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.5.0'; + const VERSION = '12.6.0'; /** * The base path for the Laravel installation. From e6b7c31fae5f7a41d90296f951a4f953c3e27c86 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 2 Apr 2025 16:26:39 +0000 Subject: [PATCH 296/455] Update CHANGELOG --- CHANGELOG.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74e56a7c8327..0a5140359bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,20 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.5.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.6.0...12.x) + +## [v12.6.0](https://github.com/laravel/framework/compare/v12.5.0...v12.6.0) - 2025-04-02 + +* [12.x] Dont stop pruning if pruning one model fails by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/55237 +* [12.x] Update Date Facade Docblocks by [@fdalcin](https://github.com/fdalcin) in https://github.com/laravel/framework/pull/55235 +* Make `db:seed` command prohibitable by [@spawnia](https://github.com/spawnia) in https://github.com/laravel/framework/pull/55238 +* [12.x] Introducing `Rules\Password::appliedRules` Method by [@devajmeireles](https://github.com/devajmeireles) in https://github.com/laravel/framework/pull/55206 +* [12.x] Allowing merging model attributes before insert via `Model::fillAndInsert()` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55038 +* [12.x] Fix type hints for DateTimeZone and DateTimeInterface on DateFactory by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/55243 +* [12.x] Fix DateFactory docblock type hints by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/55244 +* List missing `migrate:rollback` in DB::prohibitDestructiveCommands PhpDoc by [@spawnia](https://github.com/spawnia) in https://github.com/laravel/framework/pull/55252 +* [12.x] Add `Http::requestException()` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55241 +* New: Uri `pathSegments()` helper method by [@chester-sykes](https://github.com/chester-sykes) in https://github.com/laravel/framework/pull/55250 +* [12.x] Do not require returning a Builder instance from a local scope method by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55246 ## [v12.5.0](https://github.com/laravel/framework/compare/v12.4.1...v12.5.0) - 2025-04-01 From 83d07e96740af19d2f0c9ce6f1db9b50de3c064b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Wed, 2 Apr 2025 19:00:22 +0200 Subject: [PATCH 297/455] [12.x] `AbstractPaginator` should implement `CanBeEscapedWhenCastToString` (#55256) * Add failing test * Update AbstractPaginator * Update AbstractPaginator.php --------- Co-authored-by: Taylor Otwell --- .../Pagination/AbstractPaginator.php | 27 +++++++++++++++++-- .../Blade/BladeComponentTagCompilerTest.php | 5 ++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index dc6c9d0adc25..4f0529299928 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -3,6 +3,7 @@ namespace Illuminate\Pagination; use Closure; +use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -18,7 +19,7 @@ * * @mixin \Illuminate\Support\Collection */ -abstract class AbstractPaginator implements Htmlable, Stringable +abstract class AbstractPaginator implements CanBeEscapedWhenCastToString, Htmlable, Stringable { use ForwardsCalls, Tappable; @@ -71,6 +72,13 @@ abstract class AbstractPaginator implements Htmlable, Stringable */ protected $pageName = 'page'; + /** + * Indicates that the paginator's string representation should be escaped when __toString is invoked. + * + * @var bool + */ + protected $escapeWhenCastingToString = false; + /** * The number of links to display on each side of current page link. * @@ -797,6 +805,21 @@ public function __call($method, $parameters) */ public function __toString() { - return (string) $this->render(); + return $this->escapeWhenCastingToString + ? e((string) $this->render()) + : (string) $this->render(); + } + + /** + * Indicate that the paginator's string representation should be escaped when __toString is invoked. + * + * @param bool $escape + * @return $this + */ + public function escapeWhenCastingToString($escape = true) + { + $this->escapeWhenCastingToString = $escape; + + return $this; } } diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index da1fffbd63c5..46d7a1c08f2d 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\View\Factory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Pagination\AbstractPaginator; use Illuminate\View\Compilers\BladeCompiler; use Illuminate\View\Compilers\ComponentTagCompiler; use Illuminate\View\Component; @@ -799,11 +800,15 @@ public function __toString() $model = new class extends Model { }; + $paginator = new class extends AbstractPaginator { + }; + $this->assertEquals(e(''), BladeCompiler::sanitizeComponentAttribute('')); $this->assertEquals(e('1'), BladeCompiler::sanitizeComponentAttribute('1')); $this->assertEquals(1, BladeCompiler::sanitizeComponentAttribute(1)); $this->assertEquals(e(''), BladeCompiler::sanitizeComponentAttribute($class)); $this->assertSame($model, BladeCompiler::sanitizeComponentAttribute($model)); + $this->assertSame($paginator, BladeCompiler::sanitizeComponentAttribute($paginator)); } public function testItThrowsAnExceptionForNonExistingAliases() From 6a08dbdd88538e87753b8a5ca46d25bc0bcf34eb Mon Sep 17 00:00:00 2001 From: Jacob Baker-Kretzmar Date: Wed, 2 Apr 2025 13:45:56 -0400 Subject: [PATCH 298/455] [12.x] Add `whereAttachedTo()` Eloquent builder method (#55245) * Add `whereAttachedTo` and `orWhereAttachedTo` * Add tests --- .../Concerns/QueriesRelationships.php | 58 +++++++++++++++++++ .../Database/DatabaseEloquentBuilderTest.php | 33 ++++++++++- .../DatabaseEloquentIntegrationTest.php | 54 +++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 2a8fc0a35ebb..f9f21536d1fc 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\RelationNotFoundException; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Query\Builder as QueryBuilder; @@ -765,6 +766,63 @@ public function orWhereBelongsTo($related, $relationshipName = null) return $this->whereBelongsTo($related, $relationshipName, 'or'); } + /** + * Add a "belongs to many" relationship where clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection $related + * @param string|null $relationshipName + * @param string $boolean + * @return $this + * + * @throws \Illuminate\Database\Eloquent\RelationNotFoundException + */ + public function whereAttachedTo($related, $relationshipName = null, $boolean = 'and') + { + $relatedCollection = $related instanceof EloquentCollection ? $related : $related->newCollection([$related]); + + $related = $relatedCollection->first(); + + if ($relatedCollection->isEmpty()) { + throw new InvalidArgumentException('Collection given to whereAttachedTo method may not be empty.'); + } + + if ($relationshipName === null) { + $relationshipName = Str::plural(Str::camel(class_basename($related))); + } + + try { + $relationship = $this->model->{$relationshipName}(); + } catch (BadMethodCallException) { + throw RelationNotFoundException::make($this->model, $relationshipName); + } + + if (! $relationship instanceof BelongsToMany) { + throw RelationNotFoundException::make($this->model, $relationshipName, BelongsToMany::class); + } + + $this->has( + $relationshipName, + boolean: $boolean, + callback: fn (Builder $query) => $query->whereKey($relatedCollection), + ); + + return $this; + } + + /** + * Add a "belongs to many" relationship with an "or where" clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model $related + * @param string|null $relationshipName + * @return $this + * + * @throws \RuntimeException + */ + public function orWhereAttachedTo($related, $relationshipName = null) + { + return $this->whereAttachedTo($related, $relationshipName, 'or'); + } + /** * Add subselect queries to include an aggregate value for a relationship. * diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 41e5fa529877..96a6beed7e20 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -1278,6 +1278,29 @@ public function testWhereBelongsTo() $this->assertEquals($result, $builder); } + public function testWhereAttachedTo() + { + $related = new EloquentBuilderTestModelFarRelatedStub; + $related->id = 49; + + $builder = EloquentBuilderTestModelParentStub::whereAttachedTo($related, 'roles'); + + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where exists (select * from "eloquent_builder_test_model_far_related_stubs" inner join "user_role" on "eloquent_builder_test_model_far_related_stubs"."id" = "user_role"."related_id" where "eloquent_builder_test_model_parent_stubs"."id" = "user_role"."self_id" and "eloquent_builder_test_model_far_related_stubs"."id" in (49))', $builder->toSql()); + } + + public function testWhereAttachedToCollection() + { + $model1 = new EloquentBuilderTestModelParentStub; + $model1->id = 3; + + $model2 = new EloquentBuilderTestModelParentStub; + $model2->id = 4; + + $builder = EloquentBuilderTestModelFarRelatedStub::whereAttachedTo(new Collection([$model1, $model2]), 'roles'); + + $this->assertSame('select * from "eloquent_builder_test_model_far_related_stubs" where exists (select * from "eloquent_builder_test_model_parent_stubs" inner join "user_role" on "eloquent_builder_test_model_parent_stubs"."id" = "user_role"."self_id" where "eloquent_builder_test_model_far_related_stubs"."id" = "user_role"."related_id" and "eloquent_builder_test_model_parent_stubs"."id" in (3, 4))', $builder->toSql()); + } + public function testDeleteOverride() { $builder = $this->getBuilder(); @@ -2813,7 +2836,15 @@ public function baz() class EloquentBuilderTestModelFarRelatedStub extends Model { - // + public function roles() + { + return $this->belongsToMany( + EloquentBuilderTestModelParentStub::class, + 'user_role', + 'related_id', + 'self_id', + ); + } } class EloquentBuilderTestModelSelfRelatedStub extends Model diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 914feff0f993..1d176afa00f1 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -170,6 +170,15 @@ protected function createSchema() $table->integer('parent_id')->nullable(); $table->timestamps(); }); + + $this->schema($connection)->create('achievements', function ($table) { + $table->increments('id'); + }); + + $this->schema($connection)->create('eloquent_test_achievement_eloquent_test_user', function ($table) { + $table->integer('eloquent_test_achievement_id'); + $table->integer('eloquent_test_user_id'); + }); } $this->schema($connection)->create('non_incrementing_users', function ($table) { @@ -1483,6 +1492,34 @@ public function testBelongsToManyRelationshipModelsAreProperlyHydratedOverCursor } } + public function testWhereAttachedTo() + { + $user1 = EloquentTestUser::create(['email' => 'user1@gmail.com']); + $user2 = EloquentTestUser::create(['email' => 'user2@gmail.com']); + $user3 = EloquentTestUser::create(['email' => 'user3@gmail.com']); + $achievement1 = EloquentTestAchievement::create(); + $achievement2 = EloquentTestAchievement::create(); + $achievement3 = EloquentTestAchievement::create(); + + $user1->eloquentTestAchievements()->attach([$achievement1]); + $user2->eloquentTestAchievements()->attach([$achievement1, $achievement3]); + $user3->eloquentTestAchievements()->attach([$achievement2, $achievement3]); + + $achievedAchievement1 = EloquentTestUser::whereAttachedTo($achievement1)->get(); + + $this->assertSame(2, $achievedAchievement1->count()); + $this->assertTrue($achievedAchievement1->contains($user1)); + $this->assertTrue($achievedAchievement1->contains($user2)); + + $achievedByUser1or2 = EloquentTestAchievement::whereAttachedTo( + new Collection([$user1, $user2]) + )->get(); + + $this->assertSame(2, $achievedByUser1or2->count()); + $this->assertTrue($achievedByUser1or2->contains($achievement1)); + $this->assertTrue($achievedByUser1or2->contains($achievement3)); + } + public function testBasicHasManyEagerLoading() { $user = EloquentTestUser::create(['email' => 'taylorotwell@gmail.com']); @@ -2686,6 +2723,11 @@ public function postWithPhotos() $join->where('photo.imageable_type', 'EloquentTestPost'); }); } + + public function eloquentTestAchievements() + { + return $this->belongsToMany(EloquentTestAchievement::class); + } } class EloquentTestUserWithCustomFriendPivot extends EloquentTestUser @@ -2941,6 +2983,18 @@ public function children() } } +class EloquentTestAchievement extends Eloquent +{ + public $timestamps = false; + + protected $table = 'achievements'; + + public function eloquentTestUsers() + { + return $this->belongsToMany(EloquentTestUser::class); + } +} + class ModelWithUniqueStringIds extends Eloquent { use HasUuids; From d8dff6dda44dfa59adbc594b73efde67e9c6b171 Mon Sep 17 00:00:00 2001 From: Richard van Baarsen Date: Wed, 2 Apr 2025 21:35:42 +0200 Subject: [PATCH 299/455] Make Illuminate\Support\Uri Macroable (#55260) * Make Illuminate\Support\Uri Macroable * Simplify test * update test --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Uri.php | 3 ++- tests/Support/SupportUriTest.php | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Uri.php b/src/Illuminate/Support/Uri.php index 0a9333de35e5..b90d8c48b7be 100644 --- a/src/Illuminate/Support/Uri.php +++ b/src/Illuminate/Support/Uri.php @@ -9,6 +9,7 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Support\Traits\Conditionable; use Illuminate\Support\Traits\Dumpable; +use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\Tappable; use League\Uri\Contracts\UriInterface; use League\Uri\Uri as LeagueUri; @@ -17,7 +18,7 @@ class Uri implements Htmlable, Responsable, Stringable { - use Conditionable, Dumpable, Tappable; + use Conditionable, Dumpable, Macroable, Tappable; /** * The URI instance. diff --git a/tests/Support/SupportUriTest.php b/tests/Support/SupportUriTest.php index fe1c9ba60498..1f86588a1eb8 100644 --- a/tests/Support/SupportUriTest.php +++ b/tests/Support/SupportUriTest.php @@ -220,4 +220,15 @@ public function test_path_segments() $this->assertEquals(3, $uri->pathSegments()->count()); } + + public function test_macroable() + { + Uri::macro('myMacro', function () { + return $this->withPath('foobar'); + }); + + $uri = new Uri('https://laravel.com/'); + + $this->assertSame('https://laravel.com/foobar', (string) $uri->myMacro()); + } } From cc889e6ee0c551898d3ec8e89acfeed095712d37 Mon Sep 17 00:00:00 2001 From: Tim Kunze Date: Wed, 2 Apr 2025 21:57:36 +0200 Subject: [PATCH 300/455] [12.x] Add resource helper functions to Model/Collections (#55107) * Add resource helper functions * Fix doc-block style * Remove empty line * Make resource param optional and guess resource name * Use throw_unless instead of assert * Extract name guessing function * Add tests for resource helpers * Fix formatting * Fix namespace conflicts and add current page * Use more descriptive LogicException instead of Exception * Refactor to use traits and extend base collection instead of eloquent collection * Ensure trait method exists * formatting * formatting * formatting * adjust tests and logic * add testS * remove comment --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Collections/Collection.php | 3 +- src/Illuminate/Database/Eloquent/Model.php | 4 +- .../Http/Resources/TransformsToResource.php | 74 +++++++++++++++++++ .../TransformsToResourceCollection.php | 59 +++++++++++++++ .../Pagination/AbstractPaginator.php | 3 +- ...DatabaseEloquentResourceCollectionTest.php | 52 +++++++++++++ .../DatabaseEloquentResourceModelTest.php | 68 +++++++++++++++++ .../EloquentResourceCollectionTestModel.php | 10 +++ .../EloquentResourceTestResourceModel.php | 11 +++ ...TestResourceModelWithGuessableResource.php | 11 +++ .../Models/PaginatorResourceTestModel.php | 11 +++ tests/Pagination/PaginatorResourceTest.php | 58 +++++++++++++++ 12 files changed, 361 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Http/Resources/TransformsToResource.php create mode 100644 src/Illuminate/Http/Resources/TransformsToResourceCollection.php create mode 100644 tests/Database/DatabaseEloquentResourceCollectionTest.php create mode 100644 tests/Database/DatabaseEloquentResourceModelTest.php create mode 100644 tests/Database/Fixtures/Models/EloquentResourceCollectionTestModel.php create mode 100644 tests/Database/Fixtures/Models/EloquentResourceTestResourceModel.php create mode 100644 tests/Database/Fixtures/Models/EloquentResourceTestResourceModelWithGuessableResource.php create mode 100644 tests/Pagination/Fixtures/Models/PaginatorResourceTestModel.php create mode 100644 tests/Pagination/PaginatorResourceTest.php diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 784057067509..962bfefd670c 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -5,6 +5,7 @@ use ArrayAccess; use ArrayIterator; use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString; +use Illuminate\Http\Resources\TransformsToResourceCollection; use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; @@ -24,7 +25,7 @@ class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerabl /** * @use \Illuminate\Support\Traits\EnumeratesValues */ - use EnumeratesValues, Macroable; + use EnumeratesValues, Macroable, TransformsToResourceCollection; /** * The items contained in the collection. diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 8137fa1233a6..f730ec3cd24c 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\Pivot; +use Illuminate\Http\Resources\TransformsToResource; use Illuminate\Support\Arr; use Illuminate\Support\Collection as BaseCollection; use Illuminate\Support\Str; @@ -39,7 +40,8 @@ abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToSt Concerns\HidesAttributes, Concerns\GuardsAttributes, Concerns\PreventsCircularRecursion, - ForwardsCalls; + ForwardsCalls, + TransformsToResource; /** @use HasCollection<\Illuminate\Database\Eloquent\Collection> */ use HasCollection; diff --git a/src/Illuminate/Http/Resources/TransformsToResource.php b/src/Illuminate/Http/Resources/TransformsToResource.php new file mode 100644 index 000000000000..15319c7676d2 --- /dev/null +++ b/src/Illuminate/Http/Resources/TransformsToResource.php @@ -0,0 +1,74 @@ +|null $resourceClass + * @return JsonResource + * + * @throws \Throwable + */ + public function toResource(?string $resourceClass = null): JsonResource + { + if ($resourceClass === null) { + return $this->guessResource(); + } + + return $resourceClass::make($this); + } + + /** + * Guess the resource class for the model. + * + * @return JsonResource + * + * @throws \Throwable + */ + protected function guessResource(): JsonResource + { + foreach (static::guessResourceName() as $resourceClass) { + if (is_string($resourceClass) && class_exists($resourceClass)) { + return $resourceClass::make($this); + } + } + + throw new LogicException(sprintf('Failed to find resource class for model [%s].', get_class($this))); + } + + /** + * Guess the resource class name for the model. + * + * @return array> + */ + public static function guessResourceName(): array + { + $modelClass = static::class; + + if (! Str::contains($modelClass, '\\Models\\')) { + return []; + } + + $relativeNamespace = Str::after($modelClass, '\\Models\\'); + + $relativeNamespace = Str::contains($relativeNamespace, '\\') + ? Str::before($relativeNamespace, '\\'.class_basename($modelClass)) + : ''; + + $potentialResource = sprintf( + '%s\\Http\\Resources\\%s%s', + Str::before($modelClass, '\\Models'), + strlen($relativeNamespace) > 0 ? $relativeNamespace.'\\' : '', + class_basename($modelClass) + ); + + return [$potentialResource.'Resource', $potentialResource]; + } +} diff --git a/src/Illuminate/Http/Resources/TransformsToResourceCollection.php b/src/Illuminate/Http/Resources/TransformsToResourceCollection.php new file mode 100644 index 000000000000..2e98388e71cd --- /dev/null +++ b/src/Illuminate/Http/Resources/TransformsToResourceCollection.php @@ -0,0 +1,59 @@ +|null $resourceClass + * @return ResourceCollection + * + * @throws \Throwable + */ + public function toResourceCollection(?string $resourceClass = null): ResourceCollection + { + if ($resourceClass === null) { + return $this->guessResourceCollection(); + } + + return $resourceClass::collection($this); + } + + /** + * Guess the resource collection for the items. + * + * @return ResourceCollection + * + * @throws \Throwable + */ + protected function guessResourceCollection(): ResourceCollection + { + if ($this->isEmpty()) { + return new ResourceCollection($this); + } + + $model = $this->items[0] ?? null; + + throw_unless(is_object($model), LogicException::class, 'Resource collection guesser expects the collection to contain objects.'); + + /** @var class-string $className */ + $className = get_class($model); + + throw_unless(method_exists($className, 'guessResourceName'), LogicException::class, sprintf('Expected class %s to implement guessResourceName method. Make sure the model uses the TransformsToResource trait.', $className)); + + foreach ($className::guessResourceName() as $resourceClass) { + if (is_string($resourceClass) && class_exists($resourceClass)) { + return $resourceClass::collection($this); + } + } + + throw new LogicException(sprintf('Failed to find resource class for model [%s].', $className)); + } +} diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index 4f0529299928..dad034f7f1d9 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -5,6 +5,7 @@ use Closure; use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString; use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Http\Resources\TransformsToResourceCollection; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; @@ -21,7 +22,7 @@ */ abstract class AbstractPaginator implements CanBeEscapedWhenCastToString, Htmlable, Stringable { - use ForwardsCalls, Tappable; + use ForwardsCalls, Tappable, TransformsToResourceCollection; /** * All of the items being paginated. diff --git a/tests/Database/DatabaseEloquentResourceCollectionTest.php b/tests/Database/DatabaseEloquentResourceCollectionTest.php new file mode 100644 index 000000000000..ba8bd7e0c181 --- /dev/null +++ b/tests/Database/DatabaseEloquentResourceCollectionTest.php @@ -0,0 +1,52 @@ +toResourceCollection(EloquentResourceCollectionTestResource::class); + + $this->assertInstanceOf(JsonResource::class, $resource); + } + + public function testItThrowsExceptionWhenResourceCannotBeFound() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Failed to find resource class for model [Illuminate\Tests\Database\Fixtures\Models\EloquentResourceCollectionTestModel].'); + + $collection = new Collection([ + new EloquentResourceCollectionTestModel(), + ]); + $collection->toResourceCollection(); + } + + public function testItCanGuessResourceWhenNotProvided() + { + $collection = new Collection([ + new EloquentResourceCollectionTestModel(), + ]); + + class_alias(EloquentResourceCollectionTestResource::class, 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceCollectionTestModelResource'); + + $resource = $collection->toResourceCollection(); + + $this->assertInstanceOf(JsonResource::class, $resource); + } +} + +class EloquentResourceCollectionTestResource extends JsonResource +{ + // +} diff --git a/tests/Database/DatabaseEloquentResourceModelTest.php b/tests/Database/DatabaseEloquentResourceModelTest.php new file mode 100644 index 000000000000..5cfb26cfd413 --- /dev/null +++ b/tests/Database/DatabaseEloquentResourceModelTest.php @@ -0,0 +1,68 @@ +toResource(EloquentResourceTestJsonResource::class); + + $this->assertInstanceOf(EloquentResourceTestJsonResource::class, $resource); + $this->assertSame($model, $resource->resource); + } + + public function testItThrowsExceptionWhenResourceCannotBeFound() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Failed to find resource class for model [Illuminate\Tests\Database\Fixtures\Models\EloquentResourceTestResourceModel].'); + + $model = new EloquentResourceTestResourceModel(); + $model->toResource(); + } + + public function testItCanGuessResourceWhenNotProvided() + { + $model = new EloquentResourceTestResourceModelWithGuessableResource(); + + class_alias(EloquentResourceTestJsonResource::class, 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModelWithGuessableResourceResource'); + + $resource = $model->toResource(); + + $this->assertInstanceOf(EloquentResourceTestJsonResource::class, $resource); + $this->assertSame($model, $resource->resource); + } + + public function testItCanGuessResourceWhenNotProvidedWithNonResourceSuffix() + { + $model = new EloquentResourceTestResourceModelWithGuessableResource(); + + class_alias(EloquentResourceTestJsonResource::class, 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModelWithGuessableResource'); + + $resource = $model->toResource(); + + $this->assertInstanceOf(EloquentResourceTestJsonResource::class, $resource); + $this->assertSame($model, $resource->resource); + } + + public function testItCanGuessResourceName() + { + $model = new EloquentResourceTestResourceModel(); + $this->assertEquals([ + 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModelResource', + 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModel' + ], $model::guessResourceName()); + } +} + +class EloquentResourceTestJsonResource extends JsonResource +{ + // +} diff --git a/tests/Database/Fixtures/Models/EloquentResourceCollectionTestModel.php b/tests/Database/Fixtures/Models/EloquentResourceCollectionTestModel.php new file mode 100644 index 000000000000..0596158dc5de --- /dev/null +++ b/tests/Database/Fixtures/Models/EloquentResourceCollectionTestModel.php @@ -0,0 +1,10 @@ +toResourceCollection(PaginatorResourceTestResource::class); + + $this->assertInstanceOf(JsonResource::class, $resource); + } + + public function testItThrowsExceptionWhenResourceCannotBeFound() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Failed to find resource class for model [Illuminate\Tests\Pagination\Fixtures\Models\PaginatorResourceTestModel].'); + + $paginator = new PaginatorResourceTestPaginator([ + new PaginatorResourceTestModel(), + ], 1, 1, 1); + + $paginator->toResourceCollection(); + } + + public function testItCanGuessResourceWhenNotProvided() + { + $paginator = new PaginatorResourceTestPaginator([ + new PaginatorResourceTestModel(), + ], 1, 1, 1); + + class_alias(PaginatorResourceTestResource::class, 'Illuminate\Tests\Pagination\Fixtures\Http\Resources\PaginatorResourceTestModelResource'); + + $resource = $paginator->toResourceCollection(); + + $this->assertInstanceOf(JsonResource::class, $resource); + } +} + +class PaginatorResourceTestResource extends JsonResource +{ + // +} + +class PaginatorResourceTestPaginator extends LengthAwarePaginator +{ + // +} From b5a8ea68d74d73e2a0f8d0db35a51ebcbe3781f3 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 2 Apr 2025 19:58:00 +0000 Subject: [PATCH 301/455] Apply fixes from StyleCI --- tests/Database/DatabaseEloquentResourceCollectionTest.php | 1 - tests/Database/DatabaseEloquentResourceModelTest.php | 3 +-- .../Fixtures/Models/EloquentResourceTestResourceModel.php | 1 - .../EloquentResourceTestResourceModelWithGuessableResource.php | 1 - .../Pagination/Fixtures/Models/PaginatorResourceTestModel.php | 1 - tests/Pagination/PaginatorResourceTest.php | 1 - 6 files changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/Database/DatabaseEloquentResourceCollectionTest.php b/tests/Database/DatabaseEloquentResourceCollectionTest.php index ba8bd7e0c181..e2a1232c3694 100644 --- a/tests/Database/DatabaseEloquentResourceCollectionTest.php +++ b/tests/Database/DatabaseEloquentResourceCollectionTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Database; use Illuminate\Database\Eloquent\Collection; -use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Tests\Database\Fixtures\Models\EloquentResourceCollectionTestModel; use PHPUnit\Framework\TestCase; diff --git a/tests/Database/DatabaseEloquentResourceModelTest.php b/tests/Database/DatabaseEloquentResourceModelTest.php index 5cfb26cfd413..0be4eb3ad83d 100644 --- a/tests/Database/DatabaseEloquentResourceModelTest.php +++ b/tests/Database/DatabaseEloquentResourceModelTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Database; -use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Tests\Database\Fixtures\Models\EloquentResourceTestResourceModel; use Illuminate\Tests\Database\Fixtures\Models\EloquentResourceTestResourceModelWithGuessableResource; @@ -57,7 +56,7 @@ public function testItCanGuessResourceName() $model = new EloquentResourceTestResourceModel(); $this->assertEquals([ 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModelResource', - 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModel' + 'Illuminate\Tests\Database\Fixtures\Http\Resources\EloquentResourceTestResourceModel', ], $model::guessResourceName()); } } diff --git a/tests/Database/Fixtures/Models/EloquentResourceTestResourceModel.php b/tests/Database/Fixtures/Models/EloquentResourceTestResourceModel.php index 8a28f6e9780b..e171a7de3ec3 100644 --- a/tests/Database/Fixtures/Models/EloquentResourceTestResourceModel.php +++ b/tests/Database/Fixtures/Models/EloquentResourceTestResourceModel.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Database\Fixtures\Models; -use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; class EloquentResourceTestResourceModel extends Model diff --git a/tests/Database/Fixtures/Models/EloquentResourceTestResourceModelWithGuessableResource.php b/tests/Database/Fixtures/Models/EloquentResourceTestResourceModelWithGuessableResource.php index 7b1f3db8cc0a..227c63c0cdc1 100644 --- a/tests/Database/Fixtures/Models/EloquentResourceTestResourceModelWithGuessableResource.php +++ b/tests/Database/Fixtures/Models/EloquentResourceTestResourceModelWithGuessableResource.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Database\Fixtures\Models; -use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; class EloquentResourceTestResourceModelWithGuessableResource extends Model diff --git a/tests/Pagination/Fixtures/Models/PaginatorResourceTestModel.php b/tests/Pagination/Fixtures/Models/PaginatorResourceTestModel.php index 990740980edc..44c65629a175 100644 --- a/tests/Pagination/Fixtures/Models/PaginatorResourceTestModel.php +++ b/tests/Pagination/Fixtures/Models/PaginatorResourceTestModel.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Pagination\Fixtures\Models; -use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; class PaginatorResourceTestModel extends Model diff --git a/tests/Pagination/PaginatorResourceTest.php b/tests/Pagination/PaginatorResourceTest.php index 391851d22d70..6bd0c5e04d3c 100644 --- a/tests/Pagination/PaginatorResourceTest.php +++ b/tests/Pagination/PaginatorResourceTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Pagination; -use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Tests\Pagination\Fixtures\Models\PaginatorResourceTestModel; From 8158e29d76706d948da6a143afd6afe7e67a55a8 Mon Sep 17 00:00:00 2001 From: Peter Gasser Date: Thu, 3 Apr 2025 14:55:52 +0200 Subject: [PATCH 302/455] use char(36) for uuid type on MariaDB < 10.7.0 (#55197) --- .../Schema/Grammars/MariaDbGrammar.php | 4 +++ .../DatabaseMariaDbSchemaGrammarTest.php | 29 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php index 5bf769843e68..72ac8a37dc56 100755 --- a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php @@ -31,6 +31,10 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) */ protected function typeUuid(Fluent $column) { + if (version_compare($this->connection->getServerVersion(), '10.7.0', '<')) { + return 'char(36)'; + } + return 'uuid'; } diff --git a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php index 1152b2c1adcb..1224247e20de 100755 --- a/tests/Database/DatabaseMariaDbSchemaGrammarTest.php +++ b/tests/Database/DatabaseMariaDbSchemaGrammarTest.php @@ -53,6 +53,7 @@ public function testBasicCreateTable() $conn = $this->getConnection(); $conn->shouldReceive('getConfig')->andReturn(null); + $conn->shouldReceive('getServerVersion')->andReturn('10.7.0'); $blueprint = new Blueprint($conn, 'users'); $blueprint->create(); @@ -1118,7 +1119,10 @@ public function testAddingBinary() public function testAddingUuid() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getServerVersion')->andReturn('10.7.0'); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->uuid('foo'); $statements = $blueprint->toSql(); @@ -1126,9 +1130,25 @@ public function testAddingUuid() $this->assertSame('alter table `users` add `foo` uuid not null', $statements[0]); } + public function testAddingUuidOn106() + { + $conn = $this->getConnection(); + $conn->shouldReceive('getServerVersion')->andReturn('10.6.21'); + + $blueprint = new Blueprint($conn, 'users'); + $blueprint->uuid('foo'); + $statements = $blueprint->toSql(); + + $this->assertCount(1, $statements); + $this->assertSame('alter table `users` add `foo` char(36) not null', $statements[0]); + } + public function testAddingUuidDefaultsColumnName() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getServerVersion')->andReturn('10.7.0'); + + $blueprint = new Blueprint($conn, 'users'); $blueprint->uuid(); $statements = $blueprint->toSql(); @@ -1138,7 +1158,10 @@ public function testAddingUuidDefaultsColumnName() public function testAddingForeignUuid() { - $blueprint = new Blueprint($this->getConnection(), 'users'); + $conn = $this->getConnection(); + $conn->shouldReceive('getServerVersion')->andReturn('10.7.0'); + + $blueprint = new Blueprint($conn, 'users'); $foreignUuid = $blueprint->foreignUuid('foo'); $blueprint->foreignUuid('company_id')->constrained(); $blueprint->foreignUuid('laravel_idea_id')->constrained(); From 9482d0eeb9e4a43a48885e822cec7e847ad29839 Mon Sep 17 00:00:00 2001 From: AJ <60591772+devajmeireles@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:50:30 -0300 Subject: [PATCH 303/455] [12.x] Introducing `toArray` to `ComponentAttributeBag` class (#55258) * introducing toArray to ComponentAttributeBag class * using all inside the toArray * Update ComponentAttributeBag.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/View/ComponentAttributeBag.php | 15 +++++++++++++-- tests/View/ViewComponentAttributeBagTest.php | 11 +++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index f9f8812f0895..6ab3ab433ca5 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -4,6 +4,7 @@ use ArrayAccess; use ArrayIterator; +use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -16,7 +17,7 @@ use Stringable; use Traversable; -class ComponentAttributeBag implements ArrayAccess, IteratorAggregate, JsonSerializable, Htmlable, Stringable +class ComponentAttributeBag implements Arrayable, ArrayAccess, IteratorAggregate, JsonSerializable, Htmlable, Stringable { use Conditionable, Macroable; @@ -38,7 +39,7 @@ public function __construct(array $attributes = []) } /** - * Get all of the attribute values. + * Get all the attribute values. * * @return array */ @@ -497,6 +498,16 @@ public function jsonSerialize(): mixed return $this->attributes; } + /** + * Get all the attribute values. + * + * @return array + */ + public function toArray() + { + return $this->all(); + } + /** * Implode the attributes into a single HTML ready string. * diff --git a/tests/View/ViewComponentAttributeBagTest.php b/tests/View/ViewComponentAttributeBagTest.php index 82fbd8687fa1..511181024b2c 100644 --- a/tests/View/ViewComponentAttributeBagTest.php +++ b/tests/View/ViewComponentAttributeBagTest.php @@ -153,4 +153,15 @@ public function testAttributeIsNotEmpty() $this->assertTrue((bool) $bag->isNotEmpty()); } + + public function testAttributeIsArray() + { + $bag = new ComponentAttributeBag([ + 'name' => 'test', + 'class' => 'font-bold', + ]); + + $this->assertIsArray($bag->toArray()); + $this->assertEquals(['name' => 'test', 'class' => 'font-bold'], $bag->toArray()); + } } From 99399696f64d31545ee161905140b66277afd7c8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 3 Apr 2025 09:58:53 -0500 Subject: [PATCH 304/455] move file --- src/Illuminate/Collections/Collection.php | 4 ++-- .../Traits}/TransformsToResourceCollection.php | 2 +- src/Illuminate/Pagination/AbstractPaginator.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/Illuminate/{Http/Resources => Collections/Traits}/TransformsToResourceCollection.php (97%) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 962bfefd670c..baa3489296db 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -4,13 +4,13 @@ use ArrayAccess; use ArrayIterator; +use Illuminate\Collections\Traits\TransformsToResourceCollection; use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString; -use Illuminate\Http\Resources\TransformsToResourceCollection; use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; -use stdClass; use Traversable; +use stdClass; /** * @template TKey of array-key diff --git a/src/Illuminate/Http/Resources/TransformsToResourceCollection.php b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php similarity index 97% rename from src/Illuminate/Http/Resources/TransformsToResourceCollection.php rename to src/Illuminate/Collections/Traits/TransformsToResourceCollection.php index 2e98388e71cd..3820bfa47338 100644 --- a/src/Illuminate/Http/Resources/TransformsToResourceCollection.php +++ b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php @@ -1,6 +1,6 @@ Date: Thu, 3 Apr 2025 15:00:32 +0000 Subject: [PATCH 305/455] Apply fixes from StyleCI --- src/Illuminate/Collections/Collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index baa3489296db..8d2620ee974b 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -9,8 +9,8 @@ use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; -use Traversable; use stdClass; +use Traversable; /** * @template TKey of array-key From 34e05cb8a708f847367810cf9f4f52407692c445 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:01:23 +0000 Subject: [PATCH 306/455] Update version to v12.7.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 3015cd02781f..9d087ee28cd1 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.6.0'; + const VERSION = '12.7.0'; /** * The base path for the Laravel installation. From ea7742a9fb6e7f6743bdeaffd745eaee5032b62f Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:03:05 +0000 Subject: [PATCH 307/455] Update CHANGELOG --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a5140359bff..574f3a08ebc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.6.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.7.0...12.x) + +## [v12.7.0](https://github.com/laravel/framework/compare/v12.6.0...v12.7.0) - 2025-04-03 + +* [12.x] `AbstractPaginator` should implement `CanBeEscapedWhenCastToString` by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/55256 +* [12.x] Add `whereAttachedTo()` Eloquent builder method by [@bakerkretzmar](https://github.com/bakerkretzmar) in https://github.com/laravel/framework/pull/55245 +* Make Illuminate\Support\Uri Macroable by [@riesjart](https://github.com/riesjart) in https://github.com/laravel/framework/pull/55260 +* [12.x] Add resource helper functions to Model/Collections by [@TimKunze96](https://github.com/TimKunze96) in https://github.com/laravel/framework/pull/55107 +* [12.x]: Use char(36) for uuid type on MariaDB < 10.7.0 by [@boedah](https://github.com/boedah) in https://github.com/laravel/framework/pull/55197 +* [12.x] Introducing `toArray` to `ComponentAttributeBag` class by [@devajmeireles](https://github.com/devajmeireles) in https://github.com/laravel/framework/pull/55258 ## [v12.6.0](https://github.com/laravel/framework/compare/v12.5.0...v12.6.0) - 2025-04-02 From 563d2453ea8e696cd61242c00d3a33b1e964bd51 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:29:14 +0000 Subject: [PATCH 308/455] Update version to v12.7.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 9d087ee28cd1..c557f9b73607 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.7.0'; + const VERSION = '12.7.1'; /** * The base path for the Laravel installation. From 7d77b0129956f60299a9337ce3fe4e2be0820b0a Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:30:55 +0000 Subject: [PATCH 309/455] Update CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 574f3a08ebc7..0f10479f8f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.7.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.7.1...12.x) + +## [v12.7.1](https://github.com/laravel/framework/compare/v12.7.0...v12.7.1) - 2025-04-03 ## [v12.7.0](https://github.com/laravel/framework/compare/v12.6.0...v12.7.0) - 2025-04-03 From 9b9309d2336d5b28c36967125b864b9e649544d2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 3 Apr 2025 12:58:28 -0500 Subject: [PATCH 310/455] update namespace --- src/Illuminate/Collections/Collection.php | 4 ++-- .../Collections/Traits/TransformsToResourceCollection.php | 2 +- src/Illuminate/Pagination/AbstractPaginator.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 8d2620ee974b..e26e434b8e7c 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -4,13 +4,13 @@ use ArrayAccess; use ArrayIterator; -use Illuminate\Collections\Traits\TransformsToResourceCollection; use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString; use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; +use Illuminate\Support\Traits\TransformsToResourceCollection; use InvalidArgumentException; -use stdClass; use Traversable; +use stdClass; /** * @template TKey of array-key diff --git a/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php index 3820bfa47338..e91369c4a03d 100644 --- a/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php +++ b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php @@ -1,6 +1,6 @@ Date: Thu, 3 Apr 2025 17:58:47 +0000 Subject: [PATCH 311/455] Apply fixes from StyleCI --- src/Illuminate/Collections/Collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index e26e434b8e7c..486570ebd71f 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -9,8 +9,8 @@ use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\TransformsToResourceCollection; use InvalidArgumentException; -use Traversable; use stdClass; +use Traversable; /** * @template TKey of array-key From a4ba76e06fe6dd02312359f8184ab259900a7780 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:00:49 +0000 Subject: [PATCH 312/455] Update version to v12.7.2 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index c557f9b73607..159fb07bfee8 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.7.1'; + const VERSION = '12.7.2'; /** * The base path for the Laravel installation. From 84f017826b97f1927ce0fa7cf965ca52d3ebbb86 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:02:25 +0000 Subject: [PATCH 313/455] Update CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f10479f8f31..60e57ed14876 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.7.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.7.2...12.x) + +## [v12.7.2](https://github.com/laravel/framework/compare/v12.7.1...v12.7.2) - 2025-04-03 ## [v12.7.1](https://github.com/laravel/framework/compare/v12.7.0...v12.7.1) - 2025-04-03 From e229445b7db53dfcb8d5adfaf257c08e5f32de82 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:56:47 -0400 Subject: [PATCH 314/455] only fetch soft deletes once (#55274) --- src/Illuminate/Database/Eloquent/MassPrunable.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/MassPrunable.php b/src/Illuminate/Database/Eloquent/MassPrunable.php index d9372eb335a4..81e2701263ca 100644 --- a/src/Illuminate/Database/Eloquent/MassPrunable.php +++ b/src/Illuminate/Database/Eloquent/MassPrunable.php @@ -23,8 +23,10 @@ public function pruneAll(int $chunkSize = 1000) $total = 0; + $softDeletable = in_array(SoftDeletes::class, class_uses_recursive(get_class($this))); + do { - $total += $count = in_array(SoftDeletes::class, class_uses_recursive(get_class($this))) + $total += $count = $softDeletable ? $query->forceDelete() : $query->delete(); From 98375d15ebeff70daaf66262d568cdf9258e5bea Mon Sep 17 00:00:00 2001 From: "Philip Iezzi (Pipo)" <2759561+onlime@users.noreply.github.com> Date: Fri, 4 Apr 2025 18:27:04 +0200 Subject: [PATCH 315/455] [12.x] Add createMany mass-assignment variants to `HasOneOrMany` relation (#55262) * Add createMany mass-assignment variants on HasOneOrMany relation * Fixed docblock for forceCreateManyQuietly() * Update HasOneOrMany.php --------- Co-authored-by: Taylor Otwell --- .../Eloquent/Relations/HasOneOrMany.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 4142572207af..7451491cbaf9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -436,6 +436,34 @@ public function createManyQuietly(iterable $records) return Model::withoutEvents(fn () => $this->createMany($records)); } + /** + * Create a Collection of new instances of the related model, allowing mass-assignment. + * + * @param iterable $records + * @return \Illuminate\Database\Eloquent\Collection + */ + public function forceCreateMany(iterable $records) + { + $instances = $this->related->newCollection(); + + foreach ($records as $record) { + $instances->push($this->forceCreate($record)); + } + + return $instances; + } + + /** + * Create a Collection of new instances of the related model, allowing mass-assignment and without raising any events to the parent model. + * + * @param iterable $records + * @return \Illuminate\Database\Eloquent\Collection + */ + public function forceCreateManyQuietly(iterable $records) + { + return Model::withoutEvents(fn () => $this->forceCreateMany($records)); + } + /** * Set the foreign ID for creating a related model. * From 0b96d9bd5430d655427301986c679e481ca64483 Mon Sep 17 00:00:00 2001 From: William Raendchen <105014007+epic-64@users.noreply.github.com> Date: Fri, 4 Apr 2025 18:27:26 +0200 Subject: [PATCH 316/455] cosmetic: include is_array() case in match of getArrayableItems (#55275) getArrayableItems() already makes excellent use of match(true). I would like to include the is_array check in there to make it more uniform and end up with a single expression. --- src/Illuminate/Collections/Traits/EnumeratesValues.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index aee186f0c209..129921d7f1c7 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -1046,11 +1046,8 @@ public function __get($key) */ protected function getArrayableItems($items) { - if (is_array($items)) { - return $items; - } - return match (true) { + is_array($items) => $items, $items instanceof WeakMap => throw new InvalidArgumentException('Collections can not be created using instances of WeakMap.'), $items instanceof Enumerable => $items->all(), $items instanceof Arrayable => $items->toArray(), From 8bb7e9deb56a57b1262c50cd4f955d141a24db6b Mon Sep 17 00:00:00 2001 From: Amirhf Date: Sat, 5 Apr 2025 22:03:28 +0330 Subject: [PATCH 317/455] Add tests for InvokeSerializedClosureCommand (#55281) * Add tests for InvokeSerializedClosureCommand * Fix code style issues in InvokeSerializedClosureCommandTest --------- Co-authored-by: AmirHossein Fallah --- .../InvokeSerializedClosureCommandTest.php | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 tests/Integration/Concurrency/Console/InvokeSerializedClosureCommandTest.php diff --git a/tests/Integration/Concurrency/Console/InvokeSerializedClosureCommandTest.php b/tests/Integration/Concurrency/Console/InvokeSerializedClosureCommandTest.php new file mode 100644 index 000000000000..b20b124112f3 --- /dev/null +++ b/tests/Integration/Concurrency/Console/InvokeSerializedClosureCommandTest.php @@ -0,0 +1,141 @@ +app[Kernel::class]->registerCommand(new InvokeSerializedClosureCommand); + } + + public function testItCanInvokeSerializedClosureFromArgument() + { + // Create a simple closure and serialize it + $closure = fn () => 'Hello, World!'; + $serialized = serialize(new SerializableClosure($closure)); + + // Create a new output buffer + $output = new BufferedOutput; + + // Call the command with the serialized closure + Artisan::call('invoke-serialized-closure', [ + 'code' => $serialized, + ], $output); + + // Get the output and decode it + $result = json_decode($output->fetch(), true); + + // Verify the result + $this->assertTrue($result['successful']); + $this->assertEquals('Hello, World!', unserialize($result['result'])); + } + + public function testItCanInvokeSerializedClosureFromEnvironment() + { + // Create a simple closure and serialize it + $closure = fn () => 'From Environment'; + $serialized = serialize(new SerializableClosure($closure)); + + // Set the environment variable + $_SERVER['LARAVEL_INVOKABLE_CLOSURE'] = $serialized; + + // Create a new output buffer + $output = new BufferedOutput; + + // Call the command without arguments + Artisan::call('invoke-serialized-closure', [], $output); + + // Get the output and decode it + $result = json_decode($output->fetch(), true); + + // Verify the result + $this->assertTrue($result['successful']); + $this->assertEquals('From Environment', unserialize($result['result'])); + + // Clean up + unset($_SERVER['LARAVEL_INVOKABLE_CLOSURE']); + } + + public function testItReturnsNullWhenNoClosureIsProvided() + { + // Create a new output buffer + $output = new BufferedOutput; + + // Call the command without arguments + Artisan::call('invoke-serialized-closure', [], $output); + + // Get the output and decode it + $result = json_decode($output->fetch(), true); + + // Verify the result + $this->assertTrue($result['successful']); + $this->assertNull(unserialize($result['result'])); + } + + public function testItHandlesExceptionsGracefully() + { + // Create a closure that throws an exception + $closure = fn () => throw new RuntimeException('Test exception'); + $serialized = serialize(new SerializableClosure($closure)); + + // Create a new output buffer + $output = new BufferedOutput; + + // Call the command with the serialized closure + Artisan::call('invoke-serialized-closure', [ + 'code' => $serialized, + ], $output); + + // Get the output and decode it + $result = json_decode($output->fetch(), true); + + // Verify the exception was caught + $this->assertFalse($result['successful']); + $this->assertEquals('RuntimeException', $result['exception']); + $this->assertEquals('Test exception', $result['message']); + } + + public function testItHandlesCustomExceptionWithParameters() + { + // Create a closure that throws an exception with parameters + $closure = fn () => throw new CustomParameterException('Test param'); + $serialized = serialize(new SerializableClosure($closure)); + + // Create a new output buffer + $output = new BufferedOutput; + + // Call the command with the serialized closure + Artisan::call('invoke-serialized-closure', [ + 'code' => $serialized, + ], $output); + + // Get the output and decode it + $result = json_decode($output->fetch(), true); + + // Verify the exception was caught and parameters were captured + $this->assertFalse($result['successful']); + $this->assertArrayHasKey('parameters', $result); + $this->assertEquals('Test param', $result['parameters']['customParam'] ?? null); + } +} From e150f371c69cbfb90ff2e89769dce5be86f3302e Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 06:04:28 +0800 Subject: [PATCH 318/455] [12.x] Temporarily prevents PHPUnit 12.1 (#55297) * [12.x] Temporarily prevents PHPUnit 12.1 Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- .github/workflows/tests.yml | 19 ++----------------- composer.json | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 47042d8a82be..e77a34fca89b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -67,19 +67,12 @@ jobs: - name: Set Framework version run: composer config version "12.x-dev" - - name: Set PHPUnit - uses: nick-fields/retry@v3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require phpunit/phpunit:^${{ matrix.phpunit }} --dev --no-interaction --no-update - - name: Install dependencies uses: nick-fields/retry@v3 with: timeout_minutes: 5 max_attempts: 5 - command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress + command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --with="phpunit/phpunit:^${{ matrix.phpunit }}" - name: Execute tests run: vendor/bin/phpunit --display-deprecation ${{ matrix.stability == 'prefer-stable' && '--fail-on-deprecation' || '' }} @@ -134,20 +127,12 @@ jobs: - name: Set Framework version run: composer config version "12.x-dev" - - name: Set PHPUnit - uses: nick-fields/retry@v3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require phpunit/phpunit:^${{ matrix.phpunit }} --dev --no-interaction --no-update - shell: bash - - name: Install dependencies uses: nick-fields/retry@v3 with: timeout_minutes: 5 max_attempts: 5 - command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress + command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --with="phpunit/phpunit:^${{ matrix.phpunit }}" - name: Execute tests run: vendor/bin/phpunit diff --git a/composer.json b/composer.json index 6ce6a3254312..84da03e144a4 100644 --- a/composer.json +++ b/composer.json @@ -115,7 +115,7 @@ "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "phpunit/phpunit": "^10.5.35|^11.5.3|~12.0.1", "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", "symfony/cache": "^7.2.0", From c1c6194fb7f7dd4e4436cf67b072fbb3c7e917cb Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:35:47 +0800 Subject: [PATCH 319/455] [12.x] Test Improvements (#55306) Signed-off-by: Mior Muhammad Zaki --- .github/workflows/tests.yml | 16 ++++++++++------ composer.json | 2 +- tests/Integration/View/BladeTest.php | 22 ++++++++++++++++------ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e77a34fca89b..2a156dd33351 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,11 +40,13 @@ jobs: fail-fast: true matrix: php: [8.2, 8.3, 8.4] - phpunit: ['10.5.35', '11.5.3', '12.0.0'] + phpunit: ['10.5.35', '11.5.3', '12.0.0', '12.1.0'] stability: [prefer-lowest, prefer-stable] exclude: - php: 8.2 phpunit: '12.0.0' + - php: 8.2 + phpunit: '12.1.0' name: PHP ${{ matrix.php }} - PHPUnit ${{ matrix.phpunit }} - ${{ matrix.stability }} @@ -72,7 +74,7 @@ jobs: with: timeout_minutes: 5 max_attempts: 5 - command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --with="phpunit/phpunit:^${{ matrix.phpunit }}" + command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --with="phpunit/phpunit:~${{ matrix.phpunit }}" - name: Execute tests run: vendor/bin/phpunit --display-deprecation ${{ matrix.stability == 'prefer-stable' && '--fail-on-deprecation' || '' }} @@ -99,11 +101,13 @@ jobs: fail-fast: true matrix: php: [8.2, 8.3, 8.4] - phpunit: ['11.5.3'] + phpunit: ['10.5.35', '11.5.3', '12.0.0', '12.1.0'] stability: [prefer-lowest, prefer-stable] exclude: - - php: 8.4 - stability: prefer-lowest + - php: 8.2 + phpunit: '12.0.0' + - php: 8.2 + phpunit: '12.1.0' name: PHP ${{ matrix.php }} - PHPUnit ${{ matrix.phpunit }} - ${{ matrix.stability }} - Windows @@ -132,7 +136,7 @@ jobs: with: timeout_minutes: 5 max_attempts: 5 - command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --with="phpunit/phpunit:^${{ matrix.phpunit }}" + command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --with="phpunit/phpunit:~${{ matrix.phpunit }}" - name: Execute tests run: vendor/bin/phpunit diff --git a/composer.json b/composer.json index 84da03e144a4..6ce6a3254312 100644 --- a/composer.json +++ b/composer.json @@ -115,7 +115,7 @@ "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.5.35|^11.5.3|~12.0.1", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", "symfony/cache": "^7.2.0", diff --git a/tests/Integration/View/BladeTest.php b/tests/Integration/View/BladeTest.php index 6495175337c4..1acb38372b86 100644 --- a/tests/Integration/View/BladeTest.php +++ b/tests/Integration/View/BladeTest.php @@ -11,8 +11,20 @@ use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; +use function Orchestra\Testbench\artisan; +use function Orchestra\Testbench\phpunit_version_compare; + class BladeTest extends TestCase { + /** {@inheritdoc} */ + #[\Override] + protected function tearDown(): void + { + artisan($this, 'view:clear'); + + parent::tearDown(); + } + public function test_rendering_blade_string() { $this->assertSame('Hello Taylor', Blade::render('Hello {{ $name }}', ['name' => 'Taylor'])); @@ -33,8 +45,8 @@ public function test_rendering_blade_long_maxpathlen_string_with_exact_length() // The PHP_MAXPATHLEN restriction is only active, if // open_basedir is set and active. Otherwise, the check // for the PHP_MAXPATHLEN is not active. - if (ini_get('open_basedir') === '') { - $openBaseDir = windows_os() ? explode('\\', __DIR__)[0].'\\'.';'.sys_get_temp_dir() : '/'; + if (ini_get('open_basedir') === '' && phpunit_version_compare('12.1.0', '<')) { + $openBaseDir = explode(DIRECTORY_SEPARATOR, __DIR__)[0].DIRECTORY_SEPARATOR.PATH_SEPARATOR.sys_get_temp_dir(); $iniSet = ini_set( 'open_basedir', $openBaseDir @@ -197,8 +209,6 @@ public function test_bound_name_attribute_can_be_used_if_using_short_slot_names_ public function testViewCacheCommandHandlesConfiguredBladeExtensions() { - $this->artisan('view:clear'); - View::addExtension('sh', 'blade'); $this->artisan('view:cache'); @@ -206,10 +216,10 @@ public function testViewCacheCommandHandlesConfiguredBladeExtensions() $found = collect($compiledFiles) ->contains(fn (SplFileInfo $file) => str_contains($file->getContents(), 'echo "" > output.log')); $this->assertTrue($found); - - $this->artisan('view:clear'); } + /** {@inheritdoc} */ + #[\Override] protected function defineEnvironment($app) { $app['config']->set('view.paths', [__DIR__.'/templates']); From 906295d29f06c2ec6545cee15761a3f735fa1732 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 08:31:51 -0500 Subject: [PATCH 320/455] Bump vite in /src/Illuminate/Foundation/resources/exceptions/renderer (#55301) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.12 to 5.4.17. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.4.17/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.4.17/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 5.4.17 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../resources/exceptions/renderer/package-lock.json | 8 ++++---- .../Foundation/resources/exceptions/renderer/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json b/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json index 5ffbe5243951..3e51c3f26930 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json @@ -11,7 +11,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "tippy.js": "^6.3.7", - "vite": "^5.4.12", + "vite": "^5.4.17", "vite-require": "^0.2.3" } }, @@ -2106,9 +2106,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "5.4.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.12.tgz", - "integrity": "sha512-KwUaKB27TvWwDJr1GjjWthLMATbGEbeWYZIbGZ5qFIsgPP3vWzLu4cVooqhm5/Z2SPDUMjyPVjTztm5tYKwQxA==", + "version": "5.4.17", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.17.tgz", + "integrity": "sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==", "license": "MIT", "dependencies": { "esbuild": "^0.21.3", diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/package.json b/src/Illuminate/Foundation/resources/exceptions/renderer/package.json index 588c6aed9d86..15ea5041d0e7 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/package.json +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/package.json @@ -12,7 +12,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "tippy.js": "^6.3.7", - "vite": "^5.4.12", + "vite": "^5.4.17", "vite-require": "^0.2.3" } } From 8448fa202aadafcd2e65edbaf10339ebb1039d7a Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 21:32:10 +0800 Subject: [PATCH 321/455] [12.x] Test Improvements (#55307) * [12.x] Test Improvements fixes risky tests Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- .../Database/DatabaseEloquentCollectionTest.php | 9 ++++++++- tests/Integration/Cache/Psr6RedisTest.php | 15 +++++++-------- tests/Integration/Cache/RedisStoreTest.php | 17 +++++++++-------- tests/Integration/Queue/RedisQueueTest.php | 17 +++++++++-------- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index 61d22c8a0f0d..a7a71fcebb78 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\TestCase; use stdClass; +use function Orchestra\Testbench\phpunit_version_compare; + class DatabaseEloquentCollectionTest extends TestCase { /** @@ -702,7 +704,12 @@ public function testLoadExistsShouldCastBool() $user = EloquentTestUserModel::with('articles')->first(); $user->articles->loadExists('comments'); $commentsExists = $user->articles->pluck('comments_exists')->toArray(); - $this->assertContainsOnly('bool', $commentsExists); + + if (phpunit_version_compare('11.5.0', '<')) { + $this->assertContainsOnly('bool', $commentsExists); + } else { + $this->assertContainsOnlyBool($commentsExists); + } } public function testWithNonScalarKey() diff --git a/tests/Integration/Cache/Psr6RedisTest.php b/tests/Integration/Cache/Psr6RedisTest.php index 9328077fe6e0..ff8816f9d9e1 100644 --- a/tests/Integration/Cache/Psr6RedisTest.php +++ b/tests/Integration/Cache/Psr6RedisTest.php @@ -14,16 +14,15 @@ class Psr6RedisTest extends TestCase protected function setUp(): void { - parent::setUp(); + $this->afterApplicationCreated(function () { + $this->setUpRedis(); + }); - $this->setUpRedis(); - } + $this->beforeApplicationDestroyed(function () { + $this->tearDownRedis(); + }); - protected function tearDown(): void - { - $this->tearDownRedis(); - - parent::tearDown(); + parent::setUp(); } #[DataProvider('redisClientDataProvider')] diff --git a/tests/Integration/Cache/RedisStoreTest.php b/tests/Integration/Cache/RedisStoreTest.php index 491461950824..f4a217c9e9f2 100644 --- a/tests/Integration/Cache/RedisStoreTest.php +++ b/tests/Integration/Cache/RedisStoreTest.php @@ -16,18 +16,19 @@ class RedisStoreTest extends TestCase { use InteractsWithRedis; + /** {@inheritdoc} */ + #[\Override] protected function setUp(): void { - parent::setUp(); + $this->afterApplicationCreated(function () { + $this->setUpRedis(); + }); - $this->setUpRedis(); - } + $this->beforeApplicationDestroyed(function () { + $this->tearDownRedis(); + }); - protected function tearDown(): void - { - $this->tearDownRedis(); - - parent::tearDown(); + parent::setUp(); } public function testCacheTtl(): void diff --git a/tests/Integration/Queue/RedisQueueTest.php b/tests/Integration/Queue/RedisQueueTest.php index 037dc69cc25d..fdb8b4608cd1 100644 --- a/tests/Integration/Queue/RedisQueueTest.php +++ b/tests/Integration/Queue/RedisQueueTest.php @@ -31,18 +31,19 @@ class RedisQueueTest extends TestCase */ private $container; + /** {@inheritdoc} */ + #[\Override] protected function setUp(): void { - parent::setUp(); - - $this->setUpRedis(); - } + $this->afterApplicationCreated(function () { + $this->setUpRedis(); + }); - protected function tearDown(): void - { - $this->tearDownRedis(); + $this->beforeApplicationDestroyed(function () { + $this->tearDownRedis(); + }); - parent::tearDown(); + parent::setUp(); } /** From e1e4913f4f9c215103290a9863ea90231ff9b3ca Mon Sep 17 00:00:00 2001 From: Takayasu Oyama Date: Mon, 7 Apr 2025 22:50:59 +0900 Subject: [PATCH 322/455] [12.x] add generics to array types for Schema Grammars (#55314) --- .../Database/Schema/Grammars/Grammar.php | 8 +++---- .../Schema/Grammars/MariaDbGrammar.php | 8 +------ .../Database/Schema/Grammars/MySqlGrammar.php | 24 +++++-------------- .../Schema/Grammars/PostgresGrammar.php | 22 +++++++---------- .../Schema/Grammars/SQLiteGrammar.php | 12 +++------- .../Schema/Grammars/SqlServerGrammar.php | 18 +++----------- 6 files changed, 25 insertions(+), 67 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index 5bbfc3a79d0a..ed683d256d30 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -169,7 +169,7 @@ public function compileForeignKeys($schema, $table) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @return array|string + * @return list|string */ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { @@ -185,7 +185,7 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @return array|string + * @return list|string * * @throws \RuntimeException */ @@ -427,8 +427,8 @@ protected function hasCommand(Blueprint $blueprint, $name) * Add a prefix to an array of values. * * @param string $prefix - * @param array $values - * @return array + * @param array $values + * @return array */ public function prefixArray($prefix, array $values) { diff --git a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php index 72ac8a37dc56..3cb682626587 100755 --- a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php @@ -7,13 +7,7 @@ class MariaDbGrammar extends MySqlGrammar { - /** - * Compile a rename column command. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { if (version_compare($this->connection->getServerVersion(), '10.5.2', '<')) { diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 56ff7583c07a..db992eac43ab 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -331,13 +331,7 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent } } - /** - * Compile a rename column command. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { $isMaria = $this->connection->isMaria(); @@ -396,13 +390,7 @@ protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $comma ); } - /** - * Compile a change column command into a series of SQL statements. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileChange(Blueprint $blueprint, Fluent $command) { $column = $command->column; @@ -650,7 +638,7 @@ public function compileRenameIndex(Blueprint $blueprint, Fluent $command) /** * Compile the SQL needed to drop all tables. * - * @param array $tables + * @param array $tables * @return string */ public function compileDropAllTables($tables) @@ -661,7 +649,7 @@ public function compileDropAllTables($tables) /** * Compile the SQL needed to drop all views. * - * @param array $views + * @param array $views * @return string */ public function compileDropAllViews($views) @@ -707,8 +695,8 @@ public function compileTableComment(Blueprint $blueprint, Fluent $command) /** * Quote-escape the given tables, views, or types. * - * @param array $names - * @return array + * @param array $names + * @return array */ public function escapeNames($names) { diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 0d7a82dc2353..a40f7a62e153 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -277,13 +277,7 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent } } - /** - * Compile a change column command into a series of SQL statements. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileChange(Blueprint $blueprint, Fluent $command) { $column = $command->column; @@ -465,7 +459,7 @@ public function compileDropIfExists(Blueprint $blueprint, Fluent $command) /** * Compile the SQL needed to drop all tables. * - * @param array $tables + * @param array $tables * @return string */ public function compileDropAllTables($tables) @@ -476,7 +470,7 @@ public function compileDropAllTables($tables) /** * Compile the SQL needed to drop all views. * - * @param array $views + * @param array $views * @return string */ public function compileDropAllViews($views) @@ -487,7 +481,7 @@ public function compileDropAllViews($views) /** * Compile the SQL needed to drop all types. * - * @param array $types + * @param array $types * @return string */ public function compileDropAllTypes($types) @@ -498,7 +492,7 @@ public function compileDropAllTypes($types) /** * Compile the SQL needed to drop all domains. * - * @param array $domains + * @param array $domains * @return string */ public function compileDropAllDomains($domains) @@ -684,8 +678,8 @@ public function compileTableComment(Blueprint $blueprint, Fluent $command) /** * Quote-escape the given tables, views, or types. * - * @param array $names - * @return array + * @param array $names + * @return array */ public function escapeNames($names) { @@ -1231,7 +1225,7 @@ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column - * @return string|array|null + * @return string|list|null */ protected function modifyGeneratedAs(Blueprint $blueprint, Fluent $column) { diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index a785b0881662..91222b7e83eb 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -319,7 +319,7 @@ public function compileAdd(Blueprint $blueprint, Fluent $command) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @return array|string + * @return list|string */ public function compileAlter(Blueprint $blueprint, Fluent $command) { @@ -370,13 +370,7 @@ public function compileAlter(Blueprint $blueprint, Fluent $command) ], $indexes, [$foreignKeyConstraintsEnabled ? $this->compileEnableForeignKeyConstraints() : null])); } - /** - * Compile a change column command into a series of SQL statements. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileChange(Blueprint $blueprint, Fluent $command) { // Handled on table alteration... @@ -526,7 +520,7 @@ public function compileRebuild($schema = null) * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $command - * @return array|null + * @return list|null */ public function compileDropColumn(Blueprint $blueprint, Fluent $command) { diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 6aff6696d507..5e183a5dce76 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -226,13 +226,7 @@ public function compileAdd(Blueprint $blueprint, Fluent $command) ); } - /** - * Compile a rename column command. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) { return sprintf("sp_rename %s, %s, N'COLUMN'", @@ -241,13 +235,7 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command) ); } - /** - * Compile a change column command into a series of SQL statements. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @param \Illuminate\Support\Fluent $command - * @return array|string - */ + /** @inheritDoc */ public function compileChange(Blueprint $blueprint, Fluent $command) { return [ @@ -1033,7 +1021,7 @@ protected function modifyPersisted(Blueprint $blueprint, Fluent $column) /** * Quote the given string literal. * - * @param string|array $value + * @param string|array $value * @return string */ public function quoteString($value) From 9800c50506e348e42d5dd044936588f85c883913 Mon Sep 17 00:00:00 2001 From: Takayasu Oyama Date: Mon, 7 Apr 2025 22:51:19 +0900 Subject: [PATCH 323/455] [12.x] fix missing nullable for Query/Grammar::compileInsertGetId (#55311) --- src/Illuminate/Database/Query/Grammars/Grammar.php | 2 +- src/Illuminate/Database/Query/Grammars/PostgresGrammar.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index c64aa49a783f..9b35083af603 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -1203,7 +1203,7 @@ public function compileInsertOrIgnore(Builder $query, array $values) * * @param \Illuminate\Database\Query\Builder $query * @param array $values - * @param string $sequence + * @param string|null $sequence * @return string */ public function compileInsertGetId(Builder $query, $values, $sequence) diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index c43a253cd1e2..9207fe54565f 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -383,7 +383,7 @@ public function compileInsertOrIgnoreUsing(Builder $query, array $columns, strin * * @param \Illuminate\Database\Query\Builder $query * @param array $values - * @param string $sequence + * @param string|null $sequence * @return string */ public function compileInsertGetId(Builder $query, $values, $sequence) From 267a072a3e606fe614b787a81be1984ee8af6770 Mon Sep 17 00:00:00 2001 From: Italo Date: Mon, 7 Apr 2025 09:56:45 -0400 Subject: [PATCH 324/455] [12.x] Adds `fromJson()` to Collection (#55310) --- .../Collections/Traits/EnumeratesValues.php | 13 +++++++++ tests/Support/SupportCollectionTest.php | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 129921d7f1c7..d2894529ed6e 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -179,6 +179,19 @@ public static function times($number, ?callable $callback = null) ->map($callback); } + /** + * Create a new collection by decoding a JSON string. + * + * @param string $json + * @param int $depth + * @param int $flags + * @return static + */ + public static function fromJson($json, $depth = 512, $flags = 0) + { + return new static(json_decode($json, true, $depth, $flags)); + } + /** * Get the average value of a given key. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 0e246dc8f3d5..b1e3a387f46e 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2814,6 +2814,35 @@ public function testRangeMethod($collection) ); } + #[DataProvider('collectionClassProvider')] + public function testFromJson($collection) + { + $json = json_encode($array = ['foo' => 'bar', 'baz' => 'quz']); + + $instance = $collection::fromJson($json); + + $this->assertSame($array, $instance->toArray()); + } + + #[DataProvider('collectionClassProvider')] + public function testFromJsonWithDepth($collection) + { + $json = json_encode(['foo' => ['baz' => ['quz']], 'bar' => 'baz']); + + $instance = $collection::fromJson($json, 1); + + $this->assertEmpty($instance->toArray()); + $this->assertSame(JSON_ERROR_DEPTH, json_last_error()); + } + + #[DataProvider('collectionClassProvider')] + public function testFromJsonWithFlags($collection) + { + $instance = $collection::fromJson('{"int":99999999999999999999999}', 512, JSON_BIGINT_AS_STRING); + + $this->assertSame(['int' => '99999999999999999999999'], $instance->toArray()); + } + #[DataProvider('collectionClassProvider')] public function testConstructMakeFromObject($collection) { From 3a93c484950a806389106915671cc1024523e65e Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 21:58:45 +0800 Subject: [PATCH 325/455] [12.x] Fix `illuminate/database` usage as standalone package (#55309) * [12.x] Fix `illuminate/database` usage as standalone package Avoid regression issue introduced in #55107 fixes #55272 Signed-off-by: Mior Muhammad Zaki * Update composer.json * Update composer.json --------- Signed-off-by: Mior Muhammad Zaki Co-authored-by: Taylor Otwell --- .../Traits/TransformsToResourceCollection.php | 7 +++---- src/Illuminate/Collections/composer.json | 1 + .../Eloquent/Concerns}/TransformsToResource.php | 10 +++++----- src/Illuminate/Database/Eloquent/Model.php | 5 ++--- src/Illuminate/Database/composer.json | 1 + 5 files changed, 12 insertions(+), 12 deletions(-) rename src/Illuminate/{Http/Resources => Database/Eloquent/Concerns}/TransformsToResource.php (83%) diff --git a/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php index e91369c4a03d..80fe2d803308 100644 --- a/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php +++ b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php @@ -3,7 +3,6 @@ namespace Illuminate\Support\Traits; use Illuminate\Database\Eloquent\Model; -use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\ResourceCollection; use LogicException; @@ -12,8 +11,8 @@ trait TransformsToResourceCollection /** * Create a new resource collection instance for the given resource. * - * @param class-string|null $resourceClass - * @return ResourceCollection + * @param class-string<\Illuminate\Http\Resources\Json\JsonResource>|null $resourceClass + * @return \Illuminate\Http\Resources\Json\ResourceCollection * * @throws \Throwable */ @@ -29,7 +28,7 @@ public function toResourceCollection(?string $resourceClass = null): ResourceCol /** * Guess the resource collection for the items. * - * @return ResourceCollection + * @return \Illuminate\Http\Resources\Json\ResourceCollection * * @throws \Throwable */ diff --git a/src/Illuminate/Collections/composer.json b/src/Illuminate/Collections/composer.json index ab98b8ee456a..8d9c96125a47 100644 --- a/src/Illuminate/Collections/composer.json +++ b/src/Illuminate/Collections/composer.json @@ -34,6 +34,7 @@ } }, "suggest": { + "illuminate/http": "Required to convert collections to API resources (^12.0).", "symfony/var-dumper": "Required to use the dump method (^7.2)." }, "config": { diff --git a/src/Illuminate/Http/Resources/TransformsToResource.php b/src/Illuminate/Database/Eloquent/Concerns/TransformsToResource.php similarity index 83% rename from src/Illuminate/Http/Resources/TransformsToResource.php rename to src/Illuminate/Database/Eloquent/Concerns/TransformsToResource.php index 15319c7676d2..578de7d0a86f 100644 --- a/src/Illuminate/Http/Resources/TransformsToResource.php +++ b/src/Illuminate/Database/Eloquent/Concerns/TransformsToResource.php @@ -1,6 +1,6 @@ |null $resourceClass - * @return JsonResource + * @param class-string<\Illuminate\Http\Resources\Json\JsonResource>|null $resourceClass + * @return \Illuminate\Http\Resources\Json\JsonResource * * @throws \Throwable */ @@ -28,7 +28,7 @@ public function toResource(?string $resourceClass = null): JsonResource /** * Guess the resource class for the model. * - * @return JsonResource + * @return \Illuminate\Http\Resources\Json\JsonResource * * @throws \Throwable */ @@ -46,7 +46,7 @@ protected function guessResource(): JsonResource /** * Guess the resource class name for the model. * - * @return array> + * @return array> */ public static function guessResourceName(): array { diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index f730ec3cd24c..89ea7f79a3b0 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -17,7 +17,6 @@ use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\Pivot; -use Illuminate\Http\Resources\TransformsToResource; use Illuminate\Support\Arr; use Illuminate\Support\Collection as BaseCollection; use Illuminate\Support\Str; @@ -40,8 +39,8 @@ abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToSt Concerns\HidesAttributes, Concerns\GuardsAttributes, Concerns\PreventsCircularRecursion, - ForwardsCalls, - TransformsToResource; + Concerns\TransformsToResource, + ForwardsCalls; /** @use HasCollection<\Illuminate\Database\Eloquent\Collection> */ use HasCollection; diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 24ac5a219201..606c093f1ba9 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -41,6 +41,7 @@ "illuminate/console": "Required to use the database commands (^12.0).", "illuminate/events": "Required to use the observers with Eloquent (^12.0).", "illuminate/filesystem": "Required to use the migrations (^12.0).", + "illuminate/http": "Required to convert Eloquent models to API resources (^12.0).", "illuminate/pagination": "Required to paginate the result set (^12.0).", "symfony/finder": "Required to use Eloquent model factories (^7.2)." }, From 912ab40b9333bc324044e8d21b642d74dd4ca3ac Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Mon, 7 Apr 2025 16:05:40 +0200 Subject: [PATCH 326/455] Correct array key in InteractsWithInput (#55287) --- src/Illuminate/Http/Concerns/InteractsWithInput.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Http/Concerns/InteractsWithInput.php b/src/Illuminate/Http/Concerns/InteractsWithInput.php index 730ab9e7ade4..b10714ea2d99 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithInput.php +++ b/src/Illuminate/Http/Concerns/InteractsWithInput.php @@ -175,7 +175,7 @@ public function cookie($key = null, $default = null) /** * Get an array of all of the files on the request. * - * @return array + * @return array */ public function allFiles() { @@ -187,8 +187,8 @@ public function allFiles() /** * Convert the given array of Symfony UploadedFiles to custom Laravel UploadedFiles. * - * @param array $files - * @return array + * @param array $files + * @return array */ protected function convertUploadedFiles(array $files) { @@ -240,7 +240,7 @@ protected function isValidFile($file) * * @param string|null $key * @param mixed $default - * @return ($key is null ? array : \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null) + * @return ($key is null ? array : \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null) */ public function file($key = null, $default = null) { From a750ae59c035810b063cb517aee42bad28f8cfa6 Mon Sep 17 00:00:00 2001 From: Will Rowe Date: Mon, 7 Apr 2025 17:22:12 -0400 Subject: [PATCH 327/455] [12.x] Fix support for adding custom observable events from traits (#55286) * Add failing test * Resolve observer attributes after booting has finished - This ensure that all custom events have been registered by any traits first. - It also prevents a new instance of the model from being created by the call to `observe` too early, since an instance created before booting has finished would be in an inconsistent state due to not all of the trait boot methods being run yet and not all of the initializer methods would be registered yet, so they would not be run either. * Style fixes * Add tests for booted callbacks * Add `whenBooted` method to models * Use `whenBooted` instead of registering an event listener - This removes any reliance on the event dispatcher, which complicated testing. * Clear the callbacks when clearing booted models * formatting --------- Co-authored-by: Taylor Otwell --- .../Database/Eloquent/Concerns/HasEvents.php | 2 +- src/Illuminate/Database/Eloquent/Model.php | 28 +++++++++ tests/Database/DatabaseEloquentModelTest.php | 57 +++++++++++++++++++ .../EloquentModelCustomEventsTest.php | 52 +++++++++++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php index 7eda42308be2..fa654de966d4 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php @@ -38,7 +38,7 @@ trait HasEvents */ public static function bootHasEvents() { - static::observe(static::resolveObserveAttributes()); + static::whenBooted(fn () => static::observe(static::resolveObserveAttributes())); } /** diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 89ea7f79a3b0..505eece9f957 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Eloquent; use ArrayAccess; +use Closure; use Illuminate\Contracts\Broadcasting\HasBroadcastChannel; use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Contracts\Queue\QueueableEntity; @@ -149,6 +150,13 @@ abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToSt */ protected static $booted = []; + /** + * The callbacks that should be executed after the model has booted. + * + * @var array + */ + protected static $bootedCallbacks = []; + /** * The array of trait initializers that will be called on each new instance. * @@ -279,6 +287,12 @@ protected function bootIfNotBooted() static::boot(); static::booted(); + static::$bootedCallbacks[static::class] ??= []; + + foreach (static::$bootedCallbacks[static::class] as $callback) { + $callback(); + } + $this->fireModelEvent('booted', false); } } @@ -357,6 +371,19 @@ protected static function booted() // } + /** + * Register a closure to be executed after the model has booted. + * + * @param \Closure $callback + * @return void + */ + protected static function whenBooted(Closure $callback) + { + static::$bootedCallbacks[static::class] ??= []; + + static::$bootedCallbacks[static::class][] = $callback; + } + /** * Clear the list of booted models so they will be re-booted. * @@ -365,6 +392,7 @@ protected static function booted() public static function clearBootedModels() { static::$booted = []; + static::$bootedCallbacks = []; static::$globalScopes = []; } diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 4b9a2be34364..ae7b70490e90 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -2293,6 +2293,35 @@ public function testModelIsBootedOnUnserialize() $this->assertTrue(EloquentModelBootingTestStub::isBooted()); } + public function testCallbacksCanBeRunAfterBootingHasFinished() + { + $this->assertFalse(EloquentModelBootingCallbackTestStub::$bootHasFinished); + + $model = new EloquentModelBootingCallbackTestStub(); + + $this->assertTrue($model::$bootHasFinished); + + EloquentModelBootingCallbackTestStub::unboot(); + } + + public function testBootedCallbacksAreSeparatedByClass() + { + $this->assertFalse(EloquentModelBootingCallbackTestStub::$bootHasFinished); + + $model = new EloquentModelBootingCallbackTestStub(); + + $this->assertTrue($model::$bootHasFinished); + + $this->assertFalse(EloquentChildModelBootingCallbackTestStub::$bootHasFinished); + + $model = new EloquentChildModelBootingCallbackTestStub(); + + $this->assertTrue($model::$bootHasFinished); + + EloquentModelBootingCallbackTestStub::unboot(); + EloquentChildModelBootingCallbackTestStub::unboot(); + } + public function testModelsTraitIsInitialized() { $model = new EloquentModelStubWithTrait; @@ -3602,6 +3631,7 @@ class EloquentModelBootingTestStub extends Model public static function unboot() { unset(static::$booted[static::class]); + unset(static::$bootedCallbacks[static::class]); } public static function isBooted() @@ -4121,3 +4151,30 @@ class EloquentModelWithUseFactoryAttribute extends Model { use HasFactory; } + +trait EloquentTraitBootingCallbackTestStub +{ + public static function bootEloquentTraitBootingCallbackTestStub() + { + static::whenBooted(fn () => static::$bootHasFinished = true); + } +} + +class EloquentModelBootingCallbackTestStub extends Model +{ + use EloquentTraitBootingCallbackTestStub; + + public static bool $bootHasFinished = false; + + public static function unboot() + { + unset(static::$booted[static::class]); + unset(static::$bootedCallbacks[static::class]); + static::$bootHasFinished = false; + } +} + +class EloquentChildModelBootingCallbackTestStub extends EloquentModelBootingCallbackTestStub +{ + public static bool $bootHasFinished = false; +} diff --git a/tests/Integration/Database/EloquentModelCustomEventsTest.php b/tests/Integration/Database/EloquentModelCustomEventsTest.php index 6a85e3379ca4..e52227c3d47f 100644 --- a/tests/Integration/Database/EloquentModelCustomEventsTest.php +++ b/tests/Integration/Database/EloquentModelCustomEventsTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Database\EloquentModelCustomEventsTest; +use Illuminate\Database\Eloquent\Attributes\ObservedBy; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Event; @@ -24,6 +25,11 @@ protected function afterRefreshingDatabase() Schema::create('test_model1', function (Blueprint $table) { $table->increments('id'); }); + + Schema::create('eloquent_model_stub_with_custom_event_from_traits', function (Blueprint $table) { + $table->boolean('custom_attribute'); + $table->boolean('observer_attribute'); + }); } public function testFlushListenersClearsCustomEvents() @@ -45,6 +51,19 @@ public function testCustomEventListenersAreFired() $this->assertTrue($_SERVER['fired_event']); } + + public function testAddObservableEventFromTrait() + { + $model = new EloquentModelStubWithCustomEventFromTrait(); + + $this->assertNull($model->custom_attribute); + $this->assertNull($model->observer_attribute); + + $model->completeCustomAction(); + + $this->assertTrue($model->custom_attribute); + $this->assertTrue($model->observer_attribute); + } } class TestModel1 extends Model @@ -59,3 +78,36 @@ class CustomEvent { // } + +trait CustomEventTrait +{ + public function completeCustomAction() + { + $this->custom_attribute = true; + + $this->fireModelEvent('customEvent'); + } + + public function initializeCustomEventTrait() + { + $this->addObservableEvents([ + 'customEvent', + ]); + } +} + +class CustomObserver +{ + public function customEvent(EloquentModelStubWithCustomEventFromTrait $model) + { + $model->observer_attribute = true; + } +} + +#[ObservedBy(CustomObserver::class)] +class EloquentModelStubWithCustomEventFromTrait extends Model +{ + use CustomEventTrait; + + public $timestamps = false; +} From f82faadf104ed97ce24e2a18b2ab8b0225971080 Mon Sep 17 00:00:00 2001 From: Serhii Litvinchuk Date: Tue, 8 Apr 2025 21:31:21 +0300 Subject: [PATCH 328/455] [12.x] Added Automatic Relation Loading (Eager Loading) Feature (#53655) * Add eloquent relation autoload feature * update tests * update tests * fix cs * fix cs * Rename alwaysAutoloadRelations method to globalAutoloadRelations * Rename enableRelationAutoload method to withRelationAutoload * Optimize withRelationAutoload method * Simplified circular relation autoload detection * formatting * formatting * formatting * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Eloquent/Builder.php | 10 +- .../Database/Eloquent/Collection.php | 47 +++++ .../Eloquent/Concerns/HasAttributes.php | 4 + .../Eloquent/Concerns/HasRelationships.php | 100 ++++++++++ src/Illuminate/Database/Eloquent/Model.php | 28 +++ ...tBelongsToManyWithCastedAttributesTest.php | 2 + .../EloquentModelRelationAutoloadTest.php | 183 ++++++++++++++++++ 7 files changed, 371 insertions(+), 3 deletions(-) create mode 100644 tests/Integration/Database/EloquentModelRelationAutoloadTest.php diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 4e22b9ae9fa2..73163988aec8 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -854,9 +854,13 @@ public function get($columns = ['*']) $models = $builder->eagerLoadRelations($models); } - return $this->applyAfterQueryCallbacks( - $builder->getModel()->newCollection($models) - ); + $collection = $builder->getModel()->newCollection($models); + + if (Model::isAutomaticallyEagerLoadingRelationships()) { + $collection->withRelationshipAutoloading(); + } + + return $this->applyAfterQueryCallbacks($collection); } /** diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index d030a3bc93e9..ba15202828e1 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -248,6 +248,35 @@ public function loadMissing($relations) return $this; } + /** + * Load a relationship path for models of the given type if it is not already eager loaded. + * + * @param array> $tuples + * @return void + */ + public function loadMissingRelationshipChain(array $tuples) + { + [$relation, $class] = array_shift($tuples); + + $this->filter(function ($model) use ($relation, $class) { + return ! is_null($model) && + ! $model->relationLoaded($relation) && + $model::class === $class; + })->load($relation); + + if (empty($tuples)) { + return; + } + + $models = $this->pluck($relation)->whereNotNull(); + + if ($models->first() instanceof BaseCollection) { + $models = $models->collapse(); + } + + (new static($models))->loadMissingRelationshipChain($tuples); + } + /** * Load a relationship path if it is not already eager loaded. * @@ -721,6 +750,24 @@ protected function duplicateComparator($strict) return fn ($a, $b) => $a->is($b); } + /** + * Enable relationship autoloading for all models in this collection. + * + * @return $this + */ + public function withRelationshipAutoloading() + { + $callback = fn ($tuples) => $this->loadMissingRelationshipChain($tuples); + + foreach ($this as $model) { + if (! $model->hasRelationAutoloadCallback()) { + $model->autoloadRelationsUsing($callback); + } + } + + return $this; + } + /** * Get the type of the entities being queued. * diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 8c06e658e47e..0d0fc454bf0b 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -551,6 +551,10 @@ public function getRelationValue($key) return; } + if ($this->attemptToAutoloadRelation($key)) { + return $this->relations[$key]; + } + if ($this->preventsLazyLoading) { $this->handleLazyLoadingViolation($key); } diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index df89155e9382..2f30de88a2b1 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -39,6 +39,13 @@ trait HasRelationships */ protected $touches = []; + /** + * The relationship autoloader callback. + * + * @var \Closure|null + */ + protected $relationAutoloadCallback = null; + /** * The many to many relationship methods. * @@ -92,6 +99,97 @@ public static function resolveRelationUsing($name, Closure $callback) ); } + /** + * Determine if a relationship autoloader callback has been defined. + * + * @return bool + */ + public function hasRelationAutoloadCallback() + { + return ! is_null($this->relationAutoloadCallback); + } + + /** + * Define an automatic relationship autoloader callback for this model and its relations. + * + * @param \Closure $callback + * @param mixed $context + * @return $this + */ + public function autoloadRelationsUsing(Closure $callback, $context = null) + { + $this->relationAutoloadCallback = $callback; + + foreach ($this->relations as $key => $value) { + $this->propagateRelationAutoloadCallbackToRelation($key, $value, $context); + } + + return $this; + } + + /** + * Attempt to autoload the given relationship using the autoload callback. + * + * @param string $key + * @return bool + */ + protected function attemptToAutoloadRelation($key) + { + if (! $this->hasRelationAutoloadCallback()) { + return false; + } + + $this->invokeRelationAutoloadCallbackFor($key, []); + + return $this->relationLoaded($key); + } + + /** + * Invoke the relationship autoloader callback for the given relationships. + * + * @param string $key + * @param array $tuples + * @return void + */ + protected function invokeRelationAutoloadCallbackFor($key, $tuples) + { + $tuples = array_merge([[$key, get_class($this)]], $tuples); + + call_user_func($this->relationAutoloadCallback, $tuples); + } + + /** + * Propagate the relationship autoloader callback to the given related models. + * + * @param string $key + * @param mixed $values + * @param mixed $context + * @return void + */ + protected function propagateRelationAutoloadCallbackToRelation($key, $models, $context = null) + { + if (! $this->hasRelationAutoloadCallback() || ! $models) { + return; + } + + if ($models instanceof Model) { + $models = [$models]; + } + + if (! is_iterable($models)) { + return; + } + + $callback = fn (array $tuples) => $this->invokeRelationAutoloadCallbackFor($key, $tuples); + + foreach ($models as $model) { + // Check if relation autoload contexts are different to avoid circular relation autoload... + if (is_null($context) || $context !== $model) { + $model->autoloadRelationsUsing($callback, $context); + } + } + } + /** * Define a one-to-one relationship. * @@ -988,6 +1086,8 @@ public function setRelation($relation, $value) { $this->relations[$relation] = $value; + $this->propagateRelationAutoloadCallbackToRelation($relation, $value, $this); + return $this; } diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 505eece9f957..b159f1febc9d 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -185,6 +185,13 @@ abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToSt */ protected static $modelsShouldPreventLazyLoading = false; + /** + * Indicates whether relations should be automatically loaded on all models when they are accessed. + * + * @var bool + */ + protected static $modelsShouldAutomaticallyEagerLoadRelationships = false; + /** * The callback that is responsible for handling lazy loading violations. * @@ -473,6 +480,17 @@ public static function preventLazyLoading($value = true) static::$modelsShouldPreventLazyLoading = $value; } + /** + * Determine if model relationships should be automatically eager loaded when accessed. + * + * @param bool $value + * @return void + */ + public static function automaticallyEagerLoadRelationships($value = true) + { + static::$modelsShouldAutomaticallyEagerLoadRelationships = $value; + } + /** * Register a callback that is responsible for handling lazy loading violations. * @@ -2258,6 +2276,16 @@ public static function preventsLazyLoading() return static::$modelsShouldPreventLazyLoading; } + /** + * Determine if relationships are being automatically eager loaded when accessed. + * + * @return bool + */ + public static function isAutomaticallyEagerLoadingRelationships() + { + return static::$modelsShouldAutomaticallyEagerLoadRelationships; + } + /** * Determine if discarding guarded attribute fills is disabled. * diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php index c7cab6453dfb..08f1bd45a56e 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -27,6 +27,7 @@ public function testModelsAreProperlyMatchedToParents() $model1->shouldReceive('getAttribute')->with('foo')->passthru(); $model1->shouldReceive('hasGetMutator')->andReturn(false); $model1->shouldReceive('hasAttributeMutator')->andReturn(false); + $model1->shouldReceive('hasRelationAutoloadCallback')->andReturn(false); $model1->shouldReceive('getCasts')->andReturn([]); $model1->shouldReceive('getRelationValue', 'relationLoaded', 'relationResolver', 'setRelation', 'isRelation')->passthru(); @@ -36,6 +37,7 @@ public function testModelsAreProperlyMatchedToParents() $model2->shouldReceive('getAttribute')->with('foo')->passthru(); $model2->shouldReceive('hasGetMutator')->andReturn(false); $model2->shouldReceive('hasAttributeMutator')->andReturn(false); + $model2->shouldReceive('hasRelationAutoloadCallback')->andReturn(false); $model2->shouldReceive('getCasts')->andReturn([]); $model2->shouldReceive('getRelationValue', 'relationLoaded', 'relationResolver', 'setRelation', 'isRelation')->passthru(); diff --git a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php new file mode 100644 index 000000000000..8f80c5bb5149 --- /dev/null +++ b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php @@ -0,0 +1,183 @@ +increments('id'); + }); + + Schema::create('videos', function (Blueprint $table) { + $table->increments('id'); + }); + + Schema::create('comments', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('parent_id')->nullable(); + $table->morphs('commentable'); + }); + + Schema::create('likes', function (Blueprint $table) { + $table->increments('id'); + $table->morphs('likeable'); + }); + } + + public function testRelationAutoload() + { + $post1 = Post::create(); + $comment1 = $post1->comments()->create(['parent_id' => null]); + $comment2 = $post1->comments()->create(['parent_id' => $comment1->id]); + $comment2->likes()->create(); + $comment2->likes()->create(); + + $post2 = Post::create(); + $comment3 = $post2->comments()->create(['parent_id' => null]); + $comment3->likes()->create(); + + $posts = Post::get(); + + DB::enableQueryLog(); + + $likes = []; + + $posts->withRelationshipAutoloading(); + + foreach ($posts as $post) { + foreach ($post->comments as $comment) { + $likes = array_merge($likes, $comment->likes->all()); + } + } + + $this->assertCount(2, DB::getQueryLog()); + $this->assertCount(3, $likes); + $this->assertTrue($posts[0]->comments[0]->relationLoaded('likes')); + } + + public function testRelationAutoloadVariousNestedMorphRelations() + { + tap(Post::create(), function ($post) { + $post->likes()->create(); + $post->comments()->create(); + tap($post->comments()->create(), function ($comment) { + $comment->likes()->create(); + $comment->likes()->create(); + }); + }); + + tap(Post::create(), function ($post) { + $post->likes()->create(); + tap($post->comments()->create(), function ($comment) { + $comment->likes()->create(); + }); + }); + + tap(Video::create(), function ($video) { + tap($video->comments()->create(), function ($comment) { + $comment->likes()->create(); + }); + }); + + tap(Video::create(), function ($video) { + tap($video->comments()->create(), function ($comment) { + $comment->likes()->create(); + }); + }); + + $likes = Like::get(); + + DB::enableQueryLog(); + + $videos = []; + $videoLike = null; + + $likes->withRelationshipAutoloading(); + + foreach ($likes as $like) { + $likeable = $like->likeable; + + if (($likeable instanceof Comment) && ($likeable->commentable instanceof Video)) { + $videos[] = $likeable->commentable; + $videoLike = $like; + } + } + + $this->assertCount(4, DB::getQueryLog()); + $this->assertCount(2, $videos); + $this->assertTrue($videoLike->relationLoaded('likeable')); + $this->assertTrue($videoLike->likeable->relationLoaded('commentable')); + } +} + +class Comment extends Model +{ + public $timestamps = false; + + protected $guarded = []; + + public function parent() + { + return $this->belongsTo(self::class); + } + + public function likes() + { + return $this->morphMany(Like::class, 'likeable'); + } + + public function commentable() + { + return $this->morphTo(); + } +} + +class Post extends Model +{ + public $timestamps = false; + + public function comments() + { + return $this->morphMany(Comment::class, 'commentable'); + } + + public function likes() + { + return $this->morphMany(Like::class, 'likeable'); + } +} + +class Video extends Model +{ + public $timestamps = false; + + public function comments() + { + return $this->morphMany(Comment::class, 'commentable'); + } + + public function likes() + { + return $this->morphMany(Like::class, 'likeable'); + } +} + +class Like extends Model +{ + public $timestamps = false; + + protected $guarded = []; + + public function likeable() + { + return $this->morphTo(); + } +} From d07ba176016a3a0ef39382c2d443e6661076fe86 Mon Sep 17 00:00:00 2001 From: jsvdvis Date: Tue, 8 Apr 2025 20:32:32 +0200 Subject: [PATCH 329/455] Typehint for key-support for Collection::chunkWhile and LazyCollection::chunkWhile (#55324) Co-authored-by: jaap.vd.vis --- src/Illuminate/Collections/Collection.php | 4 ++-- src/Illuminate/Collections/LazyCollection.php | 2 +- tests/Support/SupportCollectionTest.php | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 486570ebd71f..23e1af7bbfee 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1462,8 +1462,8 @@ public function chunk($size, $preserveKeys = true) /** * Chunk the collection into chunks with a callback. * - * @param callable(TValue, TKey, static): bool $callback - * @return static> + * @param callable(TValue, TKey, static): bool $callback + * @return static> */ public function chunkWhile(callable $callback) { diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 68d6a4acdfef..601e0717590a 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1431,7 +1431,7 @@ public function splitIn($numberOfGroups) * Chunk the collection into chunks with a callback. * * @param callable(TValue, TKey, Collection): bool $callback - * @return static> + * @return static> */ public function chunkWhile(callable $callback) { diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index b1e3a387f46e..2edd11ca6718 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2209,6 +2209,21 @@ public function testChunkWhileOnContiguouslyIncreasingIntegers($collection) $this->assertEquals([8 => 19, 9 => 20, 10 => 21], $data->last()->toArray()); } + #[DataProvider('collectionClassProvider')] + public function testChunkWhilePreservingStringKeys($collection) + { + $data = (new $collection(['a' => 1, 'b' => 1, 'c' => 2, 'd' => 2, 'e' => 3, 'f' => 3, 'g' => 3])) + ->chunkWhile(function ($current, $key, $chunk) { + return $chunk->last() === $current; + }); + + $this->assertInstanceOf($collection, $data); + $this->assertInstanceOf($collection, $data->first()); + $this->assertEquals(['a' => 1, 'b' => 1], $data->first()->toArray()); + $this->assertEquals(['c' => 2, 'd' => 2], $data->get(1)->toArray()); + $this->assertEquals(['e' => 3, 'f' => 3, 'g' => 3], $data->last()->toArray()); + } + #[DataProvider('collectionClassProvider')] public function testEvery($collection) { From 08960dbd8c2843402455151c466497520488650d Mon Sep 17 00:00:00 2001 From: Brian Ferri Date: Tue, 8 Apr 2025 20:35:51 +0200 Subject: [PATCH 330/455] [12.x] Introduce Rule::anyOf() for Validating Against Multiple Rule Sets (#55191) * [12.x] introduce `Rule::oneOf()` (#https://github.com/laravel/framework/discussions/54880) * chore: apply styleCI * feat: add nested oneOf validation test * chore: apply styleCI * refactor: rename `oneof` into `anyof` to fit implementation * fix: wrong failure message * feat: update base tests * feat: add test case * chore: apply styleCI * formatting * feat: allow string fields * feat: add test and clean nested rules * chore: apply styleCI * failing test * Validation tests (#1) * feat: add more validation tests * wip: add failing test * wip: add basic string rule validations * chore: rename object fields for better debugging * refactor: rename ruleSets to rules * fix: respect array rule validation --------- Co-authored-by: Christian Ascone * fix: this should be passing because AnyOf has no type relevance and 'required' only checks to see if the field has something in it --------- Co-authored-by: Christian Ascone --------- Co-authored-by: Christian Ascone * chore: correspond with recent changes https://github.com/brianferri/framework/pull/1/commits/de3b902a950b8f5ba8edaafa273f91d7c6ade295 * chore: remove unused private property * feat: attribute mapping in favor of potentially indexed mapping * feat: add more tests * refactor(tests): remove unnecessary amount of tests, rename parameter properties to be more descriptive/analogous to use cases * chore: apply styleCI * feat: add tests to verify compliance with dot notation nesting validator * formatting * fix: remove messages * fix(wip): regression introduced in 14598f62bf8305bbe2a94ee4e2848d6ec2e05587 https://github.com/laravel/framework/pull/55191#issuecomment-2770383023 * feat: implement star rule counter tests for simple and nested rules Co-authored-by: Christian Ascone * chore: apply styleCI --------- Co-authored-by: Taylor Otwell Co-authored-by: Christian Ascone --- .../Translation/lang/en/validation.php | 1 + src/Illuminate/Validation/Rule.php | 14 + src/Illuminate/Validation/Rules/AnyOf.php | 94 +++++ tests/Validation/ValidationAnyOfRuleTest.php | 376 ++++++++++++++++++ 4 files changed, 485 insertions(+) create mode 100644 src/Illuminate/Validation/Rules/AnyOf.php create mode 100644 tests/Validation/ValidationAnyOfRuleTest.php diff --git a/src/Illuminate/Translation/lang/en/validation.php b/src/Illuminate/Translation/lang/en/validation.php index f19bd64ed6c9..a57a95ed9858 100644 --- a/src/Illuminate/Translation/lang/en/validation.php +++ b/src/Illuminate/Translation/lang/en/validation.php @@ -21,6 +21,7 @@ 'alpha' => 'The :attribute field must only contain letters.', 'alpha_dash' => 'The :attribute field must only contain letters, numbers, dashes, and underscores.', 'alpha_num' => 'The :attribute field must only contain letters and numbers.', + 'any_of' => 'The :attribute field is invalid.', 'array' => 'The :attribute field must be an array.', 'ascii' => 'The :attribute field must only contain single-byte alphanumeric characters and symbols.', 'before' => 'The :attribute field must be a date before :date.', diff --git a/src/Illuminate/Validation/Rule.php b/src/Illuminate/Validation/Rule.php index 44bb2b4347b5..170f4d04a1ea 100644 --- a/src/Illuminate/Validation/Rule.php +++ b/src/Illuminate/Validation/Rule.php @@ -5,6 +5,7 @@ use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Arr; use Illuminate\Support\Traits\Macroable; +use Illuminate\Validation\Rules\AnyOf; use Illuminate\Validation\Rules\ArrayRule; use Illuminate\Validation\Rules\Can; use Illuminate\Validation\Rules\Date; @@ -246,6 +247,19 @@ public static function numeric() return new Numeric; } + /** + * Get an "any of" rule builder instance. + * + * @param array + * @return \Illuminate\Validation\Rules\AnyOf + * + * @throws \InvalidArgumentException + */ + public static function anyOf($rules) + { + return new AnyOf($rules); + } + /** * Compile a set of rules for an attribute. * diff --git a/src/Illuminate/Validation/Rules/AnyOf.php b/src/Illuminate/Validation/Rules/AnyOf.php new file mode 100644 index 000000000000..9d653bdaadbe --- /dev/null +++ b/src/Illuminate/Validation/Rules/AnyOf.php @@ -0,0 +1,94 @@ +rules = $rules; + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * @return bool + */ + public function passes($attribute, $value) + { + foreach ($this->rules as $rule) { + $validator = Validator::make( + Arr::isAssoc(Arr::wrap($value)) ? $value : [$value], + Arr::isAssoc(Arr::wrap($rule)) ? $rule : [$rule], + $this->validator->customMessages, + $this->validator->customAttributes + ); + + if ($validator->passes()) { + return true; + } + } + + return false; + } + + /** + * Get the validation error messages. + * + * @return array + */ + public function message() + { + $message = $this->validator->getTranslator()->get('validation.any_of'); + + return $message === 'validation.any_of' + ? ['The :attribute field is invalid.'] + : $message; + } + + /** + * Set the current validator. + * + * @param \Illuminate\Contracts\Validation\Validator $validator + * @return $this + */ + public function setValidator($validator) + { + $this->validator = $validator; + + return $this; + } +} diff --git a/tests/Validation/ValidationAnyOfRuleTest.php b/tests/Validation/ValidationAnyOfRuleTest.php new file mode 100644 index 000000000000..f0806182c693 --- /dev/null +++ b/tests/Validation/ValidationAnyOfRuleTest.php @@ -0,0 +1,376 @@ + $rule]; + $requiredIdRule = ['id' => ['required', $rule]]; + + $validator = new Validator(resolve('translator'), [ + 'id' => 'taylor@laravel.com', + ], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [], $requiredIdRule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => '3c8ff5cb-4bc1-457b-a477-1833c477b254', + ], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => null, + ], $idRule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => '', + ], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => '', + ], $requiredIdRule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => 'abc', + ], $idRule); + $this->assertFalse($validator->passes()); + } + + public function testBasicStringValidation() + { + $rule = Rule::anyOf([ + 'required|uuid:4', + 'required|email', + ]); + $idRule = ['id' => $rule]; + $requiredIdRule = ['id' => ['required', $rule]]; + + $validator = new Validator(resolve('translator'), [ + 'id' => 'test@example.com', + ], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [], $requiredIdRule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => '3c8ff5cb-4bc1-457b-a477-1833c477b254', + ], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => null, + ], $idRule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => '', + ], $idRule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => '', + ], $requiredIdRule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'id' => 'abc', + ], $idRule); + $this->assertFalse($validator->passes()); + } + + public function testTaggedUnionObjects() + { + $validator = new Validator(resolve('translator'), [ + 'data' => [ + 'type' => TaggedUnionDiscriminatorType::EMAIL->value, + 'email' => 'taylor@laravel.com', + ], + ], ['data' => Rule::anyOf($this->taggedUnionRules)]); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'data' => [ + 'type' => TaggedUnionDiscriminatorType::EMAIL->value, + 'email' => 'invalid-email', + ], + ], ['data' => Rule::anyOf($this->taggedUnionRules)]); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'data' => [ + 'type' => TaggedUnionDiscriminatorType::URL->value, + 'url' => 'http://laravel.com', + ], + ], ['data' => Rule::anyOf($this->taggedUnionRules)]); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'data' => [ + 'type' => TaggedUnionDiscriminatorType::URL->value, + 'url' => 'not-a-url', + ], + ], ['data' => Rule::anyOf($this->taggedUnionRules)]); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'data' => [ + 'type' => TaggedUnionDiscriminatorType::EMAIL->value, + 'url' => 'url-should-not-be-present-with-email-discriminator', + ], + ], ['data' => Rule::anyOf($this->taggedUnionRules)]); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'data' => [ + 'type' => 'doesnt-exist', + 'email' => 'taylor@laravel.com', + ], + ], ['data' => Rule::anyOf($this->taggedUnionRules)]); + $this->assertFalse($validator->passes()); + } + + public function testNestedValidation() + { + $validator = new Validator(resolve('translator'), [ + 'user' => [ + 'identifier' => 1, + 'properties' => [ + 'name' => 'Taylor', + 'surname' => 'Otwell', + ], + ], + ], $this->nestedRules); + $this->assertTrue($validator->passes()); + $validator->setRules($this->dotNotationNestedRules); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'user' => [ + 'identifier' => 'taylor@laravel.com', + 'properties' => [ + 'bio' => 'biography', + 'name' => 'Taylor', + 'surname' => 'Otwell', + ], + ], + ], $this->nestedRules); + $this->assertTrue($validator->passes()); + $validator->setRules($this->dotNotationNestedRules); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'user' => [ + 'identifier' => 'taylor@laravel.com', + 'properties' => [ + 'name' => null, + 'surname' => 'Otwell', + ], + ], + ], $this->nestedRules); + $this->assertFalse($validator->passes()); + $validator->setRules($this->dotNotationNestedRules); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'user' => [ + 'properties' => [ + 'name' => 'Taylor', + 'surname' => 'Otwell', + ], + ], + ], $this->nestedRules); + $this->assertFalse($validator->passes()); + $validator->setRules($this->dotNotationNestedRules); + $this->assertFalse($validator->passes()); + } + + public function testStarRuleSimple() + { + $rule = [ + 'persons.*.age' => ['required', Rule::anyOf([ + ['min:10'], + ['integer'], + ])], + ]; + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['age' => 12], + ['age' => 'foobar'], + ], + ], $rule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['age' => 'foobarbazqux'], + ['month' => 12], + ], + ], $rule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['age' => 12], + ['age' => 'foobarbazqux'], + ], + ], $rule); + $this->assertTrue($validator->passes()); + } + + public function testStarRuleNested() + { + $rule = [ + 'persons.*.birth' => ['required', Rule::anyOf([ + ['year' => 'required|integer'], + 'required|min:10', + ])], + ]; + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['age' => ['year' => 12]], + ], + ], $rule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['birth' => ['month' => 12]], + ], + ], $rule); + $this->assertFalse($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['birth' => ['year' => 12]], + ], + ], $rule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['birth' => 'foobarbazqux'], + ['birth' => [ + 'year' => 12, + ]], + ], + ], $rule); + $this->assertTrue($validator->passes()); + + $validator = new Validator(resolve('translator'), [ + 'persons' => [ + ['birth' => 'foobar'], + ['birth' => [ + 'year' => 12, + ]], + ], + ], $rule); + $this->assertFalse($validator->passes()); + } + + protected function setUpRuleSets() + { + $this->taggedUnionRules = [ + [ + 'type' => ['required', Rule::in([TaggedUnionDiscriminatorType::EMAIL])], + 'email' => ['required', 'email:rfc'], + ], + [ + 'type' => ['required', Rule::in([TaggedUnionDiscriminatorType::URL])], + 'url' => ['required', 'url:http,https'], + ], + ]; + + // Using AnyOf as nesting feature + $this->nestedRules = [ + 'user' => Rule::anyOf([ + [ + 'identifier' => ['required', Rule::anyOf([ + 'email:rfc', + 'integer', + ])], + 'properties' => ['required', Rule::anyOf([ + [ + 'bio' => 'nullable', + 'name' => 'required', + 'surname' => 'required', + ], + ])], + ], + ]), + ]; + + $this->dotNotationNestedRules = [ + 'user.identifier' => ['required', Rule::anyOf([ + 'email:rfc', + 'integer', + ])], + 'user.properties.bio' => 'nullable', + 'user.properties.name' => 'required', + 'user.properties.surname' => 'required', + ]; + } + + protected function setUp(): void + { + parent::setUp(); + + $container = Container::getInstance(); + $container->bind('translator', function () { + return new Translator( + new ArrayLoader, + 'en' + ); + }); + + Facade::setFacadeApplication($container); + (new ValidationServiceProvider($container))->register(); + + $this->setUpRuleSets(); + } + + protected function tearDown(): void + { + Container::setInstance(null); + Facade::clearResolvedInstances(); + Facade::setFacadeApplication(null); + } +} From ef733d727b66b2e9120dda9b4ac96a8272724c80 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:37:30 +0000 Subject: [PATCH 331/455] Update version to v12.8.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 159fb07bfee8..b24beb5b649c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.7.2'; + const VERSION = '12.8.0'; /** * The base path for the Laravel installation. From 454d1905050d4f62aba9e36f60f0e37215bc3f87 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:39:22 +0000 Subject: [PATCH 332/455] Update CHANGELOG --- CHANGELOG.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60e57ed14876..f8937ff7cecf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,26 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.7.2...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.8.0...12.x) + +## [v12.8.0](https://github.com/laravel/framework/compare/v12.7.2...v12.8.0) - 2025-04-08 + +* [12.x] only check for soft deletes once when mass-pruning by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55274 +* [12.x] Add createMany mass-assignment variants to `HasOneOrMany` relation by [@onlime](https://github.com/onlime) in https://github.com/laravel/framework/pull/55262 +* cosmetic: include is_array() case in match construct of getArrayableItems by [@epic-64](https://github.com/epic-64) in https://github.com/laravel/framework/pull/55275 +* Add tests for InvokeSerializedClosureCommand by [@Amirhf1](https://github.com/Amirhf1) in https://github.com/laravel/framework/pull/55281 +* [12.x] Temporarily prevents PHPUnit 12.1 by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55297 +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55306 +* Bump vite from 5.4.12 to 5.4.17 in /src/Illuminate/Foundation/resources/exceptions/renderer by [@dependabot](https://github.com/dependabot) in https://github.com/laravel/framework/pull/55301 +* [12.x] Test Improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55307 +* [12.x] add generics to array types for Schema Grammars by [@taka-oyama](https://github.com/taka-oyama) in https://github.com/laravel/framework/pull/55314 +* [12.x] fix missing nullable for Query/Grammar::compileInsertGetId by [@taka-oyama](https://github.com/taka-oyama) in https://github.com/laravel/framework/pull/55311 +* [12.x] Adds `fromJson()` to Collection by [@DarkGhostHunter](https://github.com/DarkGhostHunter) in https://github.com/laravel/framework/pull/55310 +* [12.x] Fix `illuminate/database` usage as standalone package by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55309 +* Correct array key in InteractsWithInput by [@AJenbo](https://github.com/AJenbo) in https://github.com/laravel/framework/pull/55287 +* [12.x] Fix support for adding custom observable events from traits by [@willrowe](https://github.com/willrowe) in https://github.com/laravel/framework/pull/55286 +* [12.x] Added Automatic Relation Loading (Eager Loading) Feature by [@litvinchuk](https://github.com/litvinchuk) in https://github.com/laravel/framework/pull/53655 +* [12.x] Modify PHPDoc for Collection::chunkWhile functions to support preserving keys by [@jsvdvis](https://github.com/jsvdvis) in https://github.com/laravel/framework/pull/55324 +* [12.x] Introduce Rule::anyOf() for Validating Against Multiple Rule Sets by [@brianferri](https://github.com/brianferri) in https://github.com/laravel/framework/pull/55191 ## [v12.7.2](https://github.com/laravel/framework/compare/v12.7.1...v12.7.2) - 2025-04-03 From 780154c6f0b640602c010c16a0bb872ff75e2fb7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 8 Apr 2025 14:15:37 -0500 Subject: [PATCH 333/455] rename method --- src/Illuminate/Http/Client/Factory.php | 2 +- tests/Http/HttpClientTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 0371a8add718..c38932ef33d5 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -186,7 +186,7 @@ public static function psr7Response($body = null, $status = 200, $headers = []) * @param array $headers * @return \Illuminate\Http\Client\RequestException */ - public static function requestException($body = null, $status = 200, $headers = []) + public static function failedRequest($body = null, $status = 200, $headers = []) { return new RequestException(new Response(static::psr7Response($body, $status, $headers))); } diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 7f3a17ed43c5..781026e2463a 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -2364,7 +2364,7 @@ public function testRequestsWillBeWaitingSleepMillisecondsReceivedInBackoffArray public function testRequestException() { - $requestException = $this->factory->requestException(['code' => 'not_found'], 404, ['X-RateLimit-Remaining' => 199]); + $requestException = $this->factory->failedRequest(['code' => 'not_found'], 404, ['X-RateLimit-Remaining' => 199]); $this->assertInstanceOf(RequestException::class, $requestException); $this->assertEqualsCanonicalizing(['code' => 'not_found'], $requestException->response->json()); From babdca124833aa0537681189e365b4c1c41c25d3 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:16:14 +0000 Subject: [PATCH 334/455] Update facade docblocks --- src/Illuminate/Support/Facades/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index 7be14c45f6b8..ecbcca5ba49c 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -11,7 +11,7 @@ * @method static \Illuminate\Http\Client\Factory globalOptions(\Closure|array $options) * @method static \GuzzleHttp\Promise\PromiseInterface response(array|string|null $body = null, int $status = 200, array $headers = []) * @method static \GuzzleHttp\Psr7\Response psr7Response(array|string|null $body = null, int $status = 200, array $headers = []) - * @method static \Illuminate\Http\Client\RequestException requestException(array|string|null $body = null, int $status = 200, array $headers = []) + * @method static \Illuminate\Http\Client\RequestException failedRequest(array|string|null $body = null, int $status = 200, array $headers = []) * @method static \GuzzleHttp\Promise\PromiseInterface failedConnection(string|null $message = null) * @method static \Illuminate\Http\Client\ResponseSequence sequence(array $responses = []) * @method static bool preventingStrayRequests() From d959635e27cf275871ac72adba26b2609b815e03 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 8 Apr 2025 14:48:06 -0500 Subject: [PATCH 335/455] improve resource collection discovery --- .../Traits/TransformsToResourceCollection.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php index 80fe2d803308..22143b356c48 100644 --- a/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php +++ b/src/Illuminate/Collections/Traits/TransformsToResourceCollection.php @@ -47,7 +47,17 @@ protected function guessResourceCollection(): ResourceCollection throw_unless(method_exists($className, 'guessResourceName'), LogicException::class, sprintf('Expected class %s to implement guessResourceName method. Make sure the model uses the TransformsToResource trait.', $className)); - foreach ($className::guessResourceName() as $resourceClass) { + $resourceClasses = $className::guessResourceName(); + + foreach ($resourceClasses as $resourceClass) { + $resourceCollection = $resourceClass.'Collection'; + + if (is_string($resourceCollection) && class_exists($resourceCollection)) { + return new $resourceCollection($this); + } + } + + foreach ($resourceClasses as $resourceClass) { if (is_string($resourceClass) && class_exists($resourceClass)) { return $resourceClass::collection($this); } From d1ea3566f6e0cad34834c6d18db0bf995438eb87 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:58:59 +0000 Subject: [PATCH 336/455] Update version to v12.8.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index b24beb5b649c..c5fb944a1cd2 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.8.0'; + const VERSION = '12.8.1'; /** * The base path for the Laravel installation. From 25025b859bd44c054de51e06ed9d1b0a76ef8cb7 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 8 Apr 2025 20:00:42 +0000 Subject: [PATCH 337/455] Update CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8937ff7cecf..b3b6ac8f599a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.8.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.8.1...12.x) + +## [v12.8.1](https://github.com/laravel/framework/compare/v12.8.0...v12.8.1) - 2025-04-08 ## [v12.8.0](https://github.com/laravel/framework/compare/v12.7.2...v12.8.0) - 2025-04-08 From 0cfb741aadaf6e53cc84b87f7d1e0a340ae73491 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Wed, 9 Apr 2025 05:01:33 +0200 Subject: [PATCH 338/455] Add types to ViewErrorBag (#55329) --- src/Illuminate/Support/ViewErrorBag.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/ViewErrorBag.php b/src/Illuminate/Support/ViewErrorBag.php index 2865fbfa4bdd..3d95bded960b 100644 --- a/src/Illuminate/Support/ViewErrorBag.php +++ b/src/Illuminate/Support/ViewErrorBag.php @@ -14,7 +14,7 @@ class ViewErrorBag implements Countable, Stringable /** * The array of the view error bags. * - * @var array + * @var array */ protected $bags = []; @@ -43,7 +43,7 @@ public function getBag($key) /** * Get all the bags. * - * @return array + * @return array */ public function getBags() { From 07419b45f28ddc1daef4445da93b9f005da96f07 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Wed, 9 Apr 2025 05:01:50 +0200 Subject: [PATCH 339/455] Add types to MessageBag (#55327) --- src/Illuminate/Support/MessageBag.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Support/MessageBag.php b/src/Illuminate/Support/MessageBag.php index 76172ae73cf7..24c5dadf544b 100755 --- a/src/Illuminate/Support/MessageBag.php +++ b/src/Illuminate/Support/MessageBag.php @@ -14,7 +14,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess /** * All of the registered messages. * - * @var array + * @var array> */ protected $messages = []; @@ -28,7 +28,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess /** * Create a new message bag instance. * - * @param array $messages + * @param array> $messages */ public function __construct(array $messages = []) { @@ -42,7 +42,7 @@ public function __construct(array $messages = []) /** * Get the keys present in the message bag. * - * @return array + * @return array */ public function keys() { @@ -95,7 +95,7 @@ protected function isUnique($key, $message) /** * Merge a new array of messages into the message bag. * - * @param \Illuminate\Contracts\Support\MessageProvider|array $messages + * @param \Illuminate\Contracts\Support\MessageProvider|array> $messages * @return $this */ public function merge($messages) @@ -193,7 +193,7 @@ public function first($key = null, $format = null) * * @param string $key * @param string|null $format - * @return array + * @return array|array> */ public function get($key, $format = null) { @@ -218,7 +218,7 @@ public function get($key, $format = null) * * @param string $key * @param string|null $format - * @return array + * @return array> */ protected function getMessagesForWildcardKey($key, $format) { @@ -234,7 +234,7 @@ protected function getMessagesForWildcardKey($key, $format) * Get all of the messages for every key in the message bag. * * @param string|null $format - * @return array + * @return array */ public function all($format = null) { @@ -276,10 +276,10 @@ public function forget($key) /** * Format an array of messages. * - * @param array $messages + * @param array $messages * @param string $format * @param string $messageKey - * @return array + * @return array */ protected function transform($messages, $format, $messageKey) { @@ -310,7 +310,7 @@ protected function checkFormat($format) /** * Get the raw messages in the message bag. * - * @return array + * @return array> */ public function messages() { @@ -320,7 +320,7 @@ public function messages() /** * Get the raw messages in the message bag. * - * @return array + * @return array> */ public function getMessages() { From 1f90f98d6e53a65d7fd524b5c4608a89409c15db Mon Sep 17 00:00:00 2001 From: Takayasu Oyama Date: Wed, 9 Apr 2025 12:04:09 +0900 Subject: [PATCH 340/455] [12.x] add generics to commonly used methods in Schema/Builder (#55330) * [12.x] add generics to array types in Schema/Builder * fix * fix * fix style --- .../Query/Processors/MySqlProcessor.php | 21 ++------------ .../Query/Processors/PostgresProcessor.php | 28 +++---------------- .../Database/Query/Processors/Processor.php | 28 +++++++++---------- .../Query/Processors/SQLiteProcessor.php | 22 ++------------- .../Query/Processors/SqlServerProcessor.php | 21 ++------------ src/Illuminate/Database/Schema/Builder.php | 22 +++++++-------- .../Database/Schema/SQLiteBuilder.php | 21 ++------------ 7 files changed, 41 insertions(+), 122 deletions(-) diff --git a/src/Illuminate/Database/Query/Processors/MySqlProcessor.php b/src/Illuminate/Database/Query/Processors/MySqlProcessor.php index 21b1fa97f9f7..331f2d8a688e 100644 --- a/src/Illuminate/Database/Query/Processors/MySqlProcessor.php +++ b/src/Illuminate/Database/Query/Processors/MySqlProcessor.php @@ -39,12 +39,7 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu return is_numeric($id) ? (int) $id : $id; } - /** - * Process the results of a columns query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processColumns($results) { return array_map(function ($result) { @@ -71,12 +66,7 @@ public function processColumns($results) }, $results); } - /** - * Process the results of an indexes query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processIndexes($results) { return array_map(function ($result) { @@ -92,12 +82,7 @@ public function processIndexes($results) }, $results); } - /** - * Process the results of a foreign keys query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processForeignKeys($results) { return array_map(function ($result) { diff --git a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php index bedf9a4213ef..871575a5c488 100755 --- a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php +++ b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php @@ -30,12 +30,7 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu return is_numeric($id) ? (int) $id : $id; } - /** - * Process the results of a types query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processTypes($results) { return array_map(function ($result) { @@ -79,12 +74,7 @@ public function processTypes($results) }, $results); } - /** - * Process the results of a columns query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processColumns($results) { return array_map(function ($result) { @@ -112,12 +102,7 @@ public function processColumns($results) }, $results); } - /** - * Process the results of an indexes query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processIndexes($results) { return array_map(function ($result) { @@ -133,12 +118,7 @@ public function processIndexes($results) }, $results); } - /** - * Process the results of a foreign keys query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processForeignKeys($results) { return array_map(function ($result) { diff --git a/src/Illuminate/Database/Query/Processors/Processor.php b/src/Illuminate/Database/Query/Processors/Processor.php index c2b1e8b782e9..46f692e49a58 100755 --- a/src/Illuminate/Database/Query/Processors/Processor.php +++ b/src/Illuminate/Database/Query/Processors/Processor.php @@ -39,8 +39,8 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu /** * Process the results of a schemas query. * - * @param array $results - * @return array + * @param list> $results + * @return list */ public function processSchemas($results) { @@ -58,8 +58,8 @@ public function processSchemas($results) /** * Process the results of a tables query. * - * @param array $results - * @return array + * @param list> $results + * @return list */ public function processTables($results) { @@ -81,8 +81,8 @@ public function processTables($results) /** * Process the results of a views query. * - * @param array $results - * @return array + * @param list> $results + * @return list */ public function processViews($results) { @@ -101,8 +101,8 @@ public function processViews($results) /** * Process the results of a types query. * - * @param array $results - * @return array + * @param list> $results + * @return list */ public function processTypes($results) { @@ -112,8 +112,8 @@ public function processTypes($results) /** * Process the results of a columns query. * - * @param array $results - * @return array + * @param list> $results + * @return list */ public function processColumns($results) { @@ -123,8 +123,8 @@ public function processColumns($results) /** * Process the results of an indexes query. * - * @param array $results - * @return array + * @param list> $results + * @return list, type: string, unique: bool, primary: bool}> */ public function processIndexes($results) { @@ -134,8 +134,8 @@ public function processIndexes($results) /** * Process the results of a foreign keys query. * - * @param array $results - * @return array + * @param list> $results + * @return list, foreign_schema: string, foreign_table: string, foreign_columns: list, on_update: string, on_delete: string}> */ public function processForeignKeys($results) { diff --git a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php index 7062c2cd1d7b..ed4916a7a54d 100644 --- a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php +++ b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php @@ -4,13 +4,7 @@ class SQLiteProcessor extends Processor { - /** - * Process the results of a columns query. - * - * @param array $results - * @param string $sql - * @return array - */ + /** @inheritDoc */ public function processColumns($results, $sql = '') { $hasPrimaryKey = array_sum(array_column($results, 'primary')) === 1; @@ -57,12 +51,7 @@ public function processColumns($results, $sql = '') }, $results); } - /** - * Process the results of an indexes query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processIndexes($results) { $primaryCount = 0; @@ -90,12 +79,7 @@ public function processIndexes($results) return $indexes; } - /** - * Process the results of a foreign keys query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processForeignKeys($results) { return array_map(function ($result) { diff --git a/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php b/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php index f5679552e22b..8d000c4579ac 100755 --- a/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php +++ b/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php @@ -55,12 +55,7 @@ protected function processInsertGetIdForOdbc(Connection $connection) return is_object($row) ? $row->insertid : $row['insertid']; } - /** - * Process the results of a columns query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processColumns($results) { return array_map(function ($result) { @@ -90,12 +85,7 @@ public function processColumns($results) }, $results); } - /** - * Process the results of an indexes query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processIndexes($results) { return array_map(function ($result) { @@ -111,12 +101,7 @@ public function processIndexes($results) }, $results); } - /** - * Process the results of a foreign keys query. - * - * @param array $results - * @return array - */ + /** @inheritDoc */ public function processForeignKeys($results) { return array_map(function ($result) { diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index b37dafbd9b19..109932a27d12 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -149,7 +149,7 @@ public function dropDatabaseIfExists($name) /** * Get the schemas that belong to the connection. * - * @return array + * @return list */ public function getSchemas() { @@ -208,7 +208,7 @@ public function hasView($view) * Get the tables that belong to the connection. * * @param string|string[]|null $schema - * @return array + * @return list */ public function getTables($schema = null) { @@ -222,7 +222,7 @@ public function getTables($schema = null) * * @param string|string[]|null $schema * @param bool $schemaQualified - * @return array + * @return list */ public function getTableListing($schema = null, $schemaQualified = true) { @@ -236,7 +236,7 @@ public function getTableListing($schema = null, $schemaQualified = true) * Get the views that belong to the connection. * * @param string|string[]|null $schema - * @return array + * @return list */ public function getViews($schema = null) { @@ -249,7 +249,7 @@ public function getViews($schema = null) * Get the user-defined types that belong to the connection. * * @param string|string[]|null $schema - * @return array + * @return list */ public function getTypes($schema = null) { @@ -276,7 +276,7 @@ public function hasColumn($table, $column) * Determine if the given table has given columns. * * @param string $table - * @param array $columns + * @param array $columns * @return bool */ public function hasColumns($table, array $columns) @@ -347,7 +347,7 @@ public function getColumnType($table, $column, $fullDefinition = false) * Get the column listing for a given table. * * @param string $table - * @return array + * @return list */ public function getColumnListing($table) { @@ -358,7 +358,7 @@ public function getColumnListing($table) * Get the columns for a given table. * * @param string $table - * @return array + * @return list */ public function getColumns($table) { @@ -377,7 +377,7 @@ public function getColumns($table) * Get the indexes for a given table. * * @param string $table - * @return array + * @return list, type: string, unique: bool, primary: bool}> */ public function getIndexes($table) { @@ -396,7 +396,7 @@ public function getIndexes($table) * Get the names of the indexes for a given table. * * @param string $table - * @return array + * @return list */ public function getIndexListing($table) { @@ -506,7 +506,7 @@ public function dropIfExists($table) * Drop columns from a table schema. * * @param string $table - * @param string|array $columns + * @param string|array $columns * @return void */ public function dropColumns($table, $columns) diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index a473768414d2..040f1623f8a1 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -30,12 +30,7 @@ public function dropDatabaseIfExists($name) return ! File::exists($name) || File::delete($name); } - /** - * Get the tables that belong to the connection. - * - * @param string|string[]|null $schema - * @return array - */ + /** @inheritDoc */ public function getTables($schema = null) { try { @@ -65,12 +60,7 @@ public function getTables($schema = null) ); } - /** - * Get the views that belong to the connection. - * - * @param string|string[]|null $schema - * @return array - */ + /** @inheritDoc */ public function getViews($schema = null) { $schema ??= array_column($this->getSchemas(), 'name'); @@ -86,12 +76,7 @@ public function getViews($schema = null) return $this->connection->getPostProcessor()->processViews($views); } - /** - * Get the columns for a given table. - * - * @param string $table - * @return array - */ + /** @inheritDoc */ public function getColumns($table) { [$schema, $table] = $this->parseSchemaAndTable($table); From e8e0c3218ff822b5b6719927c9b5ad5cd8aeb0d8 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Tue, 8 Apr 2025 23:05:29 -0400 Subject: [PATCH 341/455] Return frozen time for easier testing (#55323) * Return frozen time for easier testing * Ensure "test now" is cleared --- .../Testing/Concerns/InteractsWithTime.php | 8 +- .../FoundationInteractsWithTimeTest.php | 78 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tests/Foundation/FoundationInteractsWithTimeTest.php diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php index b431c9b889cf..4eb10714b1e1 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php @@ -15,7 +15,9 @@ trait InteractsWithTime */ public function freezeTime($callback = null) { - return $this->travelTo(Carbon::now(), $callback); + $result = $this->travelTo($now = Carbon::now(), $callback); + + return is_null($callback) ? $now : $result; } /** @@ -26,7 +28,9 @@ public function freezeTime($callback = null) */ public function freezeSecond($callback = null) { - return $this->travelTo(Carbon::now()->startOfSecond(), $callback); + $result = $this->travelTo($now = Carbon::now()->startOfSecond(), $callback); + + return is_null($callback) ? $now : $result; } /** diff --git a/tests/Foundation/FoundationInteractsWithTimeTest.php b/tests/Foundation/FoundationInteractsWithTimeTest.php new file mode 100644 index 000000000000..ce2435bea527 --- /dev/null +++ b/tests/Foundation/FoundationInteractsWithTimeTest.php @@ -0,0 +1,78 @@ +freezeTime(); + + $this->assertTrue(Carbon::hasTestNow()); + $this->assertInstanceOf(\DateTimeInterface::class, $actual); + $this->assertTrue(Carbon::getTestNow()->eq($actual)); + } + + public function testFreezeTimeReturnsCallbackResult() + { + $actual = $this->freezeTime(function () { + return 12345; + }); + + $this->assertSame(12345, $actual); + $this->assertFalse(Carbon::hasTestNow()); + } + + public function testFreezeTimeReturnsCallbackResultEvenWhenNull() + { + $actual = $this->freezeTime(function () { + return null; + }); + + $this->assertNull($actual); + $this->assertFalse(Carbon::hasTestNow()); + } + + public function testFreezeSecondReturnsFrozenTime() + { + $actual = $this->freezeSecond(); + + $this->assertTrue(Carbon::hasTestNow()); + $this->assertInstanceOf(\DateTimeInterface::class, $actual); + $this->assertTrue(Carbon::getTestNow()->eq($actual)); + $this->assertSame(0, $actual->milliseconds); + } + + public function testFreezeSecondReturnsCallbackResult() + { + $actual = $this->freezeSecond(function () { + return 12345; + }); + + $this->assertSame(12345, $actual); + $this->assertFalse(Carbon::hasTestNow()); + } + + public function testFreezeSecondReturnsCallbackResultEvenWhenNull() + { + $actual = $this->freezeSecond(function () { + return null; + }); + + $this->assertNull($actual); + $this->assertFalse(Carbon::hasTestNow()); + } +} From 1e37ba62a087e0e2f0c67c6a4375a26a33a0e30c Mon Sep 17 00:00:00 2001 From: Saif <88875730+msaifmfz@users.noreply.github.com> Date: Wed, 9 Apr 2025 12:08:43 +0900 Subject: [PATCH 342/455] Update DetectsLostConnections.php (#55331) --- src/Illuminate/Database/DetectsLostConnections.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php index f489b28409dc..72b5a043288e 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -65,6 +65,7 @@ protected function causedByLostConnection(Throwable $e) 'SSL: Handshake timed out', 'SSL error: sslv3 alert unexpected message', 'unrecognized SSL error code:', + 'SQLSTATE[HY000] [1045] Access denied for user', 'SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it', 'SQLSTATE[HY000] [2002] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond', 'SQLSTATE[HY000] [2002] Network is unreachable', From b562df0b1e028cb6e1e02952900e494c5556dd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20K=C3=A4mmerling?= Date: Wed, 9 Apr 2025 16:09:09 +0200 Subject: [PATCH 343/455] Rename test method of failedRequest() (#55332) This renames the test name to be in line with the function name, that was renamed in https://github.com/laravel/framework/commit/780154c6f0b640602c010c16a0bb872ff75e2fb7. I just noticed it by looking through the resent git history. --- tests/Http/HttpClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 781026e2463a..8f0309329675 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -2362,7 +2362,7 @@ public function testRequestsWillBeWaitingSleepMillisecondsReceivedInBackoffArray ]); } - public function testRequestException() + public function testFailedRequest() { $requestException = $this->factory->failedRequest(['code' => 'not_found'], 404, ['X-RateLimit-Remaining' => 199]); From 7d65ce022c028d8d8f74009ee948bf97d6be8fc3 Mon Sep 17 00:00:00 2001 From: Davey Shafik Date: Wed, 9 Apr 2025 07:14:56 -0700 Subject: [PATCH 344/455] feat: Add a callback to be called on transaction failure (#55338) * feat: Add a callback to be called on transaction failure * formatting --------- Co-authored-by: Taylor Otwell --- .../Database/Concerns/ManagesTransactions.php | 12 +++++-- .../Database/ConnectionInterface.php | 3 +- .../Database/SqlServerConnection.php | 9 +++-- .../Database/DatabaseTransactionsTest.php | 36 +++++++++++++++++++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index 23bc60434e49..609095bee849 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -16,11 +16,12 @@ trait ManagesTransactions * * @param (\Closure(static): TReturn) $callback * @param int $attempts + * @param Closure|null $onFailure * @return TReturn * * @throws \Throwable */ - public function transaction(Closure $callback, $attempts = 1) + public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailure = null) { for ($currentAttempt = 1; $currentAttempt <= $attempts; $currentAttempt++) { $this->beginTransaction(); @@ -37,7 +38,7 @@ public function transaction(Closure $callback, $attempts = 1) // exception back out, and let the developer handle an uncaught exception. catch (Throwable $e) { $this->handleTransactionException( - $e, $currentAttempt, $attempts + $e, $currentAttempt, $attempts, $onFailure ); continue; @@ -78,11 +79,12 @@ public function transaction(Closure $callback, $attempts = 1) * @param \Throwable $e * @param int $currentAttempt * @param int $maxAttempts + * @param Closure|null $onFailure * @return void * * @throws \Throwable */ - protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts) + protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts, ?Closure $onFailure) { // On a deadlock, MySQL rolls back the entire transaction so we can't just // retry the query. We have to throw this exception all the way out and @@ -108,6 +110,10 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma return; } + if ($onFailure !== null) { + $onFailure($e); + } + throw $e; } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 288adb4206e3..322a59576724 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -131,11 +131,12 @@ public function prepareBindings(array $bindings); * * @param \Closure $callback * @param int $attempts + * @param Closure|null $onFailure * @return mixed * * @throws \Throwable */ - public function transaction(Closure $callback, $attempts = 1); + public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailure = null); /** * Start a new database transaction. diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index 1e6fe52bfe16..bddf82f02a70 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -27,15 +27,16 @@ public function getDriverTitle() * * @param \Closure $callback * @param int $attempts + * @param Closure|null $onFailure * @return mixed * * @throws \Throwable */ - public function transaction(Closure $callback, $attempts = 1) + public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailure = null) { for ($a = 1; $a <= $attempts; $a++) { if ($this->getDriverName() === 'sqlsrv') { - return parent::transaction($callback, $attempts); + return parent::transaction($callback, $attempts, $onFailure); } $this->getPdo()->exec('BEGIN TRAN'); @@ -55,6 +56,10 @@ public function transaction(Closure $callback, $attempts = 1) catch (Throwable $e) { $this->getPdo()->exec('ROLLBACK TRAN'); + if ($a === $attempts && $onFailure !== null) { + $onFailure($e); + } + throw $e; } diff --git a/tests/Integration/Database/DatabaseTransactionsTest.php b/tests/Integration/Database/DatabaseTransactionsTest.php index 58894d01ae5e..35051f528b20 100644 --- a/tests/Integration/Database/DatabaseTransactionsTest.php +++ b/tests/Integration/Database/DatabaseTransactionsTest.php @@ -105,6 +105,42 @@ public function testTransactionsDoNotAffectDifferentConnections() $this->assertTrue($secondObject->ran); $this->assertFalse($thirdObject->ran); } + + public function testOnErrorCallbackIsCalled() + { + $executed = false; + try { + DB::transaction(function () { + throw new \Exception; + }, 1, function () use (&$executed) { + $executed = true; + }); + } catch (\Throwable) { + // Ignore the exception + } + + $this->assertTrue($executed); + } + + public function testOnErrorCallbackIsCalledWithDeadlockRetry() + { + $executed = false; + $attempts = 0; + + try { + DB::transaction(function () use (&$attempts) { + $attempts += 1; + throw new \Exception('has been chosen as the deadlock victim'); + }, 3, function () use (&$executed) { + $executed = true; + }); + } catch (\Throwable) { + // Ignore the exception + } + + $this->assertSame(3, $attempts); + $this->assertTrue($executed); + } } class TestObjectForTransactions From 55ab0c18cce8fb224f5859eb5eb6fd75705b4af7 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 9 Apr 2025 14:15:28 +0000 Subject: [PATCH 345/455] Apply fixes from StyleCI --- src/Illuminate/Database/Concerns/ManagesTransactions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index 609095bee849..f3ec8a42df69 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -79,7 +79,7 @@ public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailur * @param \Throwable $e * @param int $currentAttempt * @param int $maxAttempts - * @param Closure|null $onFailure + * @param Closure|null $onFailure * @return void * * @throws \Throwable From db293d9fd937845c416aa6c8dae1434616a312eb Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:16:16 +0000 Subject: [PATCH 346/455] Update facade docblocks --- src/Illuminate/Support/Facades/DB.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index f1c41bc0abb4..339653c59aea 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -108,7 +108,7 @@ * @method static string getServerVersion() * @method static void resolverFor(string $driver, \Closure $callback) * @method static \Closure|null getResolver(string $driver) - * @method static mixed transaction(\Closure $callback, int $attempts = 1) + * @method static mixed transaction(\Closure $callback, int $attempts = 1, \Closure|null $onFailure = null) * @method static void beginTransaction() * @method static void commit() * @method static void rollBack(int|null $toLevel = null) From 58862a89c0883e83721b19d44e8971c34daf4efd Mon Sep 17 00:00:00 2001 From: Serhii Litvinchuk Date: Wed, 9 Apr 2025 18:56:34 +0300 Subject: [PATCH 347/455] [12.x] Add withRelationshipAutoloading method to model (#55344) * Add withRelationshipAutoloading method to model * Update HasRelationships.php --------- Co-authored-by: Taylor Otwell --- .../Eloquent/Concerns/HasRelationships.php | 12 +++++++++ .../EloquentModelRelationAutoloadTest.php | 25 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 2f30de88a2b1..02ce0543b725 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -1117,6 +1117,18 @@ public function setRelations(array $relations) return $this; } + /** + * Enable relationship autoloading for this model. + * + * @return $this + */ + public function withRelationshipAutoloading() + { + $this->newCollection([$this])->withRelationshipAutoloading(); + + return $this; + } + /** * Duplicate the instance and unset all the loaded relations. * diff --git a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php index 8f80c5bb5149..35bc49b53c54 100644 --- a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php +++ b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php @@ -32,7 +32,7 @@ protected function afterRefreshingDatabase() }); } - public function testRelationAutoload() + public function testRelationAutoloadForCollection() { $post1 = Post::create(); $comment1 = $post1->comments()->create(['parent_id' => null]); @@ -63,6 +63,29 @@ public function testRelationAutoload() $this->assertTrue($posts[0]->comments[0]->relationLoaded('likes')); } + public function testRelationAutoloadForSingleModel() + { + $post = Post::create(); + $comment1 = $post->comments()->create(['parent_id' => null]); + $comment2 = $post->comments()->create(['parent_id' => $comment1->id]); + $comment2->likes()->create(); + $comment2->likes()->create(); + + DB::enableQueryLog(); + + $likes = []; + + $post->withRelationshipAutoloading(); + + foreach ($post->comments as $comment) { + $likes = array_merge($likes, $comment->likes->all()); + } + + $this->assertCount(2, DB::getQueryLog()); + $this->assertCount(2, $likes); + $this->assertTrue($post->comments[0]->relationLoaded('likes')); + } + public function testRelationAutoloadVariousNestedMorphRelations() { tap(Post::create(), function ($post) { From c4bc12672e1df771a65c7002aea9d93c88c83753 Mon Sep 17 00:00:00 2001 From: Chris Lloyd Date: Wed, 9 Apr 2025 22:27:11 +0100 Subject: [PATCH 348/455] Allow middleware exceptions to be retried (#55343) --- src/Illuminate/Http/Client/PendingRequest.php | 2 +- tests/Http/HttpClientTest.php | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 08d64d8e4ad0..117319de5029 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -947,7 +947,7 @@ public function send(string $method, string $url, array $options = []) throw $exception; } }, $this->retryDelay ?? 100, function ($exception) use (&$shouldRetry) { - $result = $shouldRetry ?? ($this->retryWhenCallback ? call_user_func($this->retryWhenCallback, $exception, $this, $this->request->toPsrRequest()->getMethod()) : true); + $result = $shouldRetry ?? ($this->retryWhenCallback ? call_user_func($this->retryWhenCallback, $exception, $this, $this->request?->toPsrRequest()->getMethod()) : true); $shouldRetry = null; diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 8f0309329675..56ee25932b0f 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -2334,6 +2334,22 @@ public function testExceptionThrownInRetryCallbackIsReturnedWithoutRetryingInPoo $this->factory->assertSentCount(1); } + public function testExceptionThrowInMiddlewareAllowsRetry() + { + $middleware = Middleware::mapRequest(function (RequestInterface $request) { + throw new RuntimeException; + }); + + $this->expectException(RuntimeException::class); + + $this->factory->fake(function (Request $request) { + return $this->factory->response('Fake'); + })->withMiddleware($middleware) + ->retry(3, 1, function (Exception $exception, PendingRequest $request) { + return true; + })->post('https://example.com'); + } + public function testRequestsWillBeWaitingSleepMillisecondsReceivedInBackoffArray() { Sleep::fake(); From f70f69b36e818bfba3f314ab90d8c1a7ab69ec4b Mon Sep 17 00:00:00 2001 From: Serhii Litvinchuk Date: Thu, 10 Apr 2025 04:42:06 +0300 Subject: [PATCH 349/455] [12.x] Fix Closure serialization error in automatic relation loading (#55345) * Fix Serialization of 'Closure' is not allowed error in automatic relation loading * Fix tests --- src/Illuminate/Database/Eloquent/Model.php | 5 ++++ .../EloquentModelRelationAutoloadTest.php | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index b159f1febc9d..be5a2b3f1dbe 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -2501,6 +2501,7 @@ public function __sleep() $this->classCastCache = []; $this->attributeCastCache = []; + $this->relationAutoloadCallback = null; return array_keys(get_object_vars($this)); } @@ -2515,5 +2516,9 @@ public function __wakeup() $this->bootIfNotBooted(); $this->initializeTraits(); + + if (static::isAutomaticallyEagerLoadingRelationships()) { + $this->withRelationshipAutoloading(); + } } } diff --git a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php index 35bc49b53c54..a3f8a5f882f7 100644 --- a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php +++ b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php @@ -86,6 +86,31 @@ public function testRelationAutoloadForSingleModel() $this->assertTrue($post->comments[0]->relationLoaded('likes')); } + public function testRelationAutoloadWithSerialization() + { + Model::automaticallyEagerLoadRelationships(); + + $post = Post::create(); + $comment1 = $post->comments()->create(['parent_id' => null]); + $comment2 = $post->comments()->create(['parent_id' => $comment1->id]); + $comment2->likes()->create(); + + DB::enableQueryLog(); + + $likes = []; + + $post = serialize($post); + $post = unserialize($post); + + foreach ($post->comments as $comment) { + $likes = array_merge($likes, $comment->likes->all()); + } + + $this->assertCount(2, DB::getQueryLog()); + + Model::automaticallyEagerLoadRelationships(false); + } + public function testRelationAutoloadVariousNestedMorphRelations() { tap(Post::create(), function ($post) { From 437c4604a3e687c1fc75eb234337786044e0ba12 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Thu, 10 Apr 2025 18:29:27 +0330 Subject: [PATCH 350/455] Add test for Unique validation rule with WhereIn constraints (#55351) * Add database connection setup for ValidationUniqueRuleTest This commit adds proper database configuration for ValidationUniqueRuleTest class by: 1. Setting up an in-memory SQLite database 2. Creating the necessary 'users' table schema for testing 3. Adding connection helper methods for database operations * Add test for Unique rule with combined whereIn and whereNotIn constraints This commit adds a test that verifies the behavior of the Unique validation rule when using both whereIn and whereNotIn constraints together. The test demonstrates that: 1. The whereIn constraint limits validation to only consider records matching specified values ('admin', 'moderator', 'editor') 2. The whereNotIn constraint further excludes records with specific values ('editor') from validation 3. Records outside these constraints are ignored when checking uniqueness 4. Non-existent values are always considered unique * Fix unique validation test by using existing model stubs This commit refactors the `testItValidatesUniqueRuleWithWhereInAndWhereNotIn` test to use the existing `EloquentModelStub` instead of a custom `User` model, resolving name conflicts with other test files in the framework. * fix style --- tests/Validation/ValidationUniqueRuleTest.php | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/Validation/ValidationUniqueRuleTest.php b/tests/Validation/ValidationUniqueRuleTest.php index 740d829927a3..69a4d0933088 100644 --- a/tests/Validation/ValidationUniqueRuleTest.php +++ b/tests/Validation/ValidationUniqueRuleTest.php @@ -2,12 +2,30 @@ namespace Illuminate\Tests\Validation; +use Illuminate\Database\Capsule\Manager as DB; +use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Model; +use Illuminate\Translation\ArrayLoader; +use Illuminate\Translation\Translator; +use Illuminate\Validation\DatabasePresenceVerifier; use Illuminate\Validation\Rules\Unique; +use Illuminate\Validation\Validator; use PHPUnit\Framework\TestCase; class ValidationUniqueRuleTest extends TestCase { + protected function setUp(): void + { + $db = new DB; + $db->addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $this->createSchema(); + } + public function testItCorrectlyFormatsAStringVersionOfTheRule() { $rule = new Unique('table'); @@ -129,6 +147,10 @@ public function testItHandlesWhereWithSpecialValues() $rule->where('foo', null); $this->assertSame('unique:table,column,NULL,id,foo,"NULL"', (string) $rule); + $rule = new Unique('table', 'column'); + $rule->whereNot('foo', 'bar'); + $this->assertSame('unique:table,column,NULL,id,foo,"!bar"', (string) $rule); + $rule = new Unique('table', 'column'); $rule->whereNull('foo'); $this->assertSame('unique:table,column,NULL,id,foo,"NULL"', (string) $rule); @@ -141,6 +163,58 @@ public function testItHandlesWhereWithSpecialValues() $rule->where('foo', 0); $this->assertSame('unique:table,column,NULL,id,foo,"0"', (string) $rule); } + + public function testItValidatesUniqueRuleWithWhereInAndWhereNotIn() + { + EloquentModelStub::create(['id_column' => 1, 'type' => 'admin']); + EloquentModelStub::create(['id_column' => 2, 'type' => 'moderator']); + EloquentModelStub::create(['id_column' => 3, 'type' => 'editor']); + EloquentModelStub::create(['id_column' => 4, 'type' => 'user']); + + $rule = new Unique(table: 'table', column: 'id_column'); + $rule->whereIn(column: 'type', values: ['admin', 'moderator', 'editor']) + ->whereNotIn(column: 'type', values: ['editor']); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, [], ['id_column' => $rule]); + $v->setPresenceVerifier(new DatabasePresenceVerifier(Model::getConnectionResolver())); + + $v->setData(['id_column' => 1]); + $this->assertFalse($v->passes()); + + $v->setData(['id_column' => 2]); + $this->assertFalse($v->passes()); + + $v->setData(['id_column' => 3]); + $this->assertTrue($v->passes()); + + $v->setData(['id_column' => 4]); + $this->assertTrue($v->passes()); + + $v->setData(['id_column' => 5]); + $this->assertTrue($v->passes()); + } + + protected function createSchema(): void + { + $this->connection()->getSchemaBuilder()->create('table', function ($table) { + $table->unsignedInteger('id_column'); + $table->string('type'); + $table->timestamps(); + }); + } + + protected function connection(): ConnectionInterface + { + return Model::getConnectionResolver()->connection(); + } + + protected function getIlluminateArrayTranslator(): Translator + { + return new Translator( + new ArrayLoader, locale: 'en' + ); + } } class EloquentModelStub extends Model From 228944833746a40f9a0e38cd2e4060f75830cd93 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:20:16 +0330 Subject: [PATCH 351/455] Add @throws in doc-blocks (#55361) --- src/Illuminate/Routing/Route.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 7dd19b552ddc..355d18b0e058 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -271,6 +271,8 @@ protected function runController() * Get the controller instance for the route. * * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function getController() { @@ -1274,6 +1276,8 @@ public function waitsFor() * Get the dispatcher for the route's controller. * * @return \Illuminate\Routing\Contracts\ControllerDispatcher + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function controllerDispatcher() { From 8d073fb294759f963989d1b4f2ba6b20813c7669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derian=20C=C3=B3rdoba?= <113069371+derian-all-win-software@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:50:46 -0600 Subject: [PATCH 352/455] updating doc (#55363) --- src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 02ce0543b725..06f61e86c546 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -162,7 +162,7 @@ protected function invokeRelationAutoloadCallbackFor($key, $tuples) * Propagate the relationship autoloader callback to the given related models. * * @param string $key - * @param mixed $values + * @param mixed $models * @param mixed $context * @return void */ From 64fb35b76150432a1da1c1535132c253ea01dab3 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 11 Apr 2025 11:29:19 -0300 Subject: [PATCH 353/455] Establish connection first, before set the options (#55370) --- src/Illuminate/Redis/Connectors/PhpRedisConnector.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php index bddc0f11044f..df5512c9b986 100644 --- a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php +++ b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php @@ -85,6 +85,8 @@ protected function createClient(array $config) ); } + $this->establishConnection($client, $config); + if (array_key_exists('max_retries', $config)) { $client->setOption(Redis::OPT_MAX_RETRIES, $config['max_retries']); } @@ -101,8 +103,6 @@ protected function createClient(array $config) $client->setOption(Redis::OPT_BACKOFF_CAP, $config['backoff_cap']); } - $this->establishConnection($client, $config); - if (! empty($config['password'])) { if (isset($config['username']) && $config['username'] !== '' && is_string($config['password'])) { $client->auth([$config['username'], $config['password']]); From b8f4f0dea546b399e4bb3baece24487bb1499180 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Fri, 11 Apr 2025 17:28:09 +0200 Subject: [PATCH 354/455] [12.x] Fix translation FileLoader overrides with a missing key (#55342) * failing test * fix multiple lang namespace override with a missing key in the last --- src/Illuminate/Translation/FileLoader.php | 8 ++++---- tests/Translation/TranslationFileLoaderTest.php | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Translation/FileLoader.php b/src/Illuminate/Translation/FileLoader.php index 3ebbfcc1264b..e30fdf7c413e 100755 --- a/src/Illuminate/Translation/FileLoader.php +++ b/src/Illuminate/Translation/FileLoader.php @@ -102,15 +102,15 @@ protected function loadNamespaced($locale, $group, $namespace) protected function loadNamespaceOverrides(array $lines, $locale, $group, $namespace) { return (new Collection($this->paths)) - ->reduce(function ($output, $path) use ($lines, $locale, $group, $namespace) { + ->reduce(function ($output, $path) use ($locale, $group, $namespace) { $file = "{$path}/vendor/{$namespace}/{$locale}/{$group}.php"; if ($this->files->exists($file)) { - $lines = array_replace_recursive($lines, $this->files->getRequire($file)); + $output = array_replace_recursive($output, $this->files->getRequire($file)); } - return $lines; - }, []); + return $output; + }, $lines); } /** diff --git a/tests/Translation/TranslationFileLoaderTest.php b/tests/Translation/TranslationFileLoaderTest.php index b7e74f18bfaa..dd386932f79d 100755 --- a/tests/Translation/TranslationFileLoaderTest.php +++ b/tests/Translation/TranslationFileLoaderTest.php @@ -146,6 +146,20 @@ public function testLoadMethodWithNamespacesProperlyCallsLoaderAndLoadsLocalOver $this->assertEquals(['foo' => 'override-2', 'baz' => 'boom-2'], $loader->load('en', 'foo', 'namespace')); } + public function testLoadMethodWithNamespacesProperlyCallsLoaderAndLoadsLocalOverridesWithMultiplePathsWithMissingKey() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), [__DIR__, __DIR__.'/second']); + $files->shouldReceive('exists')->once()->with('test-namespace-dir/en/foo.php')->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/vendor/namespace/en/foo.php')->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/second/vendor/namespace/en/foo.php')->andReturn(true); + $files->shouldReceive('getRequire')->once()->with('test-namespace-dir/en/foo.php')->andReturn(['foo' => 'bar']); + $files->shouldReceive('getRequire')->once()->with(__DIR__.'/vendor/namespace/en/foo.php')->andReturn(['foo' => 'override', 'baz' => 'boom']); + $files->shouldReceive('getRequire')->once()->with(__DIR__.'/second/vendor/namespace/en/foo.php')->andReturn(['baz' => 'boom-2']); + $loader->addNamespace('namespace', 'test-namespace-dir'); + + $this->assertEquals(['foo' => 'override', 'baz' => 'boom-2'], $loader->load('en', 'foo', 'namespace')); + } + public function testEmptyArraysReturnedWhenFilesDontExist() { $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); From 99e1ceb6044db988b904f2940d9510299cbe9d1d Mon Sep 17 00:00:00 2001 From: Amir Alizadeh Date: Fri, 11 Apr 2025 19:44:05 +0330 Subject: [PATCH 355/455] [12.x] Fix pivot model events not working when using the `withPivotValue` (#55280) * Fix pivot model events not working when using the `withPivotValue` * formatting --------- Co-authored-by: Taylor Otwell --- .../Concerns/InteractsWithPivotTable.php | 72 +++++++++++-------- .../Database/EloquentPivotEventsTest.php | 35 +++++++++ 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 015554ed767a..454d79379195 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -207,10 +207,7 @@ protected function attachNew(array $records, array $current, $touch = true) */ public function updateExistingPivot($id, array $attributes, $touch = true) { - if ($this->using && - empty($this->pivotWheres) && - empty($this->pivotWhereIns) && - empty($this->pivotWhereNulls)) { + if ($this->using) { return $this->updateExistingPivotUsingCustomClass($id, $attributes, $touch); } @@ -218,7 +215,7 @@ public function updateExistingPivot($id, array $attributes, $touch = true) $attributes = $this->addTimestampsToAttachment($attributes, true); } - $updated = $this->newPivotStatementForId($this->parseId($id))->update( + $updated = $this->newPivotStatementForId($id)->update( $this->castAttributes($attributes) ); @@ -239,10 +236,7 @@ public function updateExistingPivot($id, array $attributes, $touch = true) */ protected function updateExistingPivotUsingCustomClass($id, array $attributes, $touch) { - $pivot = $this->getCurrentlyAttachedPivots() - ->where($this->foreignPivotKey, $this->parent->{$this->parentKey}) - ->where($this->relatedPivotKey, $this->parseId($id)) - ->first(); + $pivot = $this->getCurrentlyAttachedPivotsForIds($id)->first(); $updated = $pivot ? $pivot->fill($attributes)->isDirty() : false; @@ -435,11 +429,7 @@ public function hasPivotColumn($column) */ public function detach($ids = null, $touch = true) { - if ($this->using && - ! empty($ids) && - empty($this->pivotWheres) && - empty($this->pivotWhereIns) && - empty($this->pivotWhereNulls)) { + if ($this->using) { $results = $this->detachUsingCustomClass($ids); } else { $query = $this->newPivotQuery(); @@ -480,11 +470,21 @@ protected function detachUsingCustomClass($ids) { $results = 0; - foreach ($this->parseIds($ids) as $id) { - $results += $this->newPivot([ - $this->foreignPivotKey => $this->parent->{$this->parentKey}, - $this->relatedPivotKey => $id, - ], true)->delete(); + if (! empty($this->pivotWheres) || + ! empty($this->pivotWhereIns) || + ! empty($this->pivotWhereNulls)) { + $records = $this->getCurrentlyAttachedPivotsForIds($ids); + + foreach ($records as $record) { + $results += $record->delete(); + } + } else { + foreach ($this->parseIds($ids) as $id) { + $results += $this->newPivot([ + $this->foreignPivotKey => $this->parent->{$this->parentKey}, + $this->relatedPivotKey => $id, + ], true)->delete(); + } } return $results; @@ -497,15 +497,31 @@ protected function detachUsingCustomClass($ids) */ protected function getCurrentlyAttachedPivots() { - return $this->newPivotQuery()->get()->map(function ($record) { - $class = $this->using ?: Pivot::class; - - $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true); + return $this->getCurrentlyAttachedPivotsForIds(); + } - return $pivot - ->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) - ->setRelatedModel($this->related); - }); + /** + * Get the pivot models that are currently attached, filtered by related model keys. + * + * @param mixed $ids + * @return \Illuminate\Support\Collection + */ + protected function getCurrentlyAttachedPivotsForIds($ids = null) + { + return $this->newPivotQuery() + ->when(! is_null($ids), fn ($query) => $query->whereIn( + $this->getQualifiedRelatedPivotKeyName(), $this->parseIds($ids) + )) + ->get() + ->map(function ($record) { + $class = $this->using ?: Pivot::class; + + $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true); + + return $pivot + ->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) + ->setRelatedModel($this->related); + }); } /** @@ -557,7 +573,7 @@ public function newPivotStatement() */ public function newPivotStatementForId($id) { - return $this->newPivotQuery()->whereIn($this->relatedPivotKey, $this->parseIds($id)); + return $this->newPivotQuery()->whereIn($this->getQualifiedRelatedPivotKeyName(), $this->parseIds($id)); } /** diff --git a/tests/Integration/Database/EloquentPivotEventsTest.php b/tests/Integration/Database/EloquentPivotEventsTest.php index 7a9962982595..e94fe5cce005 100644 --- a/tests/Integration/Database/EloquentPivotEventsTest.php +++ b/tests/Integration/Database/EloquentPivotEventsTest.php @@ -74,6 +74,34 @@ public function testPivotWillTriggerEventsToBeFired() $this->assertEquals(['deleting', 'deleted'], PivotEventsTestCollaborator::$eventsCalled); } + public function testPivotWithPivotValueWillTriggerEventsToBeFired() + { + $user = PivotEventsTestUser::forceCreate(['email' => 'taylor@laravel.com']); + $user2 = PivotEventsTestUser::forceCreate(['email' => 'ralph@ralphschindler.com']); + $project = PivotEventsTestProject::forceCreate(['name' => 'Test Project']); + + $project->managers()->attach($user); + $this->assertEquals(['saving', 'creating', 'created', 'saved'], PivotEventsTestCollaborator::$eventsCalled); + $project->managers()->attach($user2); + + PivotEventsTestCollaborator::$eventsCalled = []; + $project->managers()->updateExistingPivot($user->id, ['permissions' => ['foo', 'bar']]); + $this->assertEquals(['saving', 'updating', 'updated', 'saved'], PivotEventsTestCollaborator::$eventsCalled); + $project->managers()->detach($user2); + + PivotEventsTestCollaborator::$eventsCalled = []; + $project->managers()->sync([$user2->id]); + $this->assertEquals(['deleting', 'deleted', 'saving', 'creating', 'created', 'saved'], PivotEventsTestCollaborator::$eventsCalled); + + PivotEventsTestCollaborator::$eventsCalled = []; + $project->managers()->sync([$user->id => ['permissions' => ['foo']], $user2->id => ['permissions' => ['bar']]]); + $this->assertEquals(['saving', 'creating', 'created', 'saved', 'saving', 'updating', 'updated', 'saved'], PivotEventsTestCollaborator::$eventsCalled); + + PivotEventsTestCollaborator::$eventsCalled = []; + $project->managers()->detach($user); + $this->assertEquals(['deleting', 'deleted'], PivotEventsTestCollaborator::$eventsCalled); + } + public function testPivotWithPivotCriteriaTriggerEventsToBeFiredOnCreateUpdateNoneOnDetach() { $user = PivotEventsTestUser::forceCreate(['email' => 'taylor@laravel.com']); @@ -192,6 +220,13 @@ public function contributors() ->wherePivot('role', 'contributor'); } + public function managers() + { + return $this->belongsToMany(PivotEventsTestUser::class, 'project_users', 'project_id', 'user_id') + ->using(PivotEventsTestCollaborator::class) + ->withPivotValue('role', 'manager'); + } + public function equipments() { return $this->morphToMany(PivotEventsTestEquipment::class, 'equipmentable')->using(PivotEventsTestModelEquipment::class); From f519ab8231cd23f23c677e32866819a6fa9291d1 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Sat, 12 Apr 2025 05:55:18 +1000 Subject: [PATCH 356/455] [12.x] Introduce memoized cache driver (#55304) * Introduce memoized cache driver * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Cache/CacheManager.php | 19 + src/Illuminate/Cache/MemoizedStore.php | 203 ++++++++++ src/Illuminate/Support/Facades/Cache.php | 1 + tests/Integration/Cache/MemoizedStoreTest.php | 382 ++++++++++++++++++ 4 files changed, 605 insertions(+) create mode 100644 src/Illuminate/Cache/MemoizedStore.php create mode 100644 tests/Integration/Cache/MemoizedStoreTest.php diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index c4973da748eb..0a0c2de5e171 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -71,6 +71,25 @@ public function driver($driver = null) return $this->store($driver); } + /** + * Get a memoized cache driver instance. + * + * @param string|null $driver + * @return \Illuminate\Contracts\Cache\Repository + */ + public function memo($driver = null) + { + $driver = $driver ?: $this->getDefaultDriver(); + + if (! $this->app->bound($bindingKey = "cache.__memoized:{$driver}")) { + $this->app->scoped($bindingKey, fn () => $this->repository( + new MemoizedStore($driver, $this->store($driver)), ['events' => false] + )); + } + + return $this->app->make($bindingKey); + } + /** * Resolve the given store. * diff --git a/src/Illuminate/Cache/MemoizedStore.php b/src/Illuminate/Cache/MemoizedStore.php new file mode 100644 index 000000000000..9888810de6d7 --- /dev/null +++ b/src/Illuminate/Cache/MemoizedStore.php @@ -0,0 +1,203 @@ + + */ + protected $cache = []; + + /** + * Create a new memoized cache instance. + * + * @param string $name + * @param \Illuminate\Cache\Repository $repository + */ + public function __construct( + protected $name, + protected $repository, + ) { + // + } + + /** + * Retrieve an item from the cache by key. + * + * @param string $key + * @return mixed + */ + public function get($key) + { + $prefixedKey = $this->prefix($key); + + if (array_key_exists($prefixedKey, $this->cache)) { + return $this->cache[$prefixedKey]; + } + + return $this->cache[$prefixedKey] = $this->repository->get($key); + } + + /** + * Retrieve multiple items from the cache by key. + * + * Items not found in the cache will have a null value. + * + * @return array + */ + public function many(array $keys) + { + [$memoized, $retrieved, $missing] = [[], [], []]; + + foreach ($keys as $key) { + $prefixedKey = $this->prefix($key); + + if (array_key_exists($prefixedKey, $this->cache)) { + $memoized[$key] = $this->cache[$prefixedKey]; + } else { + $missing[] = $key; + } + } + + if (count($missing) > 0) { + $retrieved = tap($this->repository->many($missing), function ($values) { + $this->cache = [ + ...$this->cache, + ...collect($values)->mapWithKeys(fn ($value, $key) => [ + $this->prefix($key) => $value, + ]), + ]; + }); + } + + $result = [ + ...$memoized, + ...$retrieved, + ]; + + return array_replace(array_flip($keys), $result); + } + + /** + * Store an item in the cache for a given number of seconds. + * + * @param string $key + * @param mixed $value + * @param int $seconds + * @return bool + */ + public function put($key, $value, $seconds) + { + unset($this->cache[$this->prefix($key)]); + + return $this->repository->put($key, $value, $seconds); + } + + /** + * Store multiple items in the cache for a given number of seconds. + * + * @param int $seconds + * @return bool + */ + public function putMany(array $values, $seconds) + { + foreach ($values as $key => $value) { + unset($this->cache[$this->prefix($key)]); + } + + return $this->repository->putMany($values, $seconds); + } + + /** + * Increment the value of an item in the cache. + * + * @param string $key + * @param mixed $value + * @return int|bool + */ + public function increment($key, $value = 1) + { + unset($this->cache[$this->prefix($key)]); + + return $this->repository->increment($key, $value); + } + + /** + * Decrement the value of an item in the cache. + * + * @param string $key + * @param mixed $value + * @return int|bool + */ + public function decrement($key, $value = 1) + { + unset($this->cache[$this->prefix($key)]); + + return $this->repository->decrement($key, $value); + } + + /** + * Store an item in the cache indefinitely. + * + * @param string $key + * @param mixed $value + * @return bool + */ + public function forever($key, $value) + { + unset($this->cache[$this->prefix($key)]); + + return $this->repository->forever($key, $value); + } + + /** + * Remove an item from the cache. + * + * @param string $key + * @return bool + */ + public function forget($key) + { + unset($this->cache[$this->prefix($key)]); + + return $this->repository->forget($key); + } + + /** + * Remove all items from the cache. + * + * @return bool + */ + public function flush() + { + $this->cache = []; + + return $this->repository->flush(); + } + + /** + * Get the cache key prefix. + * + * @return string + */ + public function getPrefix() + { + return $this->repository->getPrefix(); + } + + /** + * Prefix the given key. + * + * @param string $key + * @return string + */ + protected function prefix($key) + { + return $this->getPrefix().$key; + } +} diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php index 1463306365ca..593bd33ae596 100755 --- a/src/Illuminate/Support/Facades/Cache.php +++ b/src/Illuminate/Support/Facades/Cache.php @@ -4,6 +4,7 @@ /** * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) + * @method static \Illuminate\Contracts\Cache\Repository memo(string|null $name = null) * @method static \Illuminate\Contracts\Cache\Repository driver(string|null $driver = null) * @method static \Illuminate\Contracts\Cache\Repository resolve(string $name) * @method static \Illuminate\Cache\Repository build(array $config) diff --git a/tests/Integration/Cache/MemoizedStoreTest.php b/tests/Integration/Cache/MemoizedStoreTest.php new file mode 100644 index 000000000000..e599f83225d0 --- /dev/null +++ b/tests/Integration/Cache/MemoizedStoreTest.php @@ -0,0 +1,382 @@ +setUpRedis(); + + Config::set('cache.default', 'redis'); + Redis::flushAll(); + } + + protected function tearDown(): void + { + parent::tearDown(); + + $this->tearDownRedis(); + } + + public function test_it_can_memoize_when_retrieving_single_value() + { + Cache::put('name', 'Tim', 60); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Tim', $live); + $this->assertSame('Tim', $memoized); + + Cache::put('name', 'Taylor', 60); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Taylor', $live); + $this->assertSame('Tim', $memoized); + } + + public function test_null_values_are_memoized_when_retrieving_single_value() + { + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertNull($live); + $this->assertNull($memoized); + + Cache::put('name', 'Taylor', 60); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Taylor', $live); + $this->assertNull($memoized); + } + + public function test_it_can_memoize_when_retrieving_mulitple_values() + { + Cache::put('name.0', 'Tim', 60); + Cache::put('name.1', 'Taylor', 60); + + $live = Cache::getMultiple(['name.0', 'name.1']); + $memoized = Cache::memo()->getMultiple(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $live); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $memoized); + + Cache::put('name.0', 'MacDonald', 60); + Cache::put('name.1', 'Otwell', 60); + + $live = Cache::getMultiple(['name.0', 'name.1']); + $memoized = Cache::memo()->getMultiple(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Otwell'], $live); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $memoized); + } + + public function test_null_values_are_memoized_when_retrieving_mulitple_values() + { + $live = Cache::getMultiple(['name.0', 'name.1']); + $memoized = Cache::memo()->getMultiple(['name.0', 'name.1']); + $this->assertSame($live, ['name.0' => null, 'name.1' => null]); + $this->assertSame($memoized, ['name.0' => null, 'name.1' => null]); + + Cache::put('name.0', 'MacDonald', 60); + Cache::put('name.1', 'Otwell', 60); + + $live = Cache::getMultiple(['name.0', 'name.1']); + $memoized = Cache::memo()->getMultiple(['name.0', 'name.1']); + $this->assertSame($live, ['name.0' => 'MacDonald', 'name.1' => 'Otwell']); + $this->assertSame($memoized, ['name.0' => null, 'name.1' => null]); + } + + public function test_it_can_retrieve_already_memoized_and_not_yet_memoized_values_when_retrieving_mulitple_values() + { + Cache::put('name.0', 'Tim', 60); + Cache::put('name.1', 'Taylor', 60); + + $live = Cache::get('name.0'); + $memoized = Cache::memo()->get('name.0'); + $this->assertSame('Tim', $live); + $this->assertSame('Tim', $memoized); + + Cache::put('name.0', 'MacDonald', 60); + Cache::put('name.1', 'Otwell', 60); + + $live = Cache::getMultiple(['name.0', 'name.1']); + $memoized = Cache::memo()->getMultiple(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Otwell'], $live); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Otwell'], $memoized); + } + + public function test_put_forgets_memoized_value() + { + Cache::put(['name.0' => 'Tim', 'name.1' => 'Taylor'], 60); + + $live = Cache::get(['name.0', 'name.1']); + $memoized = Cache::memo()->get(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $live); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $memoized); + + Cache::memo()->put('name.0', 'MacDonald'); + Cache::memo()->put('name.1', 'Otwell'); + + $live = Cache::get(['name.0', 'name.1']); + $memoized = Cache::memo()->get(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Otwell'], $live); + $this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Otwell'], $memoized); + } + + public function test_put_many_forgets_memoized_value() + { + Cache::memo()->put(['name.0' => 'Tim', 'name.1' => 'Taylor'], 60); + + $live = Cache::get(['name.0', 'name.1']); + $memoized = Cache::memo()->get(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $live); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $memoized); + + Cache::memo()->put(['name.0' => 'MacDonald'], 60); + + $live = Cache::get(['name.0', 'name.1']); + $memoized = Cache::memo()->get(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Taylor'], $live); + $this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Taylor'], $memoized); + } + + public function test_increment_forgets_memoized_value() + { + Cache::put('count', 1, 60); + + $live = Cache::get('count'); + $memoized = Cache::memo()->get('count'); + $this->assertSame('1', $live); + $this->assertSame('1', $memoized); + + Cache::memo()->increment('count'); + + $live = Cache::get('count'); + $memoized = Cache::memo()->get('count'); + $this->assertSame('2', $live); + $this->assertSame('2', $memoized); + } + + public function test_decrement_forgets_memoized_value() + { + Cache::put('count', 1, 60); + + $live = Cache::get('count'); + $memoized = Cache::memo()->get('count'); + $this->assertSame('1', $live); + $this->assertSame('1', $memoized); + + Cache::memo()->decrement('count'); + + $live = Cache::get('count'); + $memoized = Cache::memo()->get('count'); + $this->assertSame('0', $live); + $this->assertSame('0', $memoized); + } + + public function test_forever_forgets_memoized_value() + { + Cache::put('name', 'Tim', 60); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Tim', $live); + $this->assertSame('Tim', $memoized); + + Cache::memo()->forever('name', 'Taylor'); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Taylor', $live); + $this->assertSame('Taylor', $memoized); + } + + public function test_forget_forgets_memoized_value() + { + Cache::put('name', 'Tim', 60); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Tim', $live); + $this->assertSame('Tim', $memoized); + + Cache::memo()->forget('name'); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertNull($live); + $this->assertNull($memoized); + } + + public function test_flush_forgets_memoized_value() + { + Cache::put(['name.0' => 'Tim', 'name.1' => 'Taylor'], 60); + + $live = Cache::get(['name.0', 'name.1']); + $memoized = Cache::memo()->get(['name.0', 'name.1']); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $live); + $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $memoized); + + Cache::memo()->flush(); + + $live = Cache::get(['name.0', 'name.1']); + $memoized = Cache::memo()->get(['name.0', 'name.1']); + $this->assertSame(['name.0' => null, 'name.1' => null], $live); + $this->assertSame(['name.0' => null, 'name.1' => null], $memoized); + } + + public function test_memoized_driver_uses_underlying_drivers_prefix() + { + $this->assertSame('laravel_cache_', Cache::memo()->getPrefix()); + + Cache::driver('redis')->setPrefix('foo'); + + $this->assertSame('foo', Cache::memo()->getPrefix()); + } + + public function test_memoized_keys_are_prefixed() + { + $redis = Cache::store('redis'); + + $redis->setPrefix('aaaa'); + $redis->put('name', 'Tim', 60); + $redis->setPrefix('zzzz'); + $redis->put('name', 'Taylor', 60); + + $redis->setPrefix('aaaa'); + $value = Cache::memo('redis')->get('name'); + $this->assertSame('Tim', $value); + + $redis->setPrefix('zzzz'); + $value = Cache::memo('redis')->get('name'); + $this->assertSame('Taylor', $value); + } + + public function test_it_dispatches_decorated_driver_events_only() + { + $redis = Cache::driver('redis'); + $events = []; + Event::listen('*', function ($type, $event) use (&$events) { + if ($event[0] instanceof CacheEvent) { + $events[] = $event[0]; + } + }); + + Cache::memo('redis')->get('name'); + $this->assertCount(2, $events); + $this->assertInstanceOf(RetrievingKey::class, $events[0]); + $this->assertSame('redis', $events[0]->storeName); + $this->assertSame('name', $events[0]->key); + $this->assertInstanceOf(CacheMissed::class, $events[1]); + $this->assertSame('redis', $events[1]->storeName); + $this->assertSame('name', $events[1]->key); + Cache::memo('redis')->get('name'); + $this->assertCount(2, $events); + + Cache::memo('redis')->many(['name']); + $this->assertCount(2, $events); + + Cache::memo('redis')->many(['name.0', 'name.1']); + $this->assertCount(5, $events); + $this->assertInstanceOf(RetrievingManyKeys::class, $events[2]); + $this->assertSame('redis', $events[2]->storeName); + $this->assertSame(['name.0', 'name.1'], $events[2]->keys); + $this->assertInstanceOf(CacheMissed::class, $events[3]); + $this->assertSame('redis', $events[3]->storeName); + $this->assertSame('name.0', $events[3]->key); + $this->assertInstanceOf(CacheMissed::class, $events[4]); + $this->assertSame('redis', $events[4]->storeName); + $this->assertSame('name.1', $events[4]->key); + + Cache::memo('redis')->many(['name.0', 'name.1']); + $this->assertCount(5, $events); + + Cache::memo('redis')->put('name', 'Tim', 1); + $this->assertCount(7, $events); + $this->assertInstanceOf(WritingKey::class, $events[5]); + $this->assertSame('redis', $events[5]->storeName); + $this->assertSame('name', $events[5]->key); + $this->assertInstanceOf(KeyWritten::class, $events[6]); + $this->assertSame('redis', $events[6]->storeName); + $this->assertSame('name', $events[6]->key); + + Cache::memo('redis')->putMany(['name.0' => 'Tim', 'name.1' => 'Taylor']); + $this->assertCount(11, $events); + $this->assertInstanceOf(WritingKey::class, $events[7]); + $this->assertSame('redis', $events[7]->storeName); + $this->assertSame('name.0', $events[7]->key); + $this->assertInstanceOf(KeyWritten::class, $events[8]); + $this->assertSame('redis', $events[8]->storeName); + $this->assertSame('name.0', $events[8]->key); + $this->assertInstanceOf(WritingKey::class, $events[9]); + $this->assertSame('redis', $events[9]->storeName); + $this->assertSame('name.1', $events[9]->key); + $this->assertInstanceOf(KeyWritten::class, $events[10]); + $this->assertSame('redis', $events[10]->storeName); + $this->assertSame('name.1', $events[10]->key); + + Cache::memo('redis')->increment('count'); + $this->assertCount(11, $events); + + Cache::memo('redis')->decrement('count'); + $this->assertCount(11, $events); + + Cache::memo('redis')->forever('name', 'Taylor'); + $this->assertCount(13, $events); + $this->assertInstanceOf(WritingKey::class, $events[11]); + $this->assertSame('redis', $events[11]->storeName); + $this->assertSame('name', $events[11]->key); + $this->assertInstanceOf(KeyWritten::class, $events[12]); + $this->assertSame('redis', $events[12]->storeName); + $this->assertSame('name', $events[12]->key); + + Cache::memo('redis')->forget('name'); + $this->assertCount(15, $events); + $this->assertInstanceOf(ForgettingKey::class, $events[13]); + $this->assertSame('redis', $events[13]->storeName); + $this->assertSame('name', $events[13]->key); + $this->assertInstanceOf(KeyForgotten::class, $events[14]); + $this->assertSame('redis', $events[14]->storeName); + $this->assertSame('name', $events[14]->key); + + Cache::memo('redis')->flush(); + $this->assertCount(15, $events); + } + + public function test_it_resets_cache_store_with_scoped_instances() + { + Cache::put('name', 'Tim', 60); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Tim', $live); + $this->assertSame('Tim', $memoized); + + Cache::put('name', 'Taylor', 60); + $this->app->forgetScopedInstances(); + + $live = Cache::get('name'); + $memoized = Cache::memo()->get('name'); + $this->assertSame('Taylor', $live); + $this->assertSame('Taylor', $memoized); + } +} From 4bf9e08d7038947564e44f45a77d88312c94db31 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Fri, 11 Apr 2025 19:55:54 +0000 Subject: [PATCH 357/455] Update facade docblocks --- src/Illuminate/Support/Facades/Cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php index 593bd33ae596..07553d8bb812 100755 --- a/src/Illuminate/Support/Facades/Cache.php +++ b/src/Illuminate/Support/Facades/Cache.php @@ -4,8 +4,8 @@ /** * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) - * @method static \Illuminate\Contracts\Cache\Repository memo(string|null $name = null) * @method static \Illuminate\Contracts\Cache\Repository driver(string|null $driver = null) + * @method static \Illuminate\Contracts\Cache\Repository memo(string|null $driver = null) * @method static \Illuminate\Contracts\Cache\Repository resolve(string $name) * @method static \Illuminate\Cache\Repository build(array $config) * @method static \Illuminate\Cache\Repository repository(\Illuminate\Contracts\Cache\Store $store, array $config = []) From 234db1cc39c34aca5c5f0594701a9ddb72ed7e20 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 11 Apr 2025 15:13:28 -0500 Subject: [PATCH 358/455] add action support to uri. uri helper --- src/Illuminate/Foundation/helpers.php | 17 ++++++++++++++++- src/Illuminate/Support/Uri.php | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 590ea00e7efa..ec4d02cae26c 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -21,6 +21,8 @@ use Illuminate\Routing\Router; use Illuminate\Support\Facades\Date; use Illuminate\Support\HtmlString; +use Illuminate\Support\Uri; +use League\Uri\Contracts\UriInterface; use Symfony\Component\HttpFoundation\Response; if (! function_exists('abort')) { @@ -1001,9 +1003,22 @@ function __($key = null, $replace = [], $locale = null) } } +if (! function_exists('uri')) { + /** + * Generate a URI for the application. + */ + function uri(UriInterface|Stringable|array|string $uri, mixed $parameters = [], bool $absolute = true): Uri + { + return match (true) { + is_array($uri) => Uri::action($uri, $parameters, $absolute), + default => Uri::of($uri), + }; + } +} + if (! function_exists('url')) { /** - * Generate a url for the application. + * Generate a URL for the application. * * @param string|null $path * @param mixed $parameters diff --git a/src/Illuminate/Support/Uri.php b/src/Illuminate/Support/Uri.php index b90d8c48b7be..0f2779c41ed5 100644 --- a/src/Illuminate/Support/Uri.php +++ b/src/Illuminate/Support/Uri.php @@ -99,6 +99,21 @@ public static function temporarySignedRoute($name, $expiration, $parameters = [] return static::signedRoute($name, $parameters, $expiration, $absolute); } + /** + * Get a URI instance for a controller action. + * + * @param string|array $action + * @param mixed $parameters + * @param bool $absolute + * @return static + * + * @throws \InvalidArgumentException + */ + public static function action($action, $parameters = [], $absolute = true): static + { + return new static(call_user_func(static::$urlGeneratorResolver)->action($action, $parameters, $absolute)); + } + /** * Get the URI's scheme. */ From 25b1d762d8b6cacf5a3da206abeac5b3831227ad Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 11 Apr 2025 15:15:35 -0500 Subject: [PATCH 359/455] allow invokables --- src/Illuminate/Foundation/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index ec4d02cae26c..c33841edf7d3 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -1010,7 +1010,7 @@ function __($key = null, $replace = [], $locale = null) function uri(UriInterface|Stringable|array|string $uri, mixed $parameters = [], bool $absolute = true): Uri { return match (true) { - is_array($uri) => Uri::action($uri, $parameters, $absolute), + is_array($uri) || str_contains($uri, '\\') => Uri::action($uri, $parameters, $absolute), default => Uri::of($uri), }; } From ae766be98bcc29f558572d2b8bb1784f482c37d2 Mon Sep 17 00:00:00 2001 From: Roshandelpoor Mohammad Date: Mon, 14 Apr 2025 00:39:19 +0330 Subject: [PATCH 360/455] Add test for Filesystem lastModified method (#55389) --- tests/Filesystem/FilesystemTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index fe26087c6274..6fab4de691b3 100755 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -648,6 +648,19 @@ public function testHash() $this->assertSame('76d3bc41c9f588f7fcd0d5bf4718f8f84b1c41b20882703100b9eb9413807c01', $filesystem->hash(self::$tempDir.'/foo.txt', 'sha3-256')); } + public function testLastModifiedReturnsTimestamp() + { + $path = self::$tempDir.'/timestamp.txt'; + file_put_contents($path, 'test content'); + + $filesystem = new Filesystem; + $timestamp = $filesystem->lastModified($path); + + $this->assertIsInt($timestamp); + $this->assertGreaterThan(0, $timestamp); + $this->assertEquals(filemtime($path), $timestamp); + } + /** * @param string $file * @return int From a7ce5ca973261781b3881a85b823c0677913f042 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 14 Apr 2025 20:41:50 +0800 Subject: [PATCH 361/455] [12.x] Supports `pda/pheanstalk` 7 (#55397) * Supports `pda/pheanstalk` 7 Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki --- .github/workflows/queues.yml | 15 ++++++++++++--- composer.json | 2 +- src/Illuminate/Queue/composer.json | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/queues.yml b/.github/workflows/queues.yml index 2302892a3d38..3df36c7d6c82 100644 --- a/.github/workflows/queues.yml +++ b/.github/workflows/queues.yml @@ -178,7 +178,16 @@ jobs: beanstalkd: runs-on: ubuntu-24.04 - name: Beanstalkd Driver + strategy: + fail-fast: true + matrix: + include: + - php: 8.2 + pheanstalk: 5 + - php: 8.3 + pheanstalk: 7 + + name: Beanstalkd Driver (pda/pheanstalk:^${{ matrix.pheanstalk }}) steps: - name: Checkout code @@ -194,7 +203,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_mysql, :php-psr tools: composer:v2 coverage: none @@ -207,7 +216,7 @@ jobs: with: timeout_minutes: 5 max_attempts: 5 - command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress + command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress --with="pda/pheanstalk:^${{ matrix.pheanstalk }}" - name: Daemonize beanstalkd run: ./beanstalkd-1.13/beanstalkd & diff --git a/composer.json b/composer.json index 6ce6a3254312..708b0c12c893 100644 --- a/composer.json +++ b/composer.json @@ -112,7 +112,7 @@ "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", "orchestra/testbench-core": "^10.0.0", - "pda/pheanstalk": "^5.0.6", + "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index ee32be673acb..197737e2d1b3 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -45,7 +45,7 @@ "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.322.9).", "illuminate/redis": "Required to use the Redis queue driver (^12.0).", - "pda/pheanstalk": "Required to use the Beanstalk queue driver (^5.0)." + "pda/pheanstalk": "Required to use the Beanstalk queue driver (^5.0.6|^7.0.0)." }, "config": { "sort-packages": true From d30738d6f8d64d726c7e4d9cb4b75dbe7669d3f2 Mon Sep 17 00:00:00 2001 From: Roshandelpoor Mohammad Date: Mon, 14 Apr 2025 16:12:39 +0330 Subject: [PATCH 362/455] [12.x] Add comprehensive filesystem operation tests to FilesystemTest (#55399) * Add test for Filesystem lastModified method * add comprehensive filesystem operation tests Add two new test cases to FilesystemTest.php: - testFileCreationAndContentVerification: Tests file creation, existence check, content verification, and size - testDirectoryOperationsWithSubdirectories: Tests directory creation, subdirectory operations, and file listing These tests complement existing filesystem tests by verifying end-to-end operations and directory structure management. --- tests/Filesystem/FilesystemTest.php | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index 6fab4de691b3..1930ff15f963 100755 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -672,4 +672,42 @@ private function getFilePermissions($file) return (int) base_convert($filePerms, 8, 10); } + + public function testFileCreationAndContentVerification() + { + $files = new Filesystem; + + $testContent = 'This is a test file content'; + $filePath = self::$tempDir.'/test.txt'; + + $files->put($filePath, $testContent); + + $this->assertTrue($files->exists($filePath)); + $this->assertSame($testContent, $files->get($filePath)); + $this->assertEquals(strlen($testContent), $files->size($filePath)); + } + + public function testDirectoryOperationsWithSubdirectories() + { + $files = new Filesystem; + + $dirPath = self::$tempDir.'/test_dir'; + $subDirPath = $dirPath.'/sub_dir'; + + $this->assertTrue($files->makeDirectory($dirPath)); + $this->assertTrue($files->isDirectory($dirPath)); + + $this->assertTrue($files->makeDirectory($subDirPath)); + $this->assertTrue($files->isDirectory($subDirPath)); + + $filePath = $subDirPath.'/test.txt'; + $files->put($filePath, 'test content'); + + $this->assertTrue($files->exists($filePath)); + + $allFiles = $files->allFiles($dirPath); + + $this->assertCount(1, $allFiles); + $this->assertEquals('test.txt', $allFiles[0]->getFilename()); + } } From 8e2f48edbccfa94b520c9234f1755b3e96f1aad4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 07:43:26 -0500 Subject: [PATCH 363/455] Bump vite in /src/Illuminate/Foundation/resources/exceptions/renderer (#55402) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.17 to 5.4.18. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.4.18/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.4.18/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 5.4.18 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../resources/exceptions/renderer/package-lock.json | 8 ++++---- .../Foundation/resources/exceptions/renderer/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json b/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json index 3e51c3f26930..45eee2341a84 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json @@ -11,7 +11,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "tippy.js": "^6.3.7", - "vite": "^5.4.17", + "vite": "^5.4.18", "vite-require": "^0.2.3" } }, @@ -2106,9 +2106,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "5.4.17", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.17.tgz", - "integrity": "sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==", + "version": "5.4.18", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz", + "integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==", "license": "MIT", "dependencies": { "esbuild": "^0.21.3", diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/package.json b/src/Illuminate/Foundation/resources/exceptions/renderer/package.json index 15ea5041d0e7..efa13c77fc74 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/package.json +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/package.json @@ -12,7 +12,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "tippy.js": "^6.3.7", - "vite": "^5.4.17", + "vite": "^5.4.18", "vite-require": "^0.2.3" } } From 0549cbab2ac6ec1360ac5fe3db58a569cf8b6204 Mon Sep 17 00:00:00 2001 From: 3Descape Date: Mon, 14 Apr 2025 17:12:25 +0200 Subject: [PATCH 364/455] Add descriptive error messages to assertViewHas() (#55392) * Add descriptive error messages to assertViewHas() * Fix inconsistency and add missing dot * Add message to key-value case, move $actual for reuse, adjust messages. * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Testing/TestResponse.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 5b632ce11051..3f6f59a36730 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -1192,21 +1192,21 @@ public function assertViewHas($key, $value = null) $this->ensureResponseHasView(); + $actual = Arr::get($this->original->gatherData(), $key); + if (is_null($value)) { - PHPUnit::withResponse($this)->assertTrue(Arr::has($this->original->gatherData(), $key)); + PHPUnit::withResponse($this)->assertTrue(Arr::has($this->original->gatherData(), $key), "Failed asserting that the data contains the key [{$key}]."); } elseif ($value instanceof Closure) { - PHPUnit::withResponse($this)->assertTrue($value(Arr::get($this->original->gatherData(), $key))); + PHPUnit::withResponse($this)->assertTrue($value($actual), "Failed asserting that the value at [{$key}] fulfills the expectations defined by the closure."); } elseif ($value instanceof Model) { - PHPUnit::withResponse($this)->assertTrue($value->is(Arr::get($this->original->gatherData(), $key))); + PHPUnit::withResponse($this)->assertTrue($value->is($actual), "Failed asserting that the model at [{$key}] matches the given model."); } elseif ($value instanceof EloquentCollection) { - $actual = Arr::get($this->original->gatherData(), $key); - PHPUnit::withResponse($this)->assertInstanceOf(EloquentCollection::class, $actual); PHPUnit::withResponse($this)->assertSameSize($value, $actual); - $value->each(fn ($item, $index) => PHPUnit::withResponse($this)->assertTrue($actual->get($index)->is($item))); + $value->each(fn ($item, $index) => PHPUnit::withResponse($this)->assertTrue($actual->get($index)->is($item), "Failed asserting that the collection at [{$key}.[{$index}]]' matches the given collection.")); } else { - PHPUnit::withResponse($this)->assertEquals($value, Arr::get($this->original->gatherData(), $key)); + PHPUnit::withResponse($this)->assertEquals($value, $actual, "Failed asserting that [{$key}] matches the expected value."); } return $this; From bfeadb48d63f395b77b59f7252913693a16dbff8 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Mon, 14 Apr 2025 18:51:48 +0330 Subject: [PATCH 365/455] Improve Generic Type annotations for LazyCollection methods (#55380) --- src/Illuminate/Collections/LazyCollection.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 601e0717590a..daf811bfcadd 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -113,7 +113,7 @@ public function all() /** * Eager load all items into a new lazy collection backed by an array. * - * @return static + * @return static */ public function eager() { @@ -123,7 +123,7 @@ public function eager() /** * Cache values as they're enumerated. * - * @return static + * @return static */ public function remember() { @@ -334,7 +334,7 @@ public function countBy($countBy = null) * Get the items that are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static + * @return static */ public function diff($items) { @@ -1091,7 +1091,7 @@ public function replaceRecursive($items) /** * Reverse items order. * - * @return static + * @return static */ public function reverse() { @@ -1186,7 +1186,7 @@ public function after($value, $strict = false) /** * Shuffle the items in the collection. * - * @return static + * @return static */ public function shuffle() { @@ -1549,7 +1549,7 @@ public function sortKeysUsing(callable $callback) * Take the first or last {$limit} items. * * @param int $limit - * @return static + * @return static */ public function take($limit) { @@ -1592,7 +1592,7 @@ public function take($limit) * Take items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value - * @return static + * @return static */ public function takeUntil($value) { @@ -1614,7 +1614,7 @@ public function takeUntil($value) * Take items in the collection until a given point in time. * * @param \DateTimeInterface $timeout - * @return static + * @return static */ public function takeUntilTimeout(DateTimeInterface $timeout) { @@ -1639,7 +1639,7 @@ public function takeUntilTimeout(DateTimeInterface $timeout) * Take items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value - * @return static + * @return static */ public function takeWhile($value) { @@ -1653,7 +1653,7 @@ public function takeWhile($value) * Pass each item in the collection to the given callback, lazily. * * @param callable(TValue, TKey): mixed $callback - * @return static + * @return static */ public function tapEach(callable $callback) { @@ -1713,7 +1713,7 @@ public function undot() * * @param (callable(TValue, TKey): mixed)|string|null $key * @param bool $strict - * @return static + * @return static */ public function unique($key = null, $strict = false) { From 109a967e3d9caefe152caebff0f469fb3071bcfd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 14 Apr 2025 12:43:40 -0500 Subject: [PATCH 366/455] add named route support --- src/Illuminate/Foundation/helpers.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index c33841edf7d3..8f0523dce09f 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -20,6 +20,7 @@ use Illuminate\Queue\CallQueuedClosure; use Illuminate\Routing\Router; use Illuminate\Support\Facades\Date; +use Illuminate\Support\Facades\Route; use Illuminate\Support\HtmlString; use Illuminate\Support\Uri; use League\Uri\Contracts\UriInterface; @@ -1011,6 +1012,7 @@ function uri(UriInterface|Stringable|array|string $uri, mixed $parameters = [], { return match (true) { is_array($uri) || str_contains($uri, '\\') => Uri::action($uri, $parameters, $absolute), + str_contains($uri, '.') && Route::has($uri) => Uri::route($uri, $parameters, $absolute), default => Uri::of($uri), }; } From c1fe481e3cf6c1d831a951709e89d1ce923c7f2f Mon Sep 17 00:00:00 2001 From: Roshandelpoor Mohammad Date: Tue, 15 Apr 2025 18:54:32 +0330 Subject: [PATCH 367/455] [12.x] Add test coverage for Process sequence with multiple env variables (#55406) * Add test for Filesystem lastModified method * add process sequence test with multiple environment variables * fix style --- tests/Process/ProcessTest.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Process/ProcessTest.php b/tests/Process/ProcessTest.php index 0c30cdf47888..b3fd5903a699 100644 --- a/tests/Process/ProcessTest.php +++ b/tests/Process/ProcessTest.php @@ -795,6 +795,37 @@ public function testAssertingThatNothingRan() $factory->assertNothingRan(); } + public function testProcessWithMultipleEnvironmentVariablesAndSequences() + { + $factory = new Factory; + + $factory->fake([ + 'printenv TEST_VAR OTHER_VAR' => $factory->sequence() + ->push("test_value\nother_value") + ->push("new_test_value\nnew_other_value"), + ]); + + $result = $factory->env([ + 'TEST_VAR' => 'test_value', + 'OTHER_VAR' => 'other_value', + ])->run('printenv TEST_VAR OTHER_VAR'); + + $this->assertTrue($result->successful()); + $this->assertEquals("test_value\nother_value\n", $result->output()); + + $result = $factory->env([ + 'TEST_VAR' => 'new_test_value', + 'OTHER_VAR' => 'new_other_value', + ])->run('printenv TEST_VAR OTHER_VAR'); + + $this->assertTrue($result->successful()); + $this->assertEquals("new_test_value\nnew_other_value\n", $result->output()); + + $factory->assertRanTimes(function ($process) { + return str_contains($process->command, 'printenv TEST_VAR OTHER_VAR'); + }, 2); + } + protected function ls() { return windows_os() ? 'dir' : 'ls'; From 5829a18eb49e53d5005b14eab3dd0b43d4c4b765 Mon Sep 17 00:00:00 2001 From: "Philip Iezzi (Pipo)" <2759561+onlime@users.noreply.github.com> Date: Tue, 15 Apr 2025 17:25:43 +0200 Subject: [PATCH 368/455] [12.x] Fix cc/bcc/replyTo address merging in `MailMessage` (#55404) * Fix cc/bcc/replyTo address merging in MailMessage * Apply Pint style fixes --- .../Notifications/Messages/MailMessage.php | 6 ++-- .../NotificationMailMessageTest.php | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Notifications/Messages/MailMessage.php b/src/Illuminate/Notifications/Messages/MailMessage.php index f6eab8ca6798..f65622863d76 100644 --- a/src/Illuminate/Notifications/Messages/MailMessage.php +++ b/src/Illuminate/Notifications/Messages/MailMessage.php @@ -212,7 +212,7 @@ public function from($address, $name = null) public function replyTo($address, $name = null) { if ($this->arrayOfAddresses($address)) { - $this->replyTo += $this->parseAddresses($address); + $this->replyTo = array_merge($this->replyTo, $this->parseAddresses($address)); } else { $this->replyTo[] = [$address, $name]; } @@ -230,7 +230,7 @@ public function replyTo($address, $name = null) public function cc($address, $name = null) { if ($this->arrayOfAddresses($address)) { - $this->cc += $this->parseAddresses($address); + $this->cc = array_merge($this->cc, $this->parseAddresses($address)); } else { $this->cc[] = [$address, $name]; } @@ -248,7 +248,7 @@ public function cc($address, $name = null) public function bcc($address, $name = null) { if ($this->arrayOfAddresses($address)) { - $this->bcc += $this->parseAddresses($address); + $this->bcc = array_merge($this->bcc, $this->parseAddresses($address)); } else { $this->bcc[] = [$address, $name]; } diff --git a/tests/Notifications/NotificationMailMessageTest.php b/tests/Notifications/NotificationMailMessageTest.php index b901f0aab297..794a1ad3670d 100644 --- a/tests/Notifications/NotificationMailMessageTest.php +++ b/tests/Notifications/NotificationMailMessageTest.php @@ -83,6 +83,16 @@ public function testCcIsSetCorrectly() $message->cc(['test@example.com', 'Test' => 'test@example.com']); $this->assertSame([['test@example.com', null], ['test@example.com', 'Test']], $message->cc); + + $message = new MailMessage; + $message->cc('test@example.com', 'Test') + ->cc(['test@example.com', 'test2@example.com']); + + $this->assertSame([ + ['test@example.com', 'Test'], + ['test@example.com', null], + ['test2@example.com', null], + ], $message->cc); } public function testBccIsSetCorrectly() @@ -102,6 +112,16 @@ public function testBccIsSetCorrectly() $message->bcc(['test@example.com', 'Test' => 'test@example.com']); $this->assertSame([['test@example.com', null], ['test@example.com', 'Test']], $message->bcc); + + $message = new MailMessage; + $message->bcc('test@example.com', 'Test') + ->bcc(['test@example.com', 'test2@example.com']); + + $this->assertSame([ + ['test@example.com', 'Test'], + ['test@example.com', null], + ['test2@example.com', null], + ], $message->bcc); } public function testReplyToIsSetCorrectly() @@ -121,6 +141,16 @@ public function testReplyToIsSetCorrectly() $message->replyTo(['test@example.com', 'Test' => 'test@example.com']); $this->assertSame([['test@example.com', null], ['test@example.com', 'Test']], $message->replyTo); + + $message = new MailMessage; + $message->replyTo('test@example.com', 'Test') + ->replyTo(['test@example.com', 'test2@example.com']); + + $this->assertSame([ + ['test@example.com', 'Test'], + ['test@example.com', null], + ['test2@example.com', null], + ], $message->replyTo); } public function testMetadataIsSetCorrectly() From 28b7dbeee5541b14cc738696d57cbd607a1441ad Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Tue, 15 Apr 2025 17:35:22 +0200 Subject: [PATCH 369/455] Add a make function (#55417) --- src/Illuminate/Support/Fluent.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Illuminate/Support/Fluent.php b/src/Illuminate/Support/Fluent.php index 0d087806583a..b1b720bb6fc8 100755 --- a/src/Illuminate/Support/Fluent.php +++ b/src/Illuminate/Support/Fluent.php @@ -39,6 +39,17 @@ public function __construct($attributes = []) $this->fill($attributes); } + /** + * Create a new fluent instance. + * + * @param iterable $attributes + * @return static + */ + public static function make($attributes = []) + { + return new static($attributes); + } + /** * Get an attribute from the fluent instance using "dot" notation. * From d413f9e297b62238c6c633c082f8f45a888e31b6 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 15 Apr 2025 15:36:35 +0000 Subject: [PATCH 370/455] Update version to v12.9.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index c5fb944a1cd2..8a13a2eeedb2 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.8.1'; + const VERSION = '12.9.0'; /** * The base path for the Laravel installation. From ff4f657ca9d9af36e021a67c6eeb97949a0e27d0 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 15 Apr 2025 15:38:19 +0000 Subject: [PATCH 371/455] Update CHANGELOG --- CHANGELOG.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b6ac8f599a..a2f1c3c3e76d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,35 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.8.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.9.0...12.x) + +## [v12.9.0](https://github.com/laravel/framework/compare/v12.8.1...v12.9.0) - 2025-04-15 + +* Add types to ViewErrorBag by [@AJenbo](https://github.com/AJenbo) in https://github.com/laravel/framework/pull/55329 +* Add types to MessageBag by [@AJenbo](https://github.com/AJenbo) in https://github.com/laravel/framework/pull/55327 +* [12.x] add generics to commonly used methods in Schema/Builder by [@taka-oyama](https://github.com/taka-oyama) in https://github.com/laravel/framework/pull/55330 +* Return frozen time for easier testing by [@jasonmccreary](https://github.com/jasonmccreary) in https://github.com/laravel/framework/pull/55323 +* Enhance DetectsLostConnections to Support AWS Aurora Credential Rotation Scenario by [@msaifmfz](https://github.com/msaifmfz) in https://github.com/laravel/framework/pull/55331 +* [12.x] Rename test method of failedRequest() by [@LKaemmerling](https://github.com/LKaemmerling) in https://github.com/laravel/framework/pull/55332 +* feat: Add a callback to be called on transaction failure by [@dshafik](https://github.com/dshafik) in https://github.com/laravel/framework/pull/55338 +* [12.x] Add withRelationshipAutoloading method to model by [@litvinchuk](https://github.com/litvinchuk) in https://github.com/laravel/framework/pull/55344 +* [12.x] Enable HTTP client retries when middleware throws an exception by [@27pchrisl](https://github.com/27pchrisl) in https://github.com/laravel/framework/pull/55343 +* [12.x] Fix Closure serialization error in automatic relation loading by [@litvinchuk](https://github.com/litvinchuk) in https://github.com/laravel/framework/pull/55345 +* Add test for Unique validation rule with WhereIn constraints by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55351 +* Add [@throws](https://github.com/throws) in doc-blocks by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55361 +* [12.x] Update `propagateRelationAutoloadCallbackToRelation` method doc-block by [@derian-all-win-software](https://github.com/derian-all-win-software) in https://github.com/laravel/framework/pull/55363 +* [12.x] - Redis - Establish connection first, before set the options by [@alexmontoanelli](https://github.com/alexmontoanelli) in https://github.com/laravel/framework/pull/55370 +* [12.x] Fix translation FileLoader overrides with a missing key by [@fabio-ivona](https://github.com/fabio-ivona) in https://github.com/laravel/framework/pull/55342 +* [12.x] Fix pivot model events not working when using the `withPivotValue` by [@amir9480](https://github.com/amir9480) in https://github.com/laravel/framework/pull/55280 +* [12.x] Introduce memoized cache driver by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/55304 +* [12.x] Add test for Filesystem::lastModified() method by [@roshandelpoor](https://github.com/roshandelpoor) in https://github.com/laravel/framework/pull/55389 +* [12.x] Supports `pda/pheanstalk` 7 by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55397 +* [12.x] Add comprehensive filesystem operation tests to FilesystemTest by [@roshandelpoor](https://github.com/roshandelpoor) in https://github.com/laravel/framework/pull/55399 +* Bump vite from 5.4.17 to 5.4.18 in /src/Illuminate/Foundation/resources/exceptions/renderer by [@dependabot](https://github.com/dependabot) in https://github.com/laravel/framework/pull/55402 +* Add descriptive error messages to assertViewHas() by [@3Descape](https://github.com/3Descape) in https://github.com/laravel/framework/pull/55392 +* Use Generic Types Annotations for LazyCollection Methods by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55380 +* [12.x] Add test coverage for Process sequence with multiple env variables by [@roshandelpoor](https://github.com/roshandelpoor) in https://github.com/laravel/framework/pull/55406 +* [12.x] Fix cc/bcc/replyTo address merging in `MailMessage` by [@onlime](https://github.com/onlime) in https://github.com/laravel/framework/pull/55404 +* [12.x] Add a `make` function in the `Fluent` by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/55417 ## [v12.8.1](https://github.com/laravel/framework/compare/v12.8.0...v12.8.1) - 2025-04-08 From b9d304d0569d3aad8ca422ebcb1d7c9903d1b97e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vikartovsk=C3=BD?= <62723172+MarekVikartovsky@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:43:39 +0200 Subject: [PATCH 372/455] [12.x] Forward only passed arguments into Illuminate\Database\Eloquent\Collection::partition method (#55422) * Forward only passed arguments into Illuminate\Database\Eloquent\Collection::partition function * Added test for partition method without operator --------- Co-authored-by: marek.vikartovsky --- src/Illuminate/Database/Eloquent/Collection.php | 2 +- tests/Database/DatabaseEloquentCollectionTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index ba15202828e1..05ec0d345a1a 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -711,7 +711,7 @@ public function pad($size, $value) */ public function partition($key, $operator = null, $value = null) { - return parent::partition($key, $operator, $value)->toBase(); + return parent::partition(...func_get_args())->toBase(); } /** diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index a7a71fcebb78..99f2ad363ac7 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -582,6 +582,7 @@ public function testNonModelRelatedMethods() $this->assertEquals(BaseCollection::class, get_class($a->countBy('foo'))); $this->assertEquals(BaseCollection::class, get_class($b->flip())); $this->assertEquals(BaseCollection::class, get_class($a->partition('foo', '=', 'bar'))); + $this->assertEquals(BaseCollection::class, get_class($a->partition('foo', 'bar'))); } public function testMakeVisibleRemovesHiddenAndIncludesVisible() From b94be7d66ee7a01b6e6ed2505ab45f962bc57d0c Mon Sep 17 00:00:00 2001 From: Roshandelpoor Mohammad Date: Tue, 15 Apr 2025 22:33:20 +0330 Subject: [PATCH 373/455] test for complex context manipulation (#55423) --- tests/Log/LogLoggerTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Log/LogLoggerTest.php b/tests/Log/LogLoggerTest.php index 85cc1799cf0e..939021d1214f 100755 --- a/tests/Log/LogLoggerTest.php +++ b/tests/Log/LogLoggerTest.php @@ -103,4 +103,21 @@ public function testListenShortcut() $writer->listen($callback); } + + public function testComplexContextManipulation() + { + $writer = new Logger($monolog = m::mock(Monolog::class)); + + $writer->withContext(['user_id' => 123, 'action' => 'login']); + $writer->withContext(['ip' => '127.0.0.1', 'timestamp' => '1986-10-29']); + $writer->withoutContext(['timestamp']); + + $monolog->shouldReceive('info')->once()->with('User action', [ + 'user_id' => 123, + 'action' => 'login', + 'ip' => '127.0.0.1', + ]); + + $writer->info('User action'); + } } From d9d2b63600314e5d3e34e2d3ecd4aa4b25c4f569 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Wed, 16 Apr 2025 07:38:48 -0400 Subject: [PATCH 374/455] Update DumpCommand.php (#55431) --- src/Illuminate/Database/Console/DumpCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Console/DumpCommand.php b/src/Illuminate/Database/Console/DumpCommand.php index b27d6c66a93c..0c038939f0de 100644 --- a/src/Illuminate/Database/Console/DumpCommand.php +++ b/src/Illuminate/Database/Console/DumpCommand.php @@ -53,7 +53,7 @@ public function handle(ConnectionResolverInterface $connections, Dispatcher $dis if ($this->option('prune')) { (new Filesystem)->deleteDirectory( - $path = database_path('migrations'), $preserve = false + $path = database_path('migrations'), preserve: false ); $info .= ' and pruned'; From b35050763b311210f9f39ef9159d824e3bb75cd3 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Wed, 16 Apr 2025 08:39:56 -0300 Subject: [PATCH 375/455] Fix the serve command sometimes fails to destructure the request pool array (#55427) The code expects the array to always contain 3 items, but apparently that's not always true. Sometimes it only contains a single key "1" with the file that was requested (when PHP serves a file). I don't know the root cause yet, but this patch seems to work around that. --- src/Illuminate/Foundation/Console/ServeCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/ServeCommand.php b/src/Illuminate/Foundation/Console/ServeCommand.php index 6b86bb65fa7a..e722046dd2ed 100644 --- a/src/Illuminate/Foundation/Console/ServeCommand.php +++ b/src/Illuminate/Foundation/Console/ServeCommand.php @@ -335,7 +335,7 @@ protected function flushOutputBuffer() } elseif ((new Stringable($line))->contains(' Closing')) { $requestPort = static::getRequestPortFromLine($line); - if (empty($this->requestsPool[$requestPort])) { + if (empty($this->requestsPool[$requestPort]) || count($this->requestsPool[$requestPort] ?? []) !== 3) { $this->requestsPool[$requestPort] = [ $this->getDateFromLine($line), false, From f7f5215a697d11711f3ea1a1377f688a23ef4ecb Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 16 Apr 2025 19:41:24 +0800 Subject: [PATCH 376/455] [12.x] Changes to `package-lock.json` should trigger `npm run build` (#55426) * [12.x] Changes to `package-lock.json` should trigger `npm run build` Signed-off-by: Mior Muhammad Zaki * Update update-assets.yml --------- Signed-off-by: Mior Muhammad Zaki Co-authored-by: Taylor Otwell --- .github/workflows/update-assets.yml | 31 +++++++++++++++++++ .../exceptions/renderer/dist/styles.css | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/update-assets.yml diff --git a/.github/workflows/update-assets.yml b/.github/workflows/update-assets.yml new file mode 100644 index 000000000000..8ecd63efce0a --- /dev/null +++ b/.github/workflows/update-assets.yml @@ -0,0 +1,31 @@ +name: 'update assets' + +on: + push: + branches: + - '12.x' + paths: + - '/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json' + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Update Exception Renderer Assets + run: | + npm ci --prefix "./src/Illuminate/Foundation/resources/exceptions/renderer" + npm run build --prefix "./src/Illuminate/Foundation/resources/exceptions/renderer" + + - name: Commit Compiled Files + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Update Assets diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/dist/styles.css b/src/Illuminate/Foundation/resources/exceptions/renderer/dist/styles.css index 0e5a2eeb8677..f0dc676d1bc4 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/dist/styles.css +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/dist/styles.css @@ -1 +1 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}.tippy-box[data-theme~=material]{background-color:#505355;font-weight:600}.tippy-box[data-theme~=material][data-placement^=top]>.tippy-arrow:before{border-top-color:#505355}.tippy-box[data-theme~=material][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#505355}.tippy-box[data-theme~=material][data-placement^=left]>.tippy-arrow:before{border-left-color:#505355}.tippy-box[data-theme~=material][data-placement^=right]>.tippy-arrow:before{border-right-color:#505355}.tippy-box[data-theme~=material]>.tippy-backdrop{background-color:#505355}.tippy-box[data-theme~=material]>.tippy-svg-arrow{fill:#505355}.tippy-box[data-animation=scale][data-placement^=top]{transform-origin:bottom}.tippy-box[data-animation=scale][data-placement^=bottom]{transform-origin:top}.tippy-box[data-animation=scale][data-placement^=left]{transform-origin:right}.tippy-box[data-animation=scale][data-placement^=right]{transform-origin:left}.tippy-box[data-animation=scale][data-state=hidden]{transform:scale(.5);opacity:0}*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Figtree,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.z-10{z-index:10}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-3{margin-top:.75rem;margin-bottom:.75rem}.-mt-2{margin-top:-.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-3{margin-left:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-\[32\.5rem\]{height:32.5rem}.h-\[35\.5rem\]{height:35.5rem}.max-h-32{max-height:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-\[8rem\]{width:8rem}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-full{max-width:100%}.flex-none{flex:none}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.origin-top-right{transform-origin:top right}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-6{gap:1.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.overflow-y-hidden{overflow-y:hidden}.overflow-x-scroll{overflow-x:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.border{border-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-transparent{border-color:transparent}.border-l-red-500{--tw-border-opacity:1;border-left-color:rgb(239 68 68 / var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-200\/80{background-color:#e5e7ebcc}.bg-red-500\/20{background-color:#ef444433}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.fill-red-500{fill:#ef4444}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-12{padding-bottom:3rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:Figtree,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.leading-5{line-height:1.25rem}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68 / var(--tw-text-opacity))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow-xl{--tw-shadow:0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-gray-900\/5{--tw-ring-color:rgb(17 24 39 / .05)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}[x-cloak]{display:none}html{-moz-tab-size:4;-o-tab-size:4;tab-size:4}table.hljs-ln{color:inherit;font-size:inherit;border-spacing:2px}pre code.hljs{background:none;padding:.5em 0 0;width:100%}.hljs-ln-line{white-space-collapse:preserve;text-wrap:nowrap}.trace{-webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 4rem),transparent)}.scrollbar-hidden{-ms-overflow-style:none;scrollbar-width:none;overflow-x:scroll}.scrollbar-hidden::-webkit-scrollbar{-webkit-appearance:none;width:0;height:0}.hljs-ln .hljs-ln-numbers{padding:5px;border-right-color:transparent;margin-right:5px}.hljs-ln-n{width:50px}.hljs-ln-numbers{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;text-align:center;border-right:1px solid #ccc;vertical-align:top;padding-right:5px}.hljs-ln-code{width:100%;padding-left:10px;padding-right:10px}.hljs-ln-code:hover{background-color:#ef444433}.default\:col-span-full:default{grid-column:1 / -1}.default\:row-span-1:default{grid-row:span 1 / span 1}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-gray-100\/75:hover{background-color:#f3f4f6bf}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:text-gray-500:focus{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}.dark\:border:is(.dark *){border-width:1px}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:border-gray-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.dark\:border-gray-900:is(.dark *){--tw-border-opacity:1;border-color:rgb(17 24 39 / var(--tw-border-opacity))}.dark\:border-l-red-500:is(.dark *){--tw-border-opacity:1;border-left-color:rgb(239 68 68 / var(--tw-border-opacity))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:bg-gray-900\/80:is(.dark *){background-color:#111827cc}.dark\:bg-gray-950\/95:is(.dark *){background-color:#030712f2}.dark\:bg-red-500\/20:is(.dark *){background-color:#ef444433}.dark\:text-gray-100:is(.dark *){--tw-text-opacity:1;color:rgb(243 244 246 / var(--tw-text-opacity))}.dark\:text-gray-300:is(.dark *){--tw-text-opacity:1;color:rgb(209 213 219 / var(--tw-text-opacity))}.dark\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-gray-600:is(.dark *){--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity))}.dark\:text-gray-950:is(.dark *){--tw-text-opacity:1;color:rgb(3 7 18 / var(--tw-text-opacity))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:ring-1:is(.dark *){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.dark\:ring-gray-800:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgb(31 41 55 / var(--tw-ring-opacity))}.dark\:hover\:bg-gray-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:hover\:bg-gray-800:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:hover\:bg-gray-800\/75:hover:is(.dark *){background-color:#1f2937bf}.dark\:hover\:text-gray-500:hover:is(.dark *){--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.dark\:focus\:text-gray-500:focus:is(.dark *){--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}@media (min-width: 640px){.sm\:col-span-1{grid-column:span 1 / span 1}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:mt-10{margin-top:2.5rem}.sm\:gap-6{gap:1.5rem}.sm\:p-12{padding:3rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}}@media (min-width: 768px){.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:min-w-64{min-width:16rem}.md\:max-w-80{max-width:20rem}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}.md\:gap-2{gap:.5rem}}@media (min-width: 1024px){.lg\:block{display:block}.lg\:inline-block{display:inline-block}.lg\:w-\[12rem\]{width:12rem}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:text-2xl{font-size:1.5rem;line-height:2rem}.lg\:text-base{font-size:1rem;line-height:1.5rem}.lg\:text-sm{font-size:.875rem;line-height:1.25rem}.default\:lg\:col-span-6:default{grid-column:span 6 / span 6}} +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}.tippy-box[data-theme~=material]{background-color:#505355;font-weight:600}.tippy-box[data-theme~=material][data-placement^=top]>.tippy-arrow:before{border-top-color:#505355}.tippy-box[data-theme~=material][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#505355}.tippy-box[data-theme~=material][data-placement^=left]>.tippy-arrow:before{border-left-color:#505355}.tippy-box[data-theme~=material][data-placement^=right]>.tippy-arrow:before{border-right-color:#505355}.tippy-box[data-theme~=material]>.tippy-backdrop{background-color:#505355}.tippy-box[data-theme~=material]>.tippy-svg-arrow{fill:#505355}.tippy-box[data-animation=scale][data-placement^=top]{transform-origin:bottom}.tippy-box[data-animation=scale][data-placement^=bottom]{transform-origin:top}.tippy-box[data-animation=scale][data-placement^=left]{transform-origin:right}.tippy-box[data-animation=scale][data-placement^=right]{transform-origin:left}.tippy-box[data-animation=scale][data-state=hidden]{transform:scale(.5);opacity:0}*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Figtree,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.z-10{z-index:10}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-3{margin-top:.75rem;margin-bottom:.75rem}.-mt-2{margin-top:-.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-3{margin-left:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-\[32\.5rem\]{height:32.5rem}.h-\[35\.5rem\]{height:35.5rem}.max-h-32{max-height:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-\[8rem\]{width:8rem}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-full{max-width:100%}.flex-none{flex:none}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.origin-top-right{transform-origin:top right}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-6{gap:1.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.overflow-y-hidden{overflow-y:hidden}.overflow-x-scroll{overflow-x:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.border{border-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-transparent{border-color:transparent}.border-l-red-500{--tw-border-opacity:1;border-left-color:rgb(239 68 68 / var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-200\/80{background-color:#e5e7ebcc}.bg-red-500\/20{background-color:#ef444433}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.fill-red-500{fill:#ef4444}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-12{padding-bottom:3rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:Figtree,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.leading-5{line-height:1.25rem}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68 / var(--tw-text-opacity))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow-xl{--tw-shadow:0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-gray-900\/5{--tw-ring-color:rgb(17 24 39 / .05)}[x-cloak]{display:none}html{-moz-tab-size:4;-o-tab-size:4;tab-size:4}table.hljs-ln{color:inherit;font-size:inherit;border-spacing:2px}pre code.hljs{background:none;padding:.5em 0 0;width:100%}.hljs-ln-line{white-space-collapse:preserve;text-wrap:nowrap}.trace{-webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 4rem),transparent)}.scrollbar-hidden{-ms-overflow-style:none;scrollbar-width:none;overflow-x:scroll}.scrollbar-hidden::-webkit-scrollbar{-webkit-appearance:none;width:0;height:0}.hljs-ln .hljs-ln-numbers{padding:5px;border-right-color:transparent;margin-right:5px}.hljs-ln-n{width:50px}.hljs-ln-numbers{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;text-align:center;border-right:1px solid #ccc;vertical-align:top;padding-right:5px}.hljs-ln-code{width:100%;padding-left:10px;padding-right:10px}.hljs-ln-code:hover{background-color:#ef444433}.default\:col-span-full:default{grid-column:1 / -1}.default\:row-span-1:default{grid-row:span 1 / span 1}.hover\:rounded-b-md:hover{border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem}.hover\:rounded-t-md:hover{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-gray-100\/75:hover{background-color:#f3f4f6bf}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:text-gray-500:focus{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}.dark\:border:is(.dark *){border-width:1px}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:border-gray-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.dark\:border-gray-900:is(.dark *){--tw-border-opacity:1;border-color:rgb(17 24 39 / var(--tw-border-opacity))}.dark\:border-l-red-500:is(.dark *){--tw-border-opacity:1;border-left-color:rgb(239 68 68 / var(--tw-border-opacity))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:bg-gray-900\/80:is(.dark *){background-color:#111827cc}.dark\:bg-gray-950\/95:is(.dark *){background-color:#030712f2}.dark\:bg-red-500\/20:is(.dark *){background-color:#ef444433}.dark\:text-gray-100:is(.dark *){--tw-text-opacity:1;color:rgb(243 244 246 / var(--tw-text-opacity))}.dark\:text-gray-300:is(.dark *){--tw-text-opacity:1;color:rgb(209 213 219 / var(--tw-text-opacity))}.dark\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-gray-600:is(.dark *){--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity))}.dark\:text-gray-950:is(.dark *){--tw-text-opacity:1;color:rgb(3 7 18 / var(--tw-text-opacity))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:ring-1:is(.dark *){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.dark\:ring-gray-800:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgb(31 41 55 / var(--tw-ring-opacity))}.dark\:hover\:bg-gray-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:hover\:bg-gray-800:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:hover\:bg-gray-800\/75:hover:is(.dark *){background-color:#1f2937bf}.dark\:hover\:text-gray-500:hover:is(.dark *){--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.dark\:focus\:text-gray-500:focus:is(.dark *){--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}@media (min-width: 640px){.sm\:col-span-1{grid-column:span 1 / span 1}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:mt-10{margin-top:2.5rem}.sm\:gap-6{gap:1.5rem}.sm\:p-12{padding:3rem}.sm\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}}@media (min-width: 768px){.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:min-w-64{min-width:16rem}.md\:max-w-80{max-width:20rem}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}.md\:gap-2{gap:.5rem}}@media (min-width: 1024px){.lg\:block{display:block}.lg\:inline-block{display:inline-block}.lg\:w-\[12rem\]{width:12rem}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:text-2xl{font-size:1.5rem;line-height:2rem}.lg\:text-base{font-size:1rem;line-height:1.5rem}.lg\:text-sm{font-size:.875rem;line-height:1.25rem}.default\:lg\:col-span-6:default{grid-column:span 6 / span 6}} From 62a313a79b1aadbdb431e8db23b67733e0d8d34d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 16 Apr 2025 06:56:24 -0500 Subject: [PATCH 377/455] revert on failure --- .../Database/Concerns/ManagesTransactions.php | 9 ++--- .../Database/ConnectionInterface.php | 3 +- .../Database/SqlServerConnection.php | 9 ++--- .../Database/DatabaseTransactionsTest.php | 36 ------------------- 4 files changed, 5 insertions(+), 52 deletions(-) diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index f3ec8a42df69..9a501967c75b 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -38,7 +38,7 @@ public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailur // exception back out, and let the developer handle an uncaught exception. catch (Throwable $e) { $this->handleTransactionException( - $e, $currentAttempt, $attempts, $onFailure + $e, $currentAttempt, $attempts ); continue; @@ -79,12 +79,11 @@ public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailur * @param \Throwable $e * @param int $currentAttempt * @param int $maxAttempts - * @param Closure|null $onFailure * @return void * * @throws \Throwable */ - protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts, ?Closure $onFailure) + protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts) { // On a deadlock, MySQL rolls back the entire transaction so we can't just // retry the query. We have to throw this exception all the way out and @@ -110,10 +109,6 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma return; } - if ($onFailure !== null) { - $onFailure($e); - } - throw $e; } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 322a59576724..288adb4206e3 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -131,12 +131,11 @@ public function prepareBindings(array $bindings); * * @param \Closure $callback * @param int $attempts - * @param Closure|null $onFailure * @return mixed * * @throws \Throwable */ - public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailure = null); + public function transaction(Closure $callback, $attempts = 1); /** * Start a new database transaction. diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index bddf82f02a70..1e6fe52bfe16 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -27,16 +27,15 @@ public function getDriverTitle() * * @param \Closure $callback * @param int $attempts - * @param Closure|null $onFailure * @return mixed * * @throws \Throwable */ - public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailure = null) + public function transaction(Closure $callback, $attempts = 1) { for ($a = 1; $a <= $attempts; $a++) { if ($this->getDriverName() === 'sqlsrv') { - return parent::transaction($callback, $attempts, $onFailure); + return parent::transaction($callback, $attempts); } $this->getPdo()->exec('BEGIN TRAN'); @@ -56,10 +55,6 @@ public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailur catch (Throwable $e) { $this->getPdo()->exec('ROLLBACK TRAN'); - if ($a === $attempts && $onFailure !== null) { - $onFailure($e); - } - throw $e; } diff --git a/tests/Integration/Database/DatabaseTransactionsTest.php b/tests/Integration/Database/DatabaseTransactionsTest.php index 35051f528b20..58894d01ae5e 100644 --- a/tests/Integration/Database/DatabaseTransactionsTest.php +++ b/tests/Integration/Database/DatabaseTransactionsTest.php @@ -105,42 +105,6 @@ public function testTransactionsDoNotAffectDifferentConnections() $this->assertTrue($secondObject->ran); $this->assertFalse($thirdObject->ran); } - - public function testOnErrorCallbackIsCalled() - { - $executed = false; - try { - DB::transaction(function () { - throw new \Exception; - }, 1, function () use (&$executed) { - $executed = true; - }); - } catch (\Throwable) { - // Ignore the exception - } - - $this->assertTrue($executed); - } - - public function testOnErrorCallbackIsCalledWithDeadlockRetry() - { - $executed = false; - $attempts = 0; - - try { - DB::transaction(function () use (&$attempts) { - $attempts += 1; - throw new \Exception('has been chosen as the deadlock victim'); - }, 3, function () use (&$executed) { - $executed = true; - }); - } catch (\Throwable) { - // Ignore the exception - } - - $this->assertSame(3, $attempts); - $this->assertTrue($executed); - } } class TestObjectForTransactions From d4a2a0c9dc3a163568e35e6ab58e2caecc98c86c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 16 Apr 2025 06:57:51 -0500 Subject: [PATCH 378/455] remove arg --- src/Illuminate/Database/Concerns/ManagesTransactions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index 9a501967c75b..23bc60434e49 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -16,12 +16,11 @@ trait ManagesTransactions * * @param (\Closure(static): TReturn) $callback * @param int $attempts - * @param Closure|null $onFailure * @return TReturn * * @throws \Throwable */ - public function transaction(Closure $callback, $attempts = 1, ?Closure $onFailure = null) + public function transaction(Closure $callback, $attempts = 1) { for ($currentAttempt = 1; $currentAttempt <= $attempts; $currentAttempt++) { $this->beginTransaction(); From d2002e3f210c37ae315cea9b6dd469981dd2392a Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:58:41 +0000 Subject: [PATCH 379/455] Update facade docblocks --- src/Illuminate/Support/Facades/DB.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 339653c59aea..f1c41bc0abb4 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -108,7 +108,7 @@ * @method static string getServerVersion() * @method static void resolverFor(string $driver, \Closure $callback) * @method static \Closure|null getResolver(string $driver) - * @method static mixed transaction(\Closure $callback, int $attempts = 1, \Closure|null $onFailure = null) + * @method static mixed transaction(\Closure $callback, int $attempts = 1) * @method static void beginTransaction() * @method static void commit() * @method static void rollBack(int|null $toLevel = null) From 7c201749cc4b463eea1b58698f5fb4f4c09dc32b Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:02:03 +0000 Subject: [PATCH 380/455] Update version to v12.9.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 8a13a2eeedb2..e469c711a1d4 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.9.0'; + const VERSION = '12.9.1'; /** * The base path for the Laravel installation. From f5036188b8d225e86701c2079ad6b81a1c9b0579 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:03:43 +0000 Subject: [PATCH 381/455] Update CHANGELOG --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2f1c3c3e76d..40d1ac1905c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.9.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.9.1...12.x) + +## [v12.9.1](https://github.com/laravel/framework/compare/v12.9.0...v12.9.1) - 2025-04-16 + +* [12.x] Forward only passed arguments into Illuminate\Database\Eloquent\Collection::partition method by [@MarekVikartovsky](https://github.com/MarekVikartovsky) in https://github.com/laravel/framework/pull/55422 +* [12.x] Add test for complex context manipulation in Logger by [@roshandelpoor](https://github.com/roshandelpoor) in https://github.com/laravel/framework/pull/55423 +* [12.x] Remove unused var from `DumpCommand` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55431 +* [12.x] Fix the serve command sometimes fails to destructure the request pool array by [@tonysm](https://github.com/tonysm) in https://github.com/laravel/framework/pull/55427 +* [12.x] Changes to `package-lock.json` should trigger `npm run build` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55426 ## [v12.9.0](https://github.com/laravel/framework/compare/v12.8.1...v12.9.0) - 2025-04-15 From fcd31a68aee19c62e4b6abfbafb1b5245fff8fee Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 16 Apr 2025 17:44:02 +0300 Subject: [PATCH 382/455] [12.x] Fixed a bug in using `illuminate/console` in external apps (#55430) * Fixed a bug in using `illuminate/console` in external apps * Update TaskResult.php * move file --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Console/View/Components/Task.php | 10 +++++----- src/Illuminate/Console/View/TaskResult.php | 10 ++++++++++ src/Illuminate/Database/Migrations/Migrator.php | 2 +- tests/Console/View/ComponentsTest.php | 6 +++--- 4 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 src/Illuminate/Console/View/TaskResult.php diff --git a/src/Illuminate/Console/View/Components/Task.php b/src/Illuminate/Console/View/Components/Task.php index a7dbf62df3c3..fb4ab8d3a517 100644 --- a/src/Illuminate/Console/View/Components/Task.php +++ b/src/Illuminate/Console/View/Components/Task.php @@ -2,7 +2,7 @@ namespace Illuminate\Console\View\Components; -use Illuminate\Database\Migrations\MigrationResult; +use Illuminate\Console\View\TaskResult; use Illuminate\Support\InteractsWithTime; use Symfony\Component\Console\Output\OutputInterface; use Throwable; @@ -35,10 +35,10 @@ public function render($description, $task = null, $verbosity = OutputInterface: $startTime = microtime(true); - $result = MigrationResult::Failure; + $result = TaskResult::Failure->value; try { - $result = ($task ?: fn () => MigrationResult::Success)(); + $result = ($task ?: fn () => TaskResult::Success->value)(); } catch (Throwable $e) { throw $e; } finally { @@ -55,8 +55,8 @@ public function render($description, $task = null, $verbosity = OutputInterface: $this->output->writeln( match ($result) { - MigrationResult::Failure => ' FAIL', - MigrationResult::Skipped => ' SKIPPED', + TaskResult::Failure->value => ' FAIL', + TaskResult::Skipped->value => ' SKIPPED', default => ' DONE' }, $verbosity, diff --git a/src/Illuminate/Console/View/TaskResult.php b/src/Illuminate/Console/View/TaskResult.php new file mode 100644 index 000000000000..13d2afba018d --- /dev/null +++ b/src/Illuminate/Console/View/TaskResult.php @@ -0,0 +1,10 @@ +write(Task::class, $name, fn () => MigrationResult::Skipped); + $this->write(Task::class, $name, fn () => MigrationResult::Skipped->value); } else { $this->write(Task::class, $name, fn () => $this->runMigration($migration, 'up')); diff --git a/tests/Console/View/ComponentsTest.php b/tests/Console/View/ComponentsTest.php index e10ff74a17d1..31958ba6cb8f 100644 --- a/tests/Console/View/ComponentsTest.php +++ b/tests/Console/View/ComponentsTest.php @@ -109,17 +109,17 @@ public function testTask() { $output = new BufferedOutput(); - with(new Components\Task($output))->render('My task', fn () => MigrationResult::Success); + with(new Components\Task($output))->render('My task', fn () => MigrationResult::Success->value); $result = $output->fetch(); $this->assertStringContainsString('My task', $result); $this->assertStringContainsString('DONE', $result); - with(new Components\Task($output))->render('My task', fn () => MigrationResult::Failure); + with(new Components\Task($output))->render('My task', fn () => MigrationResult::Failure->value); $result = $output->fetch(); $this->assertStringContainsString('My task', $result); $this->assertStringContainsString('FAIL', $result); - with(new Components\Task($output))->render('My task', fn () => MigrationResult::Skipped); + with(new Components\Task($output))->render('My task', fn () => MigrationResult::Skipped->value); $result = $output->fetch(); $this->assertStringContainsString('My task', $result); $this->assertStringContainsString('SKIPPED', $result); From 2b3d9e8c046dea04027d7eb8d171ad4c844adc85 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 16 Apr 2025 22:45:29 +0800 Subject: [PATCH 383/455] Disable SQLServer 2017 CI as `ubuntu-20.24` has been removed (#55425) https://github.com/actions/runner-images/issues/11101 Signed-off-by: Mior Muhammad Zaki --- .github/workflows/databases.yml | 94 ++++++++++++++++----------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/.github/workflows/databases.yml b/.github/workflows/databases.yml index 15fcb4c1a463..961af6983a22 100644 --- a/.github/workflows/databases.yml +++ b/.github/workflows/databases.yml @@ -293,53 +293,53 @@ jobs: DB_USERNAME: SA DB_PASSWORD: Forge123 - mssql_2017: - runs-on: ubuntu-20.04 - timeout-minutes: 5 - - services: - sqlsrv: - image: mcr.microsoft.com/mssql/server:2017-latest - env: - ACCEPT_EULA: Y - SA_PASSWORD: Forge123 - ports: - - 1433:1433 - - strategy: - fail-fast: true - - name: SQL Server 2017 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 8.3 - extensions: dom, curl, libxml, mbstring, zip, pcntl, sqlsrv, pdo, pdo_sqlsrv, odbc, pdo_odbc, :php-psr - tools: composer:v2 - coverage: none - - - name: Set Framework version - run: composer config version "12.x-dev" - - - name: Install dependencies - uses: nick-fields/retry@v3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress - - - name: Execute tests - run: vendor/bin/phpunit tests/Integration/Database - env: - DB_CONNECTION: sqlsrv - DB_DATABASE: master - DB_USERNAME: SA - DB_PASSWORD: Forge123 + # mssql_2017: + # runs-on: ubuntu-20.04 + # timeout-minutes: 5 + + # services: + # sqlsrv: + # image: mcr.microsoft.com/mssql/server:2017-latest + # env: + # ACCEPT_EULA: Y + # SA_PASSWORD: Forge123 + # ports: + # - 1433:1433 + + # strategy: + # fail-fast: true + + # name: SQL Server 2017 + + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + + # - name: Setup PHP + # uses: shivammathur/setup-php@v2 + # with: + # php-version: 8.3 + # extensions: dom, curl, libxml, mbstring, zip, pcntl, sqlsrv, pdo, pdo_sqlsrv, odbc, pdo_odbc, :php-psr + # tools: composer:v2 + # coverage: none + + # - name: Set Framework version + # run: composer config version "12.x-dev" + + # - name: Install dependencies + # uses: nick-fields/retry@v3 + # with: + # timeout_minutes: 5 + # max_attempts: 5 + # command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress + + # - name: Execute tests + # run: vendor/bin/phpunit tests/Integration/Database + # env: + # DB_CONNECTION: sqlsrv + # DB_DATABASE: master + # DB_USERNAME: SA + # DB_PASSWORD: Forge123 sqlite: runs-on: ubuntu-24.04 From 5291e1924a03390abccd0a299d06bee39500ee57 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 16 Apr 2025 10:39:36 -0500 Subject: [PATCH 384/455] check for method existence --- src/Illuminate/Cache/TaggedCache.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/TaggedCache.php b/src/Illuminate/Cache/TaggedCache.php index 62adff972249..fc5b290eee1e 100644 --- a/src/Illuminate/Cache/TaggedCache.php +++ b/src/Illuminate/Cache/TaggedCache.php @@ -109,7 +109,11 @@ public function taggedItemKey($key) */ protected function event($event) { - parent::event($event->setTags($this->tags->getNames())); + if (method_exists($event, 'setTags')) { + $event->setTags($this->tags->getNames()); + } + + parent::event($event); } /** From 3db59aa0f382c349c78a92f3e5b5522e00e3301b Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:44:19 +0000 Subject: [PATCH 385/455] Update version to v12.9.2 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index e469c711a1d4..4a5fd27bf711 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.9.1'; + const VERSION = '12.9.2'; /** * The base path for the Laravel installation. From 22f61b33090b57ab154e840752b0d2dbd0a7a3d7 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:45:59 +0000 Subject: [PATCH 386/455] Update CHANGELOG --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40d1ac1905c8..369bc45486d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.9.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.9.2...12.x) + +## [v12.9.2](https://github.com/laravel/framework/compare/v12.9.1...v12.9.2) - 2025-04-16 + +* [12.x] Fixed a bug in using `illuminate/console` in external apps by [@andrey-helldar](https://github.com/andrey-helldar) in https://github.com/laravel/framework/pull/55430 +* Disable SQLServer 2017 CI as `ubuntu-20.24` has been removed by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/55425 ## [v12.9.1](https://github.com/laravel/framework/compare/v12.9.0...v12.9.1) - 2025-04-16 From 48347e54408adfa82afe40fefaa16cd5eeea4865 Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:14:14 +0330 Subject: [PATCH 387/455] Use value() helper in 'when' method to simplify code (#55465) --- src/Illuminate/Conditionable/Traits/Conditionable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Conditionable/Traits/Conditionable.php b/src/Illuminate/Conditionable/Traits/Conditionable.php index 5e3194bbcb6a..7bc394c5f6c7 100644 --- a/src/Illuminate/Conditionable/Traits/Conditionable.php +++ b/src/Illuminate/Conditionable/Traits/Conditionable.php @@ -20,7 +20,7 @@ trait Conditionable */ public function when($value = null, ?callable $callback = null, ?callable $default = null) { - $value = $value instanceof Closure ? $value($this) : $value; + $value = value($value, $this); if (func_num_args() === 0) { return new HigherOrderWhenProxy($this); From 494fa563acb9c6a2e2759f47ce93296b43dfb555 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 18 Apr 2025 12:45:24 +0000 Subject: [PATCH 388/455] Test `@use` directive without quotes (#55462) --- tests/View/Blade/BladeUseTest.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/View/Blade/BladeUseTest.php b/tests/View/Blade/BladeUseTest.php index 8e72c321540d..ae99825de61e 100644 --- a/tests/View/Blade/BladeUseTest.php +++ b/tests/View/Blade/BladeUseTest.php @@ -6,29 +6,45 @@ class BladeUseTest extends AbstractBladeTestCase { public function testUseStatementsAreCompiled() { - $string = "Foo @use('SomeNamespace\SomeClass', 'Foo') bar"; $expected = "Foo bar"; + + $string = "Foo @use('SomeNamespace\SomeClass', 'Foo') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = "Foo @use(SomeNamespace\SomeClass, Foo) bar"; $this->assertEquals($expected, $this->compiler->compileString($string)); } public function testUseStatementsWithoutAsAreCompiled() { - $string = "Foo @use('SomeNamespace\SomeClass') bar"; $expected = "Foo bar"; + + $string = "Foo @use('SomeNamespace\SomeClass') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = "Foo @use(SomeNamespace\SomeClass) bar"; $this->assertEquals($expected, $this->compiler->compileString($string)); } public function testUseStatementsWithBackslashAtBeginningAreCompiled() { - $string = "Foo @use('\SomeNamespace\SomeClass') bar"; $expected = "Foo bar"; + + $string = "Foo @use('\SomeNamespace\SomeClass') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = "Foo @use(\SomeNamespace\SomeClass) bar"; $this->assertEquals($expected, $this->compiler->compileString($string)); } public function testUseStatementsWithBackslashAtBeginningAndAliasedAreCompiled() { - $string = "Foo @use('\SomeNamespace\SomeClass', 'Foo') bar"; $expected = "Foo bar"; + + $string = "Foo @use('\SomeNamespace\SomeClass', 'Foo') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = "Foo @use(\SomeNamespace\SomeClass, Foo) bar"; $this->assertEquals($expected, $this->compiler->compileString($string)); } } From 98f9785c7066f5f27c445af5e33272c6f1a0a2d8 Mon Sep 17 00:00:00 2001 From: Roshandelpoor Mohammad Date: Fri, 18 Apr 2025 16:16:40 +0330 Subject: [PATCH 389/455] enhance broadcast event test coverage (#55458) --- tests/Events/BroadcastedEventsTest.php | 86 ++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tests/Events/BroadcastedEventsTest.php b/tests/Events/BroadcastedEventsTest.php index c241938364ba..9b2a84a31ae7 100644 --- a/tests/Events/BroadcastedEventsTest.php +++ b/tests/Events/BroadcastedEventsTest.php @@ -62,6 +62,92 @@ public function testShouldBroadcastFail() $this->assertFalse($d->shouldBroadcast([$event])); } + + public function testBroadcastWithMultipleChannels() + { + $d = new Dispatcher($container = m::mock(Container::class)); + $broadcast = m::mock(BroadcastFactory::class); + $broadcast->shouldReceive('queue')->once(); + $container->shouldReceive('make')->once()->with(BroadcastFactory::class)->andReturn($broadcast); + + $event = new class implements ShouldBroadcast + { + public function broadcastOn() + { + return ['channel-1', 'channel-2']; + } + }; + + $d->dispatch($event); + } + + public function testBroadcastWithCustomConnectionName() + { + $d = new Dispatcher($container = m::mock(Container::class)); + $broadcast = m::mock(BroadcastFactory::class); + $broadcast->shouldReceive('queue')->once(); + $container->shouldReceive('make')->once()->with(BroadcastFactory::class)->andReturn($broadcast); + + $event = new class implements ShouldBroadcast + { + public $connection = 'custom-connection'; + + public function broadcastOn() + { + return ['test-channel']; + } + }; + + $d->dispatch($event); + } + + public function testBroadcastWithCustomEventName() + { + $d = new Dispatcher($container = m::mock(Container::class)); + $broadcast = m::mock(BroadcastFactory::class); + $broadcast->shouldReceive('queue')->once(); + $container->shouldReceive('make')->once()->with(BroadcastFactory::class)->andReturn($broadcast); + + $event = new class implements ShouldBroadcast + { + public function broadcastOn() + { + return ['test-channel']; + } + + public function broadcastAs() + { + return 'custom-event-name'; + } + }; + + $d->dispatch($event); + } + + public function testBroadcastWithCustomPayload() + { + $d = new Dispatcher($container = m::mock(Container::class)); + $broadcast = m::mock(BroadcastFactory::class); + $broadcast->shouldReceive('queue')->once(); + $container->shouldReceive('make')->once()->with(BroadcastFactory::class)->andReturn($broadcast); + + $event = new class implements ShouldBroadcast + { + public $customData = 'test-data'; + + public function broadcastOn() + { + return ['test-channel']; + } + + public function broadcastWith() + { + return ['custom' => $this->customData]; + } + }; + + $d->dispatch($event); + } } class BroadcastEvent implements ShouldBroadcast From f026be3f5564282e12a5e155418aaff335a3b74a Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Fri, 18 Apr 2025 14:48:37 +0200 Subject: [PATCH 390/455] [12.x] Add `Conditionable` Trait to `Fluent` (#55455) * Add `Conditionable` * Format * Update Fluent.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Fluent.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Fluent.php b/src/Illuminate/Support/Fluent.php index b1b720bb6fc8..e420711b3fa3 100755 --- a/src/Illuminate/Support/Fluent.php +++ b/src/Illuminate/Support/Fluent.php @@ -5,6 +5,7 @@ use ArrayAccess; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; +use Illuminate\Support\Traits\Conditionable; use Illuminate\Support\Traits\InteractsWithData; use Illuminate\Support\Traits\Macroable; use JsonSerializable; @@ -18,7 +19,7 @@ */ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable { - use InteractsWithData, Macroable { + use Conditionable, InteractsWithData, Macroable { __call as macroCall; } From c0be602f9b8d433bedab457c9349298b661b65ea Mon Sep 17 00:00:00 2001 From: Patrick Weh <40495041+patrickweh@users.noreply.github.com> Date: Fri, 18 Apr 2025 14:51:00 +0200 Subject: [PATCH 391/455] [12.x] Fix relation auto loading with manually set relations (#55452) --- src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 06f61e86c546..79a2f5d98cd0 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -184,7 +184,7 @@ protected function propagateRelationAutoloadCallbackToRelation($key, $models, $c foreach ($models as $model) { // Check if relation autoload contexts are different to avoid circular relation autoload... - if (is_null($context) || $context !== $model) { + if ((is_null($context) || $context !== $model) && is_object($model) && method_exists($model, 'autoloadRelationsUsing')) { $model->autoloadRelationsUsing($callback, $context); } } From e7ad734a41c0a63000c1eabd6ddfa292bba7b505 Mon Sep 17 00:00:00 2001 From: Claudio Eyzaguirre Date: Fri, 18 Apr 2025 08:52:24 -0400 Subject: [PATCH 392/455] add missing types (#55445) --- src/Illuminate/Cache/RateLimiter.php | 8 ++++---- src/Illuminate/Support/Facades/RateLimiter.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Cache/RateLimiter.php b/src/Illuminate/Cache/RateLimiter.php index c3598e364ebf..67588ffbb1e1 100644 --- a/src/Illuminate/Cache/RateLimiter.php +++ b/src/Illuminate/Cache/RateLimiter.php @@ -99,7 +99,7 @@ public function limiter($name) * @param string $key * @param int $maxAttempts * @param \Closure $callback - * @param int $decaySeconds + * @param \DateTimeInterface|\DateInterval|int $decaySeconds * @return mixed */ public function attempt($key, $maxAttempts, Closure $callback, $decaySeconds = 60) @@ -141,7 +141,7 @@ public function tooManyAttempts($key, $maxAttempts) * Increment (by 1) the counter for a given key for a given decay time. * * @param string $key - * @param int $decaySeconds + * @param \DateTimeInterface|\DateInterval|int $decaySeconds * @return int */ public function hit($key, $decaySeconds = 60) @@ -153,7 +153,7 @@ public function hit($key, $decaySeconds = 60) * Increment the counter for a given key for a given decay time by a given amount. * * @param string $key - * @param int $decaySeconds + * @param \DateTimeInterface|\DateInterval|int $decaySeconds * @param int $amount * @return int */ @@ -184,7 +184,7 @@ public function increment($key, $decaySeconds = 60, $amount = 1) * Decrement the counter for a given key for a given decay time by a given amount. * * @param string $key - * @param int $decaySeconds + * @param \DateTimeInterface|\DateInterval|int $decaySeconds * @param int $amount * @return int */ diff --git a/src/Illuminate/Support/Facades/RateLimiter.php b/src/Illuminate/Support/Facades/RateLimiter.php index 376c3ccc19dc..7f8cf5c2166c 100644 --- a/src/Illuminate/Support/Facades/RateLimiter.php +++ b/src/Illuminate/Support/Facades/RateLimiter.php @@ -5,11 +5,11 @@ /** * @method static \Illuminate\Cache\RateLimiter for(\BackedEnum|\UnitEnum|string $name, \Closure $callback) * @method static \Closure|null limiter(\BackedEnum|\UnitEnum|string $name) - * @method static mixed attempt(string $key, int $maxAttempts, \Closure $callback, int $decaySeconds = 60) + * @method static mixed attempt(string $key, int $maxAttempts, \Closure $callback, \DateTimeInterface|\DateInterval|int $decaySeconds = 60) * @method static bool tooManyAttempts(string $key, int $maxAttempts) - * @method static int hit(string $key, int $decaySeconds = 60) - * @method static int increment(string $key, int $decaySeconds = 60, int $amount = 1) - * @method static int decrement(string $key, int $decaySeconds = 60, int $amount = 1) + * @method static int hit(string $key, \DateTimeInterface|\DateInterval|int $decaySeconds = 60) + * @method static int increment(string $key, \DateTimeInterface|\DateInterval|int $decaySeconds = 60, int $amount = 1) + * @method static int decrement(string $key, \DateTimeInterface|\DateInterval|int $decaySeconds = 60, int $amount = 1) * @method static mixed attempts(string $key) * @method static mixed resetAttempts(string $key) * @method static int remaining(string $key, int $maxAttempts) From 5548f956a64fa620356ae96880418901d358787d Mon Sep 17 00:00:00 2001 From: Serhii Litvinchuk Date: Fri, 18 Apr 2025 15:55:05 +0300 Subject: [PATCH 393/455] [12.x] Fix for global automaticallyEagerLoadRelationships not working in certain cases (#55443) --- src/Illuminate/Database/Eloquent/Builder.php | 10 +++------- src/Illuminate/Database/Eloquent/HasCollection.php | 8 +++++++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 73163988aec8..4e22b9ae9fa2 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -854,13 +854,9 @@ public function get($columns = ['*']) $models = $builder->eagerLoadRelations($models); } - $collection = $builder->getModel()->newCollection($models); - - if (Model::isAutomaticallyEagerLoadingRelationships()) { - $collection->withRelationshipAutoloading(); - } - - return $this->applyAfterQueryCallbacks($collection); + return $this->applyAfterQueryCallbacks( + $builder->getModel()->newCollection($models) + ); } /** diff --git a/src/Illuminate/Database/Eloquent/HasCollection.php b/src/Illuminate/Database/Eloquent/HasCollection.php index a1b462784dd6..d430f0099b81 100644 --- a/src/Illuminate/Database/Eloquent/HasCollection.php +++ b/src/Illuminate/Database/Eloquent/HasCollection.php @@ -27,7 +27,13 @@ public function newCollection(array $models = []) { static::$resolvedCollectionClasses[static::class] ??= ($this->resolveCollectionFromAttribute() ?? static::$collectionClass); - return new static::$resolvedCollectionClasses[static::class]($models); + $collection = new static::$resolvedCollectionClasses[static::class]($models); + + if (Model::isAutomaticallyEagerLoadingRelationships()) { + $collection->withRelationshipAutoloading(); + } + + return $collection; } /** From bcb3f584d65ec94357d344f44047bd31f4e6844e Mon Sep 17 00:00:00 2001 From: erikn69 Date: Fri, 18 Apr 2025 09:50:25 -0500 Subject: [PATCH 394/455] Fix missing `setTags` method on new cache flush events (#55405) --- .../Cache/Events/CacheFlushFailed.php | 45 +++++++++++++++++++ src/Illuminate/Cache/Events/CacheFlushed.php | 23 +++++++++- src/Illuminate/Cache/Events/CacheFlushing.php | 23 +++++++++- src/Illuminate/Cache/RedisTaggedCache.php | 7 +++ src/Illuminate/Cache/Repository.php | 3 ++ src/Illuminate/Cache/TaggedCache.php | 8 +++- tests/Cache/CacheEventsTest.php | 9 +++- 7 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 src/Illuminate/Cache/Events/CacheFlushFailed.php diff --git a/src/Illuminate/Cache/Events/CacheFlushFailed.php b/src/Illuminate/Cache/Events/CacheFlushFailed.php new file mode 100644 index 000000000000..7d987e9de82c --- /dev/null +++ b/src/Illuminate/Cache/Events/CacheFlushFailed.php @@ -0,0 +1,45 @@ +storeName = $storeName; + $this->tags = $tags; + } + + /** + * Set the tags for the cache event. + * + * @param array $tags + * @return $this + */ + public function setTags($tags) + { + $this->tags = $tags; + + return $this; + } +} diff --git a/src/Illuminate/Cache/Events/CacheFlushed.php b/src/Illuminate/Cache/Events/CacheFlushed.php index fb0275f06e50..5f942afdd1af 100644 --- a/src/Illuminate/Cache/Events/CacheFlushed.php +++ b/src/Illuminate/Cache/Events/CacheFlushed.php @@ -11,14 +11,35 @@ class CacheFlushed */ public $storeName; + /** + * The tags that were assigned to the key. + * + * @var array + */ + public $tags; + /** * Create a new event instance. * * @param string|null $storeName * @return void */ - public function __construct($storeName) + public function __construct($storeName, array $tags = []) { $this->storeName = $storeName; + $this->tags = $tags; + } + + /** + * Set the tags for the cache event. + * + * @param array $tags + * @return $this + */ + public function setTags($tags) + { + $this->tags = $tags; + + return $this; } } diff --git a/src/Illuminate/Cache/Events/CacheFlushing.php b/src/Illuminate/Cache/Events/CacheFlushing.php index 21054c8b718a..905f016143d7 100644 --- a/src/Illuminate/Cache/Events/CacheFlushing.php +++ b/src/Illuminate/Cache/Events/CacheFlushing.php @@ -11,14 +11,35 @@ class CacheFlushing */ public $storeName; + /** + * The tags that were assigned to the key. + * + * @var array + */ + public $tags; + /** * Create a new event instance. * * @param string|null $storeName * @return void */ - public function __construct($storeName) + public function __construct($storeName, array $tags = []) { $this->storeName = $storeName; + $this->tags = $tags; + } + + /** + * Set the tags for the cache event. + * + * @param array $tags + * @return $this + */ + public function setTags($tags) + { + $this->tags = $tags; + + return $this; } } diff --git a/src/Illuminate/Cache/RedisTaggedCache.php b/src/Illuminate/Cache/RedisTaggedCache.php index 8846844b413d..69053266d33d 100644 --- a/src/Illuminate/Cache/RedisTaggedCache.php +++ b/src/Illuminate/Cache/RedisTaggedCache.php @@ -2,6 +2,9 @@ namespace Illuminate\Cache; +use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushing; + class RedisTaggedCache extends TaggedCache { /** @@ -105,9 +108,13 @@ public function forever($key, $value) */ public function flush() { + $this->event(new CacheFlushing($this->getName())); + $this->flushValues(); $this->tags->flush(); + $this->event(new CacheFlushed($this->getName())); + return true; } diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index da22ea7d4a8f..3eb6f700ed01 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -7,6 +7,7 @@ use Closure; use DateTimeInterface; use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushFailed; use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; @@ -584,6 +585,8 @@ public function clear(): bool if ($result) { $this->event(new CacheFlushed($this->getName())); + } else { + $this->event(new CacheFlushFailed($this->getName())); } return $result; diff --git a/src/Illuminate/Cache/TaggedCache.php b/src/Illuminate/Cache/TaggedCache.php index fc5b290eee1e..5504cdcc2ffd 100644 --- a/src/Illuminate/Cache/TaggedCache.php +++ b/src/Illuminate/Cache/TaggedCache.php @@ -2,6 +2,8 @@ namespace Illuminate\Cache; +use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Contracts\Cache\Store; class TaggedCache extends Repository @@ -77,8 +79,12 @@ public function decrement($key, $value = 1) */ public function flush() { + $this->event(new CacheFlushing($this->getName())); + $this->tags->reset(); + $this->event(new CacheFlushed($this->getName())); + return true; } @@ -104,7 +110,7 @@ public function taggedItemKey($key) /** * Fire an event for this cache instance. * - * @param \Illuminate\Cache\Events\CacheEvent $event + * @param object $event * @return void */ protected function event($event) diff --git a/tests/Cache/CacheEventsTest.php b/tests/Cache/CacheEventsTest.php index 77a9173506eb..e0c747d0ca7d 100755 --- a/tests/Cache/CacheEventsTest.php +++ b/tests/Cache/CacheEventsTest.php @@ -4,6 +4,7 @@ use Illuminate\Cache\ArrayStore; use Illuminate\Cache\Events\CacheFlushed; +use Illuminate\Cache\Events\CacheFlushFailed; use Illuminate\Cache\Events\CacheFlushing; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; @@ -242,7 +243,7 @@ public function testFlushTriggersEvents() $this->assertTrue($repository->clear()); } - public function testFlushFailureDoesNotDispatchEvent() + public function testFlushFailureDoesDispatchEvent() { $dispatcher = $this->getDispatcher(); @@ -258,6 +259,12 @@ public function testFlushFailureDoesNotDispatchEvent() 'storeName' => 'array', ]) ); + + $dispatcher->shouldReceive('dispatch')->once()->with( + $this->assertEventMatches(CacheFlushFailed::class, [ + 'storeName' => 'array', + ]) + ); $this->assertFalse($repository->clear()); } From 1f184bb6994829a53e9f8c1801ea32849b687880 Mon Sep 17 00:00:00 2001 From: toshitsuna-otsuka Date: Sat, 19 Apr 2025 00:44:40 +0900 Subject: [PATCH 395/455] Fix: Unique lock not being released after transaction rollback in ShouldBeUnique jobs with afterCommit() (#55420) * add a callback after transaction rollback * for unique jobs, release the UniqueLock when a transaction rollback * fix code style --- .../Database/DatabaseTransactionRecord.php | 40 +++++++++ .../Database/DatabaseTransactionsManager.php | 21 +++++ src/Illuminate/Queue/Queue.php | 11 +++ src/Illuminate/Queue/SyncQueue.php | 11 +++ .../DatabaseTransactionsManagerTest.php | 90 +++++++++++++++++++ .../Integration/Queue/QueueConnectionTest.php | 66 ++++++++++++++ tests/Queue/QueueSyncQueueTest.php | 51 +++++++++++ 7 files changed, 290 insertions(+) diff --git a/src/Illuminate/Database/DatabaseTransactionRecord.php b/src/Illuminate/Database/DatabaseTransactionRecord.php index 2afe5dfc1ce1..08fd47132394 100755 --- a/src/Illuminate/Database/DatabaseTransactionRecord.php +++ b/src/Illuminate/Database/DatabaseTransactionRecord.php @@ -32,6 +32,13 @@ class DatabaseTransactionRecord */ protected $callbacks = []; + /** + * The callbacks that should be executed after rollback. + * + * @var array + */ + protected $callbacksForRollback = []; + /** * Create a new database transaction record instance. * @@ -57,6 +64,17 @@ public function addCallback($callback) $this->callbacks[] = $callback; } + /** + * Register a callback to be executed after rollback. + * + * @param callable $callback + * @return void + */ + public function addCallbackForRollback($callback) + { + $this->callbacksForRollback[] = $callback; + } + /** * Execute all of the callbacks. * @@ -69,6 +87,18 @@ public function executeCallbacks() } } + /** + * Execute all of the callbacks for rollback. + * + * @return void + */ + public function executeCallbacksForRollback() + { + foreach ($this->callbacksForRollback as $callback) { + $callback(); + } + } + /** * Get all of the callbacks. * @@ -78,4 +108,14 @@ public function getCallbacks() { return $this->callbacks; } + + /** + * Get all of the callbacks for rollback. + * + * @return array + */ + public function getCallbacksForRollback() + { + return $this->callbacksForRollback; + } } diff --git a/src/Illuminate/Database/DatabaseTransactionsManager.php b/src/Illuminate/Database/DatabaseTransactionsManager.php index f8d639e2a465..9713c66d82f4 100755 --- a/src/Illuminate/Database/DatabaseTransactionsManager.php +++ b/src/Illuminate/Database/DatabaseTransactionsManager.php @@ -139,6 +139,8 @@ public function rollback($connection, $newTransactionLevel) do { $this->removeCommittedTransactionsThatAreChildrenOf($this->currentTransaction[$connection]); + $this->currentTransaction[$connection]->executeCallbacksForRollback(); + $this->currentTransaction[$connection] = $this->currentTransaction[$connection]->parent; } while ( isset($this->currentTransaction[$connection]) && @@ -156,6 +158,12 @@ public function rollback($connection, $newTransactionLevel) */ protected function removeAllTransactionsForConnection($connection) { + if ($this->currentTransaction) { + for ($currentTransaction = $this->currentTransaction[$connection]; isset($currentTransaction); $currentTransaction = $currentTransaction->parent) { + $currentTransaction->executeCallbacksForRollback(); + } + } + $this->currentTransaction[$connection] = null; $this->pendingTransactions = $this->pendingTransactions->reject( @@ -203,6 +211,19 @@ public function addCallback($callback) $callback(); } + /** + * Register a callback for transaction rollback. + * + * @param callable $callback + * @return void + */ + public function addCallbackForRollback($callback) + { + if ($current = $this->callbackApplicableTransactions()->last()) { + return $current->addCallbackForRollback($callback); + } + } + /** * Get the transactions that are applicable to callbacks. * diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 7a00c077204d..a5f831957b09 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -4,9 +4,12 @@ use Closure; use DateTimeInterface; +use Illuminate\Bus\UniqueLock; use Illuminate\Container\Container; +use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Queue\ShouldBeEncrypted; +use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueueAfterCommit; use Illuminate\Queue\Events\JobQueued; use Illuminate\Queue\Events\JobQueueing; @@ -324,6 +327,14 @@ protected function enqueueUsing($job, $payload, $queue, $delay, $callback) { if ($this->shouldDispatchAfterCommit($job) && $this->container->bound('db.transactions')) { + if ($job instanceof ShouldBeUnique) { + $this->container->make('db.transactions')->addCallbackForRollback( + function () use ($job) { + (new UniqueLock($this->container->make(Cache::class)))->release($job); + } + ); + } + return $this->container->make('db.transactions')->addCallback( function () use ($queue, $job, $payload, $delay, $callback) { $this->raiseJobQueueingEvent($queue, $job, $payload, $delay); diff --git a/src/Illuminate/Queue/SyncQueue.php b/src/Illuminate/Queue/SyncQueue.php index 873146da9fe4..b3413d6a5821 100755 --- a/src/Illuminate/Queue/SyncQueue.php +++ b/src/Illuminate/Queue/SyncQueue.php @@ -2,8 +2,11 @@ namespace Illuminate\Queue; +use Illuminate\Bus\UniqueLock; +use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Queue\Job; use Illuminate\Contracts\Queue\Queue as QueueContract; +use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Queue\Events\JobExceptionOccurred; use Illuminate\Queue\Events\JobProcessed; use Illuminate\Queue\Events\JobProcessing; @@ -47,6 +50,14 @@ public function push($job, $data = '', $queue = null) { if ($this->shouldDispatchAfterCommit($job) && $this->container->bound('db.transactions')) { + if ($job instanceof ShouldBeUnique) { + $this->container->make('db.transactions')->addCallbackForRollback( + function () use ($job) { + (new UniqueLock($this->container->make(Cache::class)))->release($job); + } + ); + } + return $this->container->make('db.transactions')->addCallback( fn () => $this->executeJob($job, $data, $queue) ); diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php index 61f7276d92f6..0cf4f8bdc34a 100755 --- a/tests/Database/DatabaseTransactionsManagerTest.php +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -177,6 +177,96 @@ public function testCallbackIsExecutedIfNoTransactions() $this->assertEquals(['default', 1], $callbacks[0]); } + public function testCallbacksForRollbackAreAddedToTheCurrentTransaction() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager); + + $manager->begin('default', 1); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + }); + + $manager->begin('default', 2); + + $manager->begin('admin', 1); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + }); + + $this->assertCount(1, $manager->getPendingTransactions()[0]->getCallbacksForRollback()); + $this->assertCount(0, $manager->getPendingTransactions()[1]->getCallbacksForRollback()); + $this->assertCount(1, $manager->getPendingTransactions()[2]->getCallbacksForRollback()); + } + + public function testRollbackTransactionsExecutesCallbacks() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager); + + $manager->begin('default', 1); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + $callbacks[] = ['default', 1]; + }); + + $manager->begin('default', 2); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + $callbacks[] = ['default', 2]; + }); + + $manager->begin('admin', 1); + + $manager->rollback('default', 1); + $manager->rollback('default', 0); + + $this->assertCount(2, $callbacks); + $this->assertEquals(['default', 2], $callbacks[0]); + $this->assertEquals(['default', 1], $callbacks[1]); + } + + public function testRollbackExecutesOnlyCallbacksOfTheConnection() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager); + + $manager->begin('default', 1); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + $callbacks[] = ['default', 1]; + }); + + $manager->begin('default', 2); + $manager->begin('admin', 1); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + $callbacks[] = ['admin', 1]; + }); + + $manager->rollback('default', 1); + $manager->rollback('default', 0); + + $this->assertCount(1, $callbacks); + $this->assertEquals(['default', 1], $callbacks[0]); + } + + public function testCallbackForRollbackIsNotExecutedIfNoTransactions() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager); + + $manager->addCallbackForRollback(function () use (&$callbacks) { + $callbacks[] = ['default', 1]; + }); + + $this->assertCount(0, $callbacks); + } + public function testStageTransactions() { $manager = (new DatabaseTransactionsManager); diff --git a/tests/Integration/Queue/QueueConnectionTest.php b/tests/Integration/Queue/QueueConnectionTest.php index 7ad7722499a4..35f3596df26b 100644 --- a/tests/Integration/Queue/QueueConnectionTest.php +++ b/tests/Integration/Queue/QueueConnectionTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Integration\Queue; use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\DatabaseTransactionsManager; use Illuminate\Foundation\Bus\Dispatchable; @@ -19,6 +20,7 @@ class QueueConnectionTest extends TestCase protected function tearDown(): void { QueueConnectionTestJob::$ran = false; + QueueConnectionTestUniqueJob::$ran = false; parent::tearDown(); } @@ -28,6 +30,7 @@ public function testJobWontGetDispatchedInsideATransaction() $this->app->singleton('db.transactions', function () { $transactionManager = m::mock(DatabaseTransactionsManager::class); $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldNotReceive('addCallbackForRollback'); return $transactionManager; }); @@ -40,6 +43,7 @@ public function testJobWillGetDispatchedInsideATransactionWhenExplicitlyIndicate $this->app->singleton('db.transactions', function () { $transactionManager = m::mock(DatabaseTransactionsManager::class); $transactionManager->shouldNotReceive('addCallback')->andReturn(null); + $transactionManager->shouldNotReceive('addCallbackForRollback'); return $transactionManager; }); @@ -58,6 +62,7 @@ public function testJobWontGetDispatchedInsideATransactionWhenExplicitlyIndicate $this->app->singleton('db.transactions', function () { $transactionManager = m::mock(DatabaseTransactionsManager::class); $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldNotReceive('addCallbackForRollback'); return $transactionManager; }); @@ -68,6 +73,55 @@ public function testJobWontGetDispatchedInsideATransactionWhenExplicitlyIndicate // This job was dispatched } } + + public function testUniqueJobWontGetDispatchedInsideATransaction() + { + $this->app->singleton('db.transactions', function () { + $transactionManager = m::mock(DatabaseTransactionsManager::class); + $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldReceive('addCallbackForRollback')->once()->andReturn(null); + + return $transactionManager; + }); + + Bus::dispatch(new QueueConnectionTestUniqueJob); + } + + public function testUniqueJobWillGetDispatchedInsideATransactionWhenExplicitlyIndicated() + { + $this->app->singleton('db.transactions', function () { + $transactionManager = m::mock(DatabaseTransactionsManager::class); + $transactionManager->shouldNotReceive('addCallback')->andReturn(null); + $transactionManager->shouldNotReceive('addCallbackForRollback')->andReturn(null); + + return $transactionManager; + }); + + try { + Bus::dispatch((new QueueConnectionTestUniqueJob)->beforeCommit()); + } catch (Throwable) { + // This job was dispatched + } + } + + public function testUniqueJobWontGetDispatchedInsideATransactionWhenExplicitlyIndicated() + { + $this->app['config']->set('queue.connections.sqs.after_commit', false); + + $this->app->singleton('db.transactions', function () { + $transactionManager = m::mock(DatabaseTransactionsManager::class); + $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldReceive('addCallbackForRollback')->once()->andReturn(null); + + return $transactionManager; + }); + + try { + Bus::dispatch((new QueueConnectionTestUniqueJob)->afterCommit()); + } catch (SqsException) { + // This job was dispatched + } + } } class QueueConnectionTestJob implements ShouldQueue @@ -81,3 +135,15 @@ public function handle() static::$ran = true; } } + +class QueueConnectionTestUniqueJob implements ShouldQueue, ShouldBeUnique +{ + use Dispatchable, Queueable; + + public static $ran = false; + + public function handle() + { + static::$ran = true; + } +} diff --git a/tests/Queue/QueueSyncQueueTest.php b/tests/Queue/QueueSyncQueueTest.php index a361bf5e773b..e7aab86ad779 100755 --- a/tests/Queue/QueueSyncQueueTest.php +++ b/tests/Queue/QueueSyncQueueTest.php @@ -6,6 +6,7 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Queue\QueueableEntity; +use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueueAfterCommit; use Illuminate\Database\DatabaseTransactionsManager; @@ -87,6 +88,7 @@ public function testItAddsATransactionCallbackForAfterCommitJobs() $container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class); $transactionManager = m::mock(DatabaseTransactionsManager::class); $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldNotReceive('addCallbackForRollback'); $container->instance('db.transactions', $transactionManager); $sync->setContainer($container); @@ -100,11 +102,40 @@ public function testItAddsATransactionCallbackForInterfaceBasedAfterCommitJobs() $container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class); $transactionManager = m::mock(DatabaseTransactionsManager::class); $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldNotReceive('addCallbackForRollback'); $container->instance('db.transactions', $transactionManager); $sync->setContainer($container); $sync->push(new SyncQueueAfterCommitInterfaceJob()); } + + public function testItAddsATransactionCallbackForAfterCommitUniqueJobs() + { + $sync = new SyncQueue; + $container = new Container; + $container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class); + $transactionManager = m::mock(DatabaseTransactionsManager::class); + $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldReceive('addCallbackForRollback')->once()->andReturn(null); + $container->instance('db.transactions', $transactionManager); + + $sync->setContainer($container); + $sync->push(new SyncQueueAfterCommitUniqueJob()); + } + + public function testItAddsATransactionCallbackForInterfaceBasedAfterCommitUniqueJobs() + { + $sync = new SyncQueue; + $container = new Container; + $container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class); + $transactionManager = m::mock(DatabaseTransactionsManager::class); + $transactionManager->shouldReceive('addCallback')->once()->andReturn(null); + $transactionManager->shouldReceive('addCallbackForRollback')->once()->andReturn(null); + $container->instance('db.transactions', $transactionManager); + + $sync->setContainer($container); + $sync->push(new SyncQueueAfterCommitInterfaceUniqueJob()); + } } class SyncQueueTestEntity implements QueueableEntity @@ -182,3 +213,23 @@ public function handle() { } } + +class SyncQueueAfterCommitUniqueJob implements ShouldBeUnique +{ + use InteractsWithQueue; + + public $afterCommit = true; + + public function handle() + { + } +} + +class SyncQueueAfterCommitInterfaceUniqueJob implements ShouldBeUnique, ShouldQueueAfterCommit +{ + use InteractsWithQueue; + + public function handle() + { + } +} From 60125ea0d12411c44ce688c8e7969632af5d414f Mon Sep 17 00:00:00 2001 From: Italo Date: Fri, 18 Apr 2025 12:17:26 -0400 Subject: [PATCH 396/455] [12.x] Extends `AsCollection` to map items into objects or other values (#55383) * [12.x] Extends AsCollection for map * formatting * fix signature --------- Co-authored-by: Taylor Otwell --- .../Database/Eloquent/Casts/AsCollection.php | 44 +++++++++-- .../Eloquent/Casts/AsEncryptedCollection.php | 42 ++++++++-- .../Database/DatabaseCustomCastsTest.php | 76 +++++++++++++++++++ .../EloquentModelEncryptedCastingTest.php | 53 +++++++++++++ 4 files changed, 204 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php index e71df5a3df3c..e36b13df2184 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php @@ -5,6 +5,7 @@ use Illuminate\Contracts\Database\Eloquent\Castable; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Support\Collection; +use Illuminate\Support\Str; use InvalidArgumentException; class AsCollection implements Castable @@ -21,6 +22,7 @@ public static function castUsing(array $arguments) { public function __construct(protected array $arguments) { + $this->arguments = array_pad(array_values($this->arguments), 2, ''); } public function get($model, $key, $value, $attributes) @@ -31,13 +33,29 @@ public function get($model, $key, $value, $attributes) $data = Json::decode($attributes[$key]); - $collectionClass = $this->arguments[0] ?? Collection::class; + $collectionClass = empty($this->arguments[0]) ? Collection::class : $this->arguments[0]; if (! is_a($collectionClass, Collection::class, true)) { throw new InvalidArgumentException('The provided class must extend ['.Collection::class.'].'); } - return is_array($data) ? new $collectionClass($data) : null; + if (! is_array($data)) { + return null; + } + + $instance = new $collectionClass($data); + + if (! isset($this->arguments[1]) || ! $this->arguments[1]) { + return $instance; + } + + if (is_string($this->arguments[1])) { + $this->arguments[1] = Str::parseCallback($this->arguments[1]); + } + + return is_callable($this->arguments[1]) + ? $instance->map($this->arguments[1]) + : $instance->mapInto($this->arguments[1][0]); } public function set($model, $key, $value, $attributes) @@ -48,13 +66,29 @@ public function set($model, $key, $value, $attributes) } /** - * Specify the collection for the cast. + * Specify the type of object each item in the collection should be mapped to. + * + * @param array{class-string, string}|class-string $map + * @return string + */ + public static function of($map) + { + return static::using('', $map); + } + + /** + * Specify the collection type for the cast. * * @param class-string $class + * @param array{class-string, string}|class-string $map * @return string */ - public static function using($class) + public static function using($class, $map = null) { - return static::class.':'.$class; + if (is_array($map) && is_callable($map)) { + $map = $map[0].'@'.$map[1]; + } + + return static::class.':'.implode(',', [$class, $map]); } } diff --git a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php index a192d2b0c121..b5912fa20b10 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Str; use InvalidArgumentException; class AsEncryptedCollection implements Castable @@ -22,21 +23,34 @@ public static function castUsing(array $arguments) { public function __construct(protected array $arguments) { + $this->arguments = array_pad(array_values($this->arguments), 2, ''); } public function get($model, $key, $value, $attributes) { - $collectionClass = $this->arguments[0] ?? Collection::class; + $collectionClass = empty($this->arguments[0]) ? Collection::class : $this->arguments[0]; if (! is_a($collectionClass, Collection::class, true)) { throw new InvalidArgumentException('The provided class must extend ['.Collection::class.'].'); } - if (isset($attributes[$key])) { - return new $collectionClass(Json::decode(Crypt::decryptString($attributes[$key]))); + if (! isset($attributes[$key])) { + return null; } - return null; + $instance = new $collectionClass(Json::decode(Crypt::decryptString($attributes[$key]))); + + if (! isset($this->arguments[1]) || ! $this->arguments[1]) { + return $instance; + } + + if (is_string($this->arguments[1])) { + $this->arguments[1] = Str::parseCallback($this->arguments[1]); + } + + return is_callable($this->arguments[1]) + ? $instance->map($this->arguments[1]) + : $instance->mapInto($this->arguments[1][0]); } public function set($model, $key, $value, $attributes) @@ -50,14 +64,30 @@ public function set($model, $key, $value, $attributes) }; } + /** + * Specify the type of object each item in the collection should be mapped to. + * + * @param array{class-string, string}|class-string $map + * @return string + */ + public static function of($map) + { + return static::using('', $map); + } + /** * Specify the collection for the cast. * * @param class-string $class + * @param array{class-string, string}|class-string $map * @return string */ - public static function using($class) + public static function using($class, $map = null) { - return static::class.':'.$class; + if (is_array($map) && is_callable($map)) { + $map = $map[0].'@'.$map[1]; + } + + return static::class.':'.implode(',', [$class, $map]); } } diff --git a/tests/Integration/Database/DatabaseCustomCastsTest.php b/tests/Integration/Database/DatabaseCustomCastsTest.php index 0337edf26dcc..ec14a2bf3c49 100644 --- a/tests/Integration/Database/DatabaseCustomCastsTest.php +++ b/tests/Integration/Database/DatabaseCustomCastsTest.php @@ -7,8 +7,10 @@ use Illuminate\Database\Eloquent\Casts\AsStringable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Fluent; use Illuminate\Support\Stringable; class DatabaseCustomCastsTest extends DatabaseTestCase @@ -151,6 +153,68 @@ public function test_custom_casting_nullable_values() $model->array_object_json->toArray() ); } + + public function test_as_collection_with_map_into() + { + $model = new TestEloquentModelWithCustomCasts(); + $model->mergeCasts([ + 'collection' => AsCollection::of(Fluent::class), + ]); + + $model->setRawAttributes([ + 'collection' => json_encode([['foo' => 'bar']]), + ]); + + $this->assertInstanceOf(Fluent::class, $model->collection->first()); + $this->assertSame('bar', $model->collection->first()->foo); + } + + public function test_as_custom_collection_with_map_into() + { + $model = new TestEloquentModelWithCustomCasts(); + $model->mergeCasts([ + 'collection' => AsCollection::using(CustomCollection::class, Fluent::class), + ]); + + $model->setRawAttributes([ + 'collection' => json_encode([['foo' => 'bar']]), + ]); + + $this->assertInstanceOf(CustomCollection::class, $model->collection); + $this->assertInstanceOf(Fluent::class, $model->collection->first()); + $this->assertSame('bar', $model->collection->first()->foo); + } + + public function test_as_collection_with_map_callback(): void + { + $model = new TestEloquentModelWithCustomCasts(); + $model->mergeCasts([ + 'collection' => AsCollection::of([FluentWithCallback::class, 'make']), + ]); + + $model->setRawAttributes([ + 'collection' => json_encode([['foo' => 'bar']]), + ]); + + $this->assertInstanceOf(FluentWithCallback::class, $model->collection->first()); + $this->assertSame('bar', $model->collection->first()->foo); + } + + public function test_as_custom_collection_with_map_callback(): void + { + $model = new TestEloquentModelWithCustomCasts(); + $model->mergeCasts([ + 'collection' => AsCollection::using(CustomCollection::class, [FluentWithCallback::class, 'make']), + ]); + + $model->setRawAttributes([ + 'collection' => json_encode([['foo' => 'bar']]), + ]); + + $this->assertInstanceOf(CustomCollection::class, $model->collection); + $this->assertInstanceOf(FluentWithCallback::class, $model->collection->first()); + $this->assertSame('bar', $model->collection->first()->foo); + } } class TestEloquentModelWithCustomCasts extends Model @@ -197,3 +261,15 @@ class TestEloquentModelWithCustomCastsNullable extends Model 'stringable' => AsStringable::class, ]; } + +class FluentWithCallback extends Fluent +{ + public static function make($attributes = []) + { + return new static($attributes); + } +} + +class CustomCollection extends Collection +{ +} diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index f4a00d3c98ca..0c87c7440022 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -11,6 +11,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Fluent; use stdClass; class EloquentModelEncryptedCastingTest extends DatabaseTestCase @@ -231,6 +232,58 @@ public function testAsEncryptedCollection() $this->assertNull($subject->fresh()->secret_collection); } + public function testAsEncryptedCollectionMap() + { + $this->encrypter->expects('encryptString') + ->twice() + ->with('[{"key1":"value1"}]') + ->andReturn('encrypted-secret-collection-string-1'); + $this->encrypter->expects('encryptString') + ->times(12) + ->with('[{"key1":"value1"},{"key2":"value2"}]') + ->andReturn('encrypted-secret-collection-string-2'); + $this->encrypter->expects('decryptString') + ->once() + ->with('encrypted-secret-collection-string-2') + ->andReturn('[{"key1":"value1"},{"key2":"value2"}]'); + + $subject = new EncryptedCast; + + $subject->mergeCasts(['secret_collection' => AsEncryptedCollection::of(Fluent::class)]); + + $subject->secret_collection = new Collection([new Fluent(['key1' => 'value1'])]); + $subject->secret_collection->push(new Fluent(['key2' => 'value2'])); + + $subject->save(); + + $this->assertInstanceOf(Collection::class, $subject->secret_collection); + $this->assertInstanceOf(Fluent::class, $subject->secret_collection->first()); + $this->assertSame('value1', $subject->secret_collection->get(0)->key1); + $this->assertSame('value2', $subject->secret_collection->get(1)->key2); + $this->assertDatabaseHas('encrypted_casts', [ + 'id' => $subject->id, + 'secret_collection' => 'encrypted-secret-collection-string-2', + ]); + + $subject = $subject->fresh(); + + $this->assertInstanceOf(Collection::class, $subject->secret_collection); + $this->assertInstanceOf(Fluent::class, $subject->secret_collection->first()); + $this->assertSame('value1', $subject->secret_collection->get(0)->key1); + $this->assertSame('value2', $subject->secret_collection->get(1)->key2); + + $subject->secret_collection = null; + $subject->save(); + + $this->assertNull($subject->secret_collection); + $this->assertDatabaseHas('encrypted_casts', [ + 'id' => $subject->id, + 'secret_collection' => null, + ]); + + $this->assertNull($subject->fresh()->secret_collection); + } + public function testAsEncryptedArrayObject() { $this->encrypter->expects('encryptString') From c01bb8d3ea1add70aafaa7f35480ea9d449eec62 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 18 Apr 2025 20:17:46 +0000 Subject: [PATCH 397/455] [12.x] Fix group imports in Blade `@use` directive (#55461) * Fix group imports in Blade `@use` directive * Update CompilesUseStatements.php --------- Co-authored-by: Taylor Otwell --- .../Concerns/CompilesUseStatements.php | 11 +++++++++- tests/View/Blade/BladeUseTest.php | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php b/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php index 8218c9fdf2c6..49a524a5fd9f 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php @@ -12,7 +12,16 @@ trait CompilesUseStatements */ protected function compileUse($expression) { - $segments = explode(',', preg_replace("/[\(\)]/", '', $expression)); + $expression = preg_replace('/[()]/', '', $expression); + + // Preserve grouped imports as-is... + if (str_contains($expression, '{')) { + $use = ltrim(trim($expression, " '\""), '\\'); + + return ""; + } + + $segments = explode(',', $expression); $use = ltrim(trim($segments[0], " '\""), '\\'); $as = isset($segments[1]) ? ' as '.trim($segments[1], " '\"") : ''; diff --git a/tests/View/Blade/BladeUseTest.php b/tests/View/Blade/BladeUseTest.php index ae99825de61e..980a266128a6 100644 --- a/tests/View/Blade/BladeUseTest.php +++ b/tests/View/Blade/BladeUseTest.php @@ -47,4 +47,26 @@ public function testUseStatementsWithBackslashAtBeginningAndAliasedAreCompiled() $string = "Foo @use(\SomeNamespace\SomeClass, Foo) bar"; $this->assertEquals($expected, $this->compiler->compileString($string)); } + + public function testUseStatementsWithBracesAreCompiledCorrectly() + { + $expected = "Foo bar"; + + $string = "Foo @use('SomeNamespace\{Foo, Bar}') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = "Foo @use(SomeNamespace\{Foo, Bar}) bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testUseStatementWithBracesAndBackslashAreCompiledCorrectly() + { + $expected = "Foo bar"; + + $string = "Foo @use('\SomeNamespace\{Foo, Bar}') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = "Foo @use(\SomeNamespace\{Foo, Bar}) bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } } From 064ed2ed302e68e04ac586dfc20ec3ad75f1eb86 Mon Sep 17 00:00:00 2001 From: Konstantin Auffinger <62616071+kauffinger@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:04:54 +0200 Subject: [PATCH 398/455] chore(tests): align test names with idiomatic naming style (#55496) --- tests/Config/RepositoryTest.php | 2 +- tests/Database/DatabaseEloquentModelTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Config/RepositoryTest.php b/tests/Config/RepositoryTest.php index 727918fcb5a6..64cd8ca7b414 100644 --- a/tests/Config/RepositoryTest.php +++ b/tests/Config/RepositoryTest.php @@ -280,7 +280,7 @@ public function testOffsetUnset() $this->assertNull($this->repository->get('associate')); } - public function testsItIsMacroable() + public function testItIsMacroable() { $this->repository->macro('foo', function () { return 'macroable'; diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index ae7b70490e90..d7f6f1538b72 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -3223,7 +3223,7 @@ public function testCastsMethodIsTakenInConsiderationOnSerialization() $this->assertEquals(1, $model->getAttribute('duplicatedAttribute')); } - public function testsCastOnArrayFormatWithOneElement() + public function testCastOnArrayFormatWithOneElement() { $model = new EloquentModelCastingStub; $model->setRawAttributes([ From cea87be67b1f4b2baeb3e7eeccbdcc0d19827c55 Mon Sep 17 00:00:00 2001 From: PizZaKatZe <78648379+pizkaz@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:13:20 +0200 Subject: [PATCH 399/455] Update compiled views only if they actually changed (#55450) * Update compiled views only if they actually changed When running in a read-only filesystem container with views pre-cached at build time, Laravel checks if the cached view's timestamp is older than the source's to decide when to recompile. This is fine as long as we do not make OCI image builds reproducible. If we do however, the timestamps match (because timestamps of all files are set to 01.01.1970), so Laravel recompiles the view, tries to write to a read-only filesystem and the container crashes. This patch computes SHA256 hashes over existing and newly compiled file contents, compares those and writes only if the file actually changes. * Update BladeCompiler.php --------- Co-authored-by: Taylor Otwell --- .../View/Compilers/BladeCompiler.php | 12 ++++++- tests/View/ViewBladeCompilerTest.php | 32 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 48e5d734d90f..b17bde52bce7 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -193,7 +193,17 @@ public function compile($path = null) $compiledPath = $this->getCompiledPath($this->getPath()) ); - $this->files->put($compiledPath, $contents); + if (! $this->files->exists($compiledPath)) { + $this->files->put($compiledPath, $contents); + + return; + } + + $compiledHash = $this->files->hash($compiledPath, 'sha256'); + + if ($compiledHash !== hash('sha256', $contents)) { + $this->files->put($compiledPath, $contents); + } } } diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index c3955945e8ff..e69de4a3f46d 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -66,17 +66,42 @@ public function testCompileCompilesFileAndReturnsContents() $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php')->andReturn(false); $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World'); $compiler->compile('foo'); } public function testCompileCompilesFileAndReturnsContentsCreatingDirectory() { + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); + $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); + $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php')->andReturn(false); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World'); + $compiler->compile('foo'); + } + + public function testCompileUpdatesCacheIfChanged() + { + $compiledPath = __DIR__.'/'.hash('xxh128', 'v2foo').'.php'; + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); + $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); + $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with($compiledPath)->andReturn(true); + $files->shouldReceive('hash')->once()->with($compiledPath, 'sha256')->andReturn(hash('sha256', 'outdated content')); + $files->shouldReceive('put')->once()->with($compiledPath, 'Hello World'); + $compiler->compile('foo'); + } + + public function testCompileKeepsCacheIfUnchanged() + { + $compiledPath = __DIR__.'/'.hash('xxh128', 'v2foo').'.php'; $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(false); $files->shouldReceive('makeDirectory')->once()->with(__DIR__, 0777, true, true); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World'); + $files->shouldReceive('exists')->once()->with($compiledPath)->andReturn(true); + $files->shouldReceive('hash')->once()->with($compiledPath, 'sha256')->andReturn(hash('sha256', 'Hello World')); $compiler->compile('foo'); } @@ -85,6 +110,7 @@ public function testCompileCompilesAndGetThePath() $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php')->andReturn(false); $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World'); $compiler->compile('foo'); $this->assertSame('foo', $compiler->getPath()); @@ -102,6 +128,7 @@ public function testCompileWithPathSetBefore() $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php')->andReturn(false); $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World'); // set path before compilation $compiler->setPath('foo'); @@ -132,6 +159,7 @@ public function testIncludePathToTemplate($content, $compiled) $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn($content); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php')->andReturn(false); $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', $compiled); $compiler->compile('foo'); @@ -187,6 +215,7 @@ public function testDontIncludeEmptyPath() $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('')->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php')->andReturn(false); $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php', 'Hello World'); $compiler->setPath(''); $compiler->compile(); @@ -197,6 +226,7 @@ public function testDontIncludeNullPath() $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with(null)->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php')->andReturn(false); $files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php', 'Hello World'); $compiler->setPath(null); $compiler->compile(); From 3ae99ee61c870c6bebb1a62ded1f3c39388d055a Mon Sep 17 00:00:00 2001 From: cyppe Date: Mon, 21 Apr 2025 16:14:46 +0200 Subject: [PATCH 400/455] Improve performance of Arr::dot method (#55495) --- src/Illuminate/Collections/Arr.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 72562305f251..e4ef759c8f61 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -112,13 +112,19 @@ public static function dot($array, $prepend = '') { $results = []; - foreach ($array as $key => $value) { - if (is_array($value) && ! empty($value)) { - $results = array_merge($results, static::dot($value, $prepend.$key.'.')); - } else { - $results[$prepend.$key] = $value; + $flatten = function ($data, $prefix) use (&$results, &$flatten): void { + foreach ($data as $key => $value) { + $newKey = $prefix.$key; + + if (is_array($value) && ! empty($value)) { + $flatten($value, $newKey.'.'); + } else { + $results[$newKey] = $value; + } } - } + }; + + $flatten($array, $prepend); return $results; } From bea01e404f0ce8a8492774effef22b38827774b9 Mon Sep 17 00:00:00 2001 From: Iman Date: Mon, 21 Apr 2025 17:47:26 +0330 Subject: [PATCH 401/455] add tests for CacheBasedSessionHandler (#55487) --- .../Session/CacheBasedSessionHandlerTest.php | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/Session/CacheBasedSessionHandlerTest.php diff --git a/tests/Session/CacheBasedSessionHandlerTest.php b/tests/Session/CacheBasedSessionHandlerTest.php new file mode 100644 index 000000000000..af6cf68fdc01 --- /dev/null +++ b/tests/Session/CacheBasedSessionHandlerTest.php @@ -0,0 +1,89 @@ +cacheMock = Mockery::mock(CacheContract::class); + $this->sessionHandler = new CacheBasedSessionHandler(cache: $this->cacheMock, minutes: 10); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } + + public function test_open() + { + $result = $this->sessionHandler->open('path', 'session_name'); + $this->assertTrue($result); + } + + public function test_close() + { + $result = $this->sessionHandler->close(); + $this->assertTrue($result); + } + + public function test_read_returns_data_from_cache() + { + $this->cacheMock->shouldReceive('get')->once()->with('session_id', '')->andReturn('session_data'); + + $data = $this->sessionHandler->read(sessionId: 'session_id'); + $this->assertEquals('session_data', $data); + } + + public function test_read_returns_empty_string_if_no_data() + { + $this->cacheMock->shouldReceive('get')->once()->with('some_id', '')->andReturn(''); + + $data = $this->sessionHandler->read(sessionId: 'some_id'); + $this->assertEquals('', $data); + } + + public function test_write_stores_data_in_cache() + { + $this->cacheMock->shouldReceive('put')->once()->with('session_id', 'session_data', 600) // 10 minutes in seconds + ->andReturn(true); + + $result = $this->sessionHandler->write(sessionId: 'session_id', data: 'session_data'); + + $this->assertTrue($result); + } + + public function test_destroy_removes_data_from_cache() + { + $this->cacheMock->shouldReceive('forget')->once()->with('session_id')->andReturn(true); + + $result = $this->sessionHandler->destroy(sessionId: 'session_id'); + + $this->assertTrue($result); + } + + public function test_gc_returns_zero() + { + $result = $this->sessionHandler->gc(lifetime: 120); + + $this->assertEquals(0, $result); + } + + public function test_get_cache_returns_cache_instance() + { + $cacheInstance = $this->sessionHandler->getCache(); + + $this->assertSame($this->cacheMock, $cacheInstance); + } +} From 2abde79f9940af42eda768ce6087eda7b21a0354 Mon Sep 17 00:00:00 2001 From: Iman Date: Mon, 21 Apr 2025 17:48:00 +0330 Subject: [PATCH 402/455] Add tests FileSessionHandler (#55484) --- tests/Session/FileSessionHandlerTest.php | 138 +++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 tests/Session/FileSessionHandlerTest.php diff --git a/tests/Session/FileSessionHandlerTest.php b/tests/Session/FileSessionHandlerTest.php new file mode 100644 index 000000000000..ba27b7019ade --- /dev/null +++ b/tests/Session/FileSessionHandlerTest.php @@ -0,0 +1,138 @@ +files = Mockery::mock(Filesystem::class); + + // Initialize the FileSessionHandler with the mocked Filesystem + $this->sessionHandler = new FileSessionHandler($this->files, '/path/to/sessions', 30); + } + + protected function tearDown(): void + { + Mockery::close(); + } + + public function test_open() + { + $this->assertTrue($this->sessionHandler->open('/path/to/sessions', 'session_name')); + } + + public function test_close() + { + $this->assertTrue($this->sessionHandler->close()); + } + + public function test_read_returns_data_when_file_exists_and_is_valid() + { + $sessionId = 'session_id'; + $path = '/path/to/sessions/'.$sessionId; + Carbon::setTestNow(Carbon::parse('2025-02-02 01:30:00')); + // Set up expectations + $this->files->shouldReceive('isFile')->with($path)->andReturn(true); + + $minutesAgo30 = Carbon::parse('2025-02-02 01:00:00')->getTimestamp(); + $this->files->shouldReceive('lastModified')->with($path)->andReturn($minutesAgo30); + $this->files->shouldReceive('sharedGet')->with($path)->once()->andReturn('session_data'); + + $result = $this->sessionHandler->read($sessionId); + + $this->assertEquals('session_data', $result); + } + + public function test_read_returns_data_when_file_exists_but_expired() + { + $sessionId = 'session_id'; + $path = '/path/to/sessions/'.$sessionId; + Carbon::setTestNow(Carbon::parse('2025-02-02 01:30:01')); + // Set up expectations + $this->files->shouldReceive('isFile')->with($path)->andReturn(true); + + $minutesAgo30 = Carbon::parse('2025-02-02 01:00:00')->getTimestamp(); + $this->files->shouldReceive('lastModified')->with($path)->andReturn($minutesAgo30); + $this->files->shouldReceive('sharedGet')->never(); + + $result = $this->sessionHandler->read($sessionId); + + $this->assertEquals('', $result); + } + + public function test_read_returns_empty_string_when_file_does_not_exist() + { + $sessionId = 'non_existing_session_id'; + $path = '/path/to/sessions/'.$sessionId; + + // Set up expectations + $this->files->shouldReceive('isFile')->with($path)->andReturn(false); + + $result = $this->sessionHandler->read($sessionId); + + $this->assertEquals('', $result); + } + + public function test_write_stores_data() + { + $sessionId = 'session_id'; + $data = 'session_data'; + + // Set up expectations + $this->files->shouldReceive('put')->with('/path/to/sessions/'.$sessionId, $data, true)->once()->andReturn(null); + + $result = $this->sessionHandler->write($sessionId, $data); + + $this->assertTrue($result); + } + + public function test_destroy_deletes_session_file() + { + $sessionId = 'session_id'; + + // Set up expectations + $this->files->shouldReceive('delete')->with('/path/to/sessions/'.$sessionId)->once()->andReturn(null); + + $result = $this->sessionHandler->destroy($sessionId); + + $this->assertTrue($result); + } + + public function test_gc_deletes_old_session_files() + { + $session = new FileSessionHandler($this->files, join_paths(__DIR__, 'tmp'), 30); + // Set up expectations for Filesystem + $this->files->shouldReceive('delete')->with(join_paths(__DIR__, 'tmp', 'a2'))->once()->andReturn(false); + $this->files->shouldReceive('delete')->with(join_paths(__DIR__, 'tmp', 'a3'))->once()->andReturn(true); + + mkdir(__DIR__.'/tmp'); + touch(__DIR__.'/tmp/a1', time() - 3); // last modified: 3 sec ago + touch(__DIR__.'/tmp/a2', time() - 5); // last modified: 5 sec ago + touch(__DIR__.'/tmp/a3', time() - 7); // last modified: 7 sec ago + + // act: + $count = $session->gc(5); + + $this->assertEquals(2, $count); + + unlink(__DIR__.'/tmp/a1'); + unlink(__DIR__.'/tmp/a2'); + unlink(__DIR__.'/tmp/a3'); + + rmdir(__DIR__.'/tmp'); + } +} From 5b1b8c7ec08be6df79f0f430177ea4fde093a0d8 Mon Sep 17 00:00:00 2001 From: Iman Date: Mon, 21 Apr 2025 17:49:05 +0330 Subject: [PATCH 403/455] Add tests DatabaseSessionHandler (#55485) --- .../Session/DatabaseSessionHandlerTest.php | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/Integration/Session/DatabaseSessionHandlerTest.php diff --git a/tests/Integration/Session/DatabaseSessionHandlerTest.php b/tests/Integration/Session/DatabaseSessionHandlerTest.php new file mode 100644 index 000000000000..b6e5856d6067 --- /dev/null +++ b/tests/Integration/Session/DatabaseSessionHandlerTest.php @@ -0,0 +1,113 @@ +app['db']->connection(); + $handler = new DatabaseSessionHandler($connection, 'sessions', 1); + $handler->setContainer($this->app); + + // read non-existing session id: + $this->assertEquals('', $handler->read('invalid_session_id')); + + // open and close: + $this->assertTrue($handler->open('', '')); + $this->assertTrue($handler->close()); + + // write and read: + $this->assertTrue($handler->write('valid_session_id_2425', json_encode(['foo' => 'bar']))); + $this->assertEquals(['foo' => 'bar'], json_decode($handler->read('valid_session_id_2425'), true)); + $this->assertEquals(1, $connection->table('sessions')->count()); + + $session = $connection->table('sessions')->first(); + $this->assertNotNull($session->user_agent); + $this->assertNotNull($session->ip_address); + + // re-write and read: + $this->assertTrue($handler->write('valid_session_id_2425', json_encode(['over' => 'ride']))); + $this->assertEquals(['over' => 'ride'], json_decode($handler->read('valid_session_id_2425'), true)); + $this->assertEquals(1, $connection->table('sessions')->count()); + + // handler object writes only one session id: + $this->assertTrue($handler->write('other_id', 'data')); + $this->assertEquals(1, $connection->table('sessions')->count()); + + $handler->setExists(false); + $this->assertTrue($handler->write('other_id', 'data')); + $this->assertEquals(2, $connection->table('sessions')->count()); + + // read expired: + Carbon::setTestNow(Carbon::now()->addMinutes(2)); + $this->assertEquals('', $handler->read('valid_session_id_2425')); + + // rewriting an expired session-id, makes it live: + $this->assertTrue($handler->write('valid_session_id_2425', json_encode(['come' => 'alive']))); + $this->assertEquals(['come' => 'alive'], json_decode($handler->read('valid_session_id_2425'), true)); + } + + public function test_garbage_collector() + { + $connection = $this->app['db']->connection(); + + $handler = new DatabaseSessionHandler($connection, 'sessions', 1, $this->app); + $handler->write('simple_id_1', 'abcd'); + $this->assertEquals(0, $handler->gc(1)); + + Carbon::setTestNow(Carbon::now()->addSeconds(2)); + + $handler = new DatabaseSessionHandler($connection, 'sessions', 1, $this->app); + $handler->write('simple_id_2', 'abcd'); + $this->assertEquals(1, $handler->gc(2)); + $this->assertEquals(1, $connection->table('sessions')->count()); + + Carbon::setTestNow(Carbon::now()->addSeconds(2)); + + $this->assertEquals(1, $handler->gc(1)); + $this->assertEquals(0, $connection->table('sessions')->count()); + } + + public function test_destroy() + { + $connection = $this->app['db']->connection(); + $handler1 = new DatabaseSessionHandler($connection, 'sessions', 1, $this->app); + $handler2 = clone $handler1; + + $handler1->write('id_1', 'some data'); + $handler2->write('id_2', 'some data'); + + // destroy invalid session-id: + $this->assertEquals(true, $handler1->destroy('invalid_session_id')); + // nothing deleted: + $this->assertEquals(2, $connection->table('sessions')->count()); + + // destroy valid session-id: + $this->assertEquals(true, $handler2->destroy('id_1')); + // only one row is deleted: + $this->assertEquals(1, $connection->table('sessions')->where('id', 'id_2')->count()); + } + + public function test_it_can_work_without_container() + { + $connection = $this->app['db']->connection(); + $handler = new DatabaseSessionHandler($connection, 'sessions', 1); + + // write and read: + $this->assertTrue($handler->write('session_id', 'some data')); + $this->assertEquals('some data', $handler->read('session_id')); + $this->assertEquals(1, $connection->table('sessions')->count()); + + $session = $connection->table('sessions')->first(); + $this->assertNull($session->user_agent); + $this->assertNull($session->ip_address); + $this->assertNull($session->user_id); + } +} From 3073c3a54e690f12b885921eb7cf0682f17b0ec5 Mon Sep 17 00:00:00 2001 From: Amir Alizadeh Date: Mon, 21 Apr 2025 17:57:56 +0330 Subject: [PATCH 404/455] Fix many to many detach without ids broken with custom pivot class (#55490) --- .../Concerns/InteractsWithPivotTable.php | 17 ++------ .../Database/EloquentBelongsToManyTest.php | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 454d79379195..8de013a1a38a 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -470,21 +470,10 @@ protected function detachUsingCustomClass($ids) { $results = 0; - if (! empty($this->pivotWheres) || - ! empty($this->pivotWhereIns) || - ! empty($this->pivotWhereNulls)) { - $records = $this->getCurrentlyAttachedPivotsForIds($ids); + $records = $this->getCurrentlyAttachedPivotsForIds($ids); - foreach ($records as $record) { - $results += $record->delete(); - } - } else { - foreach ($this->parseIds($ids) as $id) { - $results += $this->newPivot([ - $this->foreignPivotKey => $this->parent->{$this->parentKey}, - $this->relatedPivotKey => $id, - ], true)->delete(); - } + foreach ($records as $record) { + $results += $record->delete(); } return $results; diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 3f00341da5a1..c104e0e05026 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -336,6 +336,49 @@ public function testDetachMethod() $this->assertCount(0, $post->tags); } + public function testDetachMethodWithCustomPivot() + { + $post = Post::create(['title' => Str::random()]); + + $tag = Tag::create(['name' => Str::random()]); + $tag2 = Tag::create(['name' => Str::random()]); + $tag3 = Tag::create(['name' => Str::random()]); + $tag4 = Tag::create(['name' => Str::random()]); + $tag5 = Tag::create(['name' => Str::random()]); + Tag::create(['name' => Str::random()]); + Tag::create(['name' => Str::random()]); + + $post->tagsWithCustomPivot()->attach(Tag::all()); + + $this->assertEquals(Tag::pluck('name'), $post->tags->pluck('name')); + + $post->tagsWithCustomPivot()->detach($tag->id); + $post->load('tagsWithCustomPivot'); + $this->assertEquals( + Tag::whereNotIn('id', [$tag->id])->pluck('name'), + $post->tagsWithCustomPivot->pluck('name') + ); + + $post->tagsWithCustomPivot()->detach([$tag2->id, $tag3->id]); + $post->load('tagsWithCustomPivot'); + $this->assertEquals( + Tag::whereNotIn('id', [$tag->id, $tag2->id, $tag3->id])->pluck('name'), + $post->tagsWithCustomPivot->pluck('name') + ); + + $post->tagsWithCustomPivot()->detach(new Collection([$tag4, $tag5])); + $post->load('tagsWithCustomPivot'); + $this->assertEquals( + Tag::whereNotIn('id', [$tag->id, $tag2->id, $tag3->id, $tag4->id, $tag5->id])->pluck('name'), + $post->tagsWithCustomPivot->pluck('name') + ); + + $this->assertCount(2, $post->tagsWithCustomPivot); + $post->tagsWithCustomPivot()->detach(); + $post->load('tagsWithCustomPivot'); + $this->assertCount(0, $post->tagsWithCustomPivot); + } + public function testFirstMethod() { $post = Post::create(['title' => Str::random()]); From b6a2af2b96b1088228aa496e376b3c19ba987052 Mon Sep 17 00:00:00 2001 From: Mahesh Perera Date: Mon, 21 Apr 2025 20:02:30 +0530 Subject: [PATCH 405/455] [12.x] Support nested relations on `relationLoaded` method (#55471) * relationLoaded method in Model now supports nested relations * Removed argument type hint and return type * Improved readability and added edge case safety * Improved performance --- .../Eloquent/Concerns/HasRelationships.php | 23 ++- .../EloquentModelRelationLoadedTest.php | 168 ++++++++++++++++++ 2 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Database/EloquentModelRelationLoadedTest.php diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 79a2f5d98cd0..6893c1284e3f 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -1072,7 +1072,28 @@ public function getRelation($relation) */ public function relationLoaded($key) { - return array_key_exists($key, $this->relations); + if (array_key_exists($key, $this->relations)) { + return true; + } + + [$relation, $nestedRelation] = array_replace( + [null, null], + explode('.', $key, 2), + ); + + if (! array_key_exists($relation, $this->relations)) { + return false; + } + + if ($nestedRelation !== null) { + foreach ($this->$relation as $related) { + if (! $related->relationLoaded($nestedRelation)) { + return false; + } + } + } + + return true; } /** diff --git a/tests/Integration/Database/EloquentModelRelationLoadedTest.php b/tests/Integration/Database/EloquentModelRelationLoadedTest.php new file mode 100644 index 000000000000..06a0a740d3ba --- /dev/null +++ b/tests/Integration/Database/EloquentModelRelationLoadedTest.php @@ -0,0 +1,168 @@ +increments('id'); + }); + + Schema::create('twos', function (Blueprint $table) { + $table->increments('id'); + $table->integer('one_id'); + }); + + Schema::create('threes', function (Blueprint $table) { + $table->increments('id'); + $table->integer('two_id'); + $table->integer('one_id')->nullable(); + }); + } + + public function testWhenRelationIsInvalid() + { + $one = One::query()->create(); + $one->twos()->create(); + + $model = One::query() + ->with('twos') + ->find($one->id); + + $this->assertFalse($model->relationLoaded('.')); + $this->assertFalse($model->relationLoaded('invalid')); + } + + public function testWhenNestedRelationIsInvalid() + { + $one = One::query()->create(); + $one->twos()->create(); + + $model = One::query() + ->with('twos') + ->find($one->id); + + $this->assertFalse($model->relationLoaded('twos.')); + $this->assertFalse($model->relationLoaded('twos.invalid')); + } + + public function testWhenRelationNotLoaded() + { + $one = One::query()->create(); + $one->twos()->create(); + + $model = One::query()->find($one->id); + + $this->assertFalse($model->relationLoaded('twos')); + } + + public function testWhenRelationLoaded() + { + $one = One::query()->create(); + $one->twos()->create(); + + $model = One::query() + ->with('twos') + ->find($one->id); + + $this->assertTrue($model->relationLoaded('twos')); + } + + public function testWhenChildRelationIsNotLoaded() + { + $one = One::query()->create(); + $two = $one->twos()->create(); + $two->threes()->create(); + + $model = One::query() + ->with('twos') + ->find($one->id); + + $this->assertTrue($model->relationLoaded('twos')); + $this->assertFalse($model->relationLoaded('twos.threes')); + } + + public function testWhenChildRelationIsLoaded() + { + $one = One::query()->create(); + $two = $one->twos()->create(); + $two->threes()->create(); + + $model = One::query() + ->with('twos.threes') + ->find($one->id); + + $this->assertTrue($model->relationLoaded('twos')); + $this->assertTrue($model->relationLoaded('twos.threes')); + } + + public function testWhenChildRecursiveRelationIsLoaded() + { + $one = One::query()->create(); + $two = $one->twos()->create(); + $two->threes()->create(['one_id' => $one->id]); + + $model = One::query() + ->with('twos.threes.one') + ->find($one->id); + + $this->assertTrue($model->relationLoaded('twos')); + $this->assertTrue($model->relationLoaded('twos.threes')); + $this->assertTrue($model->relationLoaded('twos.threes.one')); + } +} + +class One extends Model +{ + public $table = 'ones'; + public $timestamps = false; + protected $guarded = []; + + public function twos(): HasMany + { + return $this->hasMany(Two::class, 'one_id'); + } +} + +class Two extends Model +{ + public $table = 'twos'; + public $timestamps = false; + protected $guarded = []; + + public function one(): BelongsTo + { + return $this->belongsTo(One::class, 'one_id'); + } + + public function threes(): HasMany + { + return $this->hasMany(Three::class, 'two_id'); + } +} + +class Three extends Model +{ + public $table = 'threes'; + public $timestamps = false; + protected $guarded = []; + + public function one(): BelongsTo + { + return $this->belongsTo(One::class, 'one_id'); + } + + public function two(): BelongsTo + { + return $this->belongsTo(Two::class, 'two_id'); + } +} From 84753fc380475f81278dc045cda98a975e70bc1f Mon Sep 17 00:00:00 2001 From: Ben McKay Date: Tue, 22 Apr 2025 08:45:35 -0500 Subject: [PATCH 406/455] Bugfix for Cache::memo()->many() returning the wrong value with an integer key type (#55503) * Update MemoizedStore.php to maintain key types Bugfix for https://github.com/laravel/framework/issues/55500 * Styling Fix * Style Fix * Add tests * Remove redundant `all` call * Make fall back strict * Improve tests * Style fix * Update tests/Integration/Cache/MemoizedStoreTest.php * Update MemoizedStore.php --------- Co-authored-by: Tim MacDonald Co-authored-by: Taylor Otwell --- src/Illuminate/Cache/MemoizedStore.php | 15 +++++++---- tests/Integration/Cache/MemoizedStoreTest.php | 27 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Cache/MemoizedStore.php b/src/Illuminate/Cache/MemoizedStore.php index 9888810de6d7..d899ef09d609 100644 --- a/src/Illuminate/Cache/MemoizedStore.php +++ b/src/Illuminate/Cache/MemoizedStore.php @@ -75,12 +75,17 @@ public function many(array $keys) }); } - $result = [ - ...$memoized, - ...$retrieved, - ]; + $result = []; - return array_replace(array_flip($keys), $result); + foreach ($keys as $key) { + if (array_key_exists($key, $memoized)) { + $result[$key] = $memoized[$key]; + } else { + $result[$key] = $retrieved[$key]; + } + } + + return $result; } /** diff --git a/tests/Integration/Cache/MemoizedStoreTest.php b/tests/Integration/Cache/MemoizedStoreTest.php index e599f83225d0..028688b262e2 100644 --- a/tests/Integration/Cache/MemoizedStoreTest.php +++ b/tests/Integration/Cache/MemoizedStoreTest.php @@ -89,6 +89,33 @@ public function test_it_can_memoize_when_retrieving_mulitple_values() $this->assertSame(['name.0' => 'Tim', 'name.1' => 'Taylor'], $memoized); } + public function test_it_uses_correct_keys_for_getMultiple() + { + $data = [ + 'a' => 'string-value', + '1.1' => 'float-value', + '1' => 'integer-value-as-string', + 2 => 'integer-value', + ]; + Cache::putMany($data); + + $memoValue = Cache::memo()->many(['a', '1.1', '1', 2]); + $cacheValue = Cache::many(['a', '1.1', '1', 2]); + + $this->assertSame([ + 'a' => 'string-value', + '1.1' => 'float-value', + '1' => 'integer-value-as-string', + 2 => 'integer-value', + ], $cacheValue); + $this->assertSame($cacheValue, $memoValue); + + // ensure correct on the second memoized retrieval + $memoValue = Cache::memo()->many(['a', '1.1', '1', 2]); + + $this->assertSame($cacheValue, $memoValue); + } + public function test_null_values_are_memoized_when_retrieving_mulitple_values() { $live = Cache::getMultiple(['name.0', 'name.1']); From 9acd22e5ace969801877227c2fa9b17d24210c18 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Tue, 22 Apr 2025 09:50:14 -0400 Subject: [PATCH 407/455] [12.x] Allow Container to build `Migrator` from class name (#55501) * allow building Migrator from class name * bind Migrator * remove unneeded change * remove unneeded change * Update MigrationServiceProvider.php --------- Co-authored-by: Taylor Otwell --- .../Database/MigrationServiceProvider.php | 4 +++- .../Database/MigrationServiceProviderTest.php | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Database/MigrationServiceProviderTest.php diff --git a/src/Illuminate/Database/MigrationServiceProvider.php b/src/Illuminate/Database/MigrationServiceProvider.php index cab266bb2f9d..037106c73579 100755 --- a/src/Illuminate/Database/MigrationServiceProvider.php +++ b/src/Illuminate/Database/MigrationServiceProvider.php @@ -82,6 +82,8 @@ protected function registerMigrator() return new Migrator($repository, $app['db'], $app['files'], $app['events']); }); + + $this->app->bind(Migrator::class, fn ($app) => $app['migrator']); } /** @@ -220,7 +222,7 @@ protected function registerMigrateStatusCommand() public function provides() { return array_merge([ - 'migrator', 'migration.repository', 'migration.creator', + 'migrator', 'migration.repository', 'migration.creator', Migrator::class, ], array_values($this->commands)); } } diff --git a/tests/Integration/Database/MigrationServiceProviderTest.php b/tests/Integration/Database/MigrationServiceProviderTest.php new file mode 100644 index 000000000000..6da602074f39 --- /dev/null +++ b/tests/Integration/Database/MigrationServiceProviderTest.php @@ -0,0 +1,16 @@ +app->make('migrator'); + $fromClass = $this->app->make(Migrator::class); + + $this->assertSame($fromString, $fromClass); + } +} From be0d6f39e18dd28d29f5dd2819a6c02eba61b7e5 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:55:18 +0000 Subject: [PATCH 408/455] Update version to v12.10.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 4a5fd27bf711..f06a87f63c1e 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.9.2'; + const VERSION = '12.10.0'; /** * The base path for the Laravel installation. From 3faeb0726cb55b4f672bf549cc93b716545b84c2 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:57:05 +0000 Subject: [PATCH 409/455] Update CHANGELOG --- CHANGELOG.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 369bc45486d8..0caa4b2b4d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,30 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.9.2...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.10.0...12.x) + +## [v12.10.0](https://github.com/laravel/framework/compare/v12.9.2...v12.10.0) - 2025-04-22 + +* Use value() helper in 'when' method by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55465 +* [12.x] Test `@use` directive without quotes by [@osbre](https://github.com/osbre) in https://github.com/laravel/framework/pull/55462 +* [12.x] Enhance Broadcast Events Test Coverage by [@roshandelpoor](https://github.com/roshandelpoor) in https://github.com/laravel/framework/pull/55458 +* [12.x] Add `Conditionable` Trait to `Fluent` by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/55455 +* [12.x] Fix relation auto loading with manually set relations by [@patrickweh](https://github.com/patrickweh) in https://github.com/laravel/framework/pull/55452 +* Add missing types to RateLimiter by [@ClaudioEyzaguirre](https://github.com/ClaudioEyzaguirre) in https://github.com/laravel/framework/pull/55445 +* [12.x] Fix for global autoload relationships not working in certain cases by [@litvinchuk](https://github.com/litvinchuk) in https://github.com/laravel/framework/pull/55443 +* [12.x] Fix adding `setTags` method on new cache flush events by [@erikn69](https://github.com/erikn69) in https://github.com/laravel/framework/pull/55405 +* Fix: Unique lock not being released after transaction rollback in ShouldBeUnique jobs with afterCommit() by [@toshitsuna-otsuka](https://github.com/toshitsuna-otsuka) in https://github.com/laravel/framework/pull/55420 +* [12.x] Extends `AsCollection` to map items into objects or other values by [@DarkGhostHunter](https://github.com/DarkGhostHunter) in https://github.com/laravel/framework/pull/55383 +* [12.x] Fix group imports in Blade `@use` directive by [@osbre](https://github.com/osbre) in https://github.com/laravel/framework/pull/55461 +* chore(tests): align test names with idiomatic naming style by [@kauffinger](https://github.com/kauffinger) in https://github.com/laravel/framework/pull/55496 +* Update compiled views only if they actually changed by [@pizkaz](https://github.com/pizkaz) in https://github.com/laravel/framework/pull/55450 +* Improve performance of Arr::dot method - 300x in some cases by [@cyppe](https://github.com/cyppe) in https://github.com/laravel/framework/pull/55495 +* [12.x] Add tests for `CacheBasedSessionHandler` by [@imanghafoori1](https://github.com/imanghafoori1) in https://github.com/laravel/framework/pull/55487 +* [12.x] Add tests for `FileSessionHandler` by [@imanghafoori1](https://github.com/imanghafoori1) in https://github.com/laravel/framework/pull/55484 +* [12.x] Add tests for `DatabaseSessionHandler` by [@imanghafoori1](https://github.com/imanghafoori1) in https://github.com/laravel/framework/pull/55485 +* [12.x] Fix many to many detach without IDs broken with custom pivot class by [@amir9480](https://github.com/amir9480) in https://github.com/laravel/framework/pull/55490 +* [12.x] Support nested relations on `relationLoaded` method by [@tmsperera](https://github.com/tmsperera) in https://github.com/laravel/framework/pull/55471 +* Bugfix for Cache::memo()->many() returning the wrong value with an integer key type by [@bmckay959](https://github.com/bmckay959) in https://github.com/laravel/framework/pull/55503 +* [12.x] Allow Container to build `Migrator` from class name by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55501 ## [v12.9.2](https://github.com/laravel/framework/compare/v12.9.1...v12.9.2) - 2025-04-16 From 9ee0795b6917a46ca933b0add4902a6a3280d1dc Mon Sep 17 00:00:00 2001 From: mohammadrasoulasghari <112411294+mohammadrasoulasghari@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:29:28 +0330 Subject: [PATCH 410/455] Revert "Use value() helper in 'when' method to simplify code (#55465)" (#55514) This reverts commit 48347e54408adfa82afe40fefaa16cd5eeea4865. --- src/Illuminate/Conditionable/Traits/Conditionable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Conditionable/Traits/Conditionable.php b/src/Illuminate/Conditionable/Traits/Conditionable.php index 7bc394c5f6c7..5e3194bbcb6a 100644 --- a/src/Illuminate/Conditionable/Traits/Conditionable.php +++ b/src/Illuminate/Conditionable/Traits/Conditionable.php @@ -20,7 +20,7 @@ trait Conditionable */ public function when($value = null, ?callable $callback = null, ?callable $default = null) { - $value = value($value, $this); + $value = $value instanceof Closure ? $value($this) : $value; if (func_num_args() === 0) { return new HigherOrderWhenProxy($this); From c65ac53d783f630318dddf639e3d28ee9f0ccd94 Mon Sep 17 00:00:00 2001 From: Shawn Lindstrom Date: Wed, 23 Apr 2025 08:59:43 -0400 Subject: [PATCH 411/455] Use xxh128 when comparing views for changes (#55517) Co-authored-by: Shawn Lindstrom --- src/Illuminate/View/Compilers/BladeCompiler.php | 4 ++-- tests/View/ViewBladeCompilerTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index b17bde52bce7..883eb16c4582 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -199,9 +199,9 @@ public function compile($path = null) return; } - $compiledHash = $this->files->hash($compiledPath, 'sha256'); + $compiledHash = $this->files->hash($compiledPath, 'xxh128'); - if ($compiledHash !== hash('sha256', $contents)) { + if ($compiledHash !== hash('xxh128', $contents)) { $this->files->put($compiledPath, $contents); } } diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index e69de4a3f46d..ed59a62fbbe7 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -88,7 +88,7 @@ public function testCompileUpdatesCacheIfChanged() $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true); $files->shouldReceive('exists')->once()->with($compiledPath)->andReturn(true); - $files->shouldReceive('hash')->once()->with($compiledPath, 'sha256')->andReturn(hash('sha256', 'outdated content')); + $files->shouldReceive('hash')->once()->with($compiledPath, 'xxh128')->andReturn(hash('xxh128', 'outdated content')); $files->shouldReceive('put')->once()->with($compiledPath, 'Hello World'); $compiler->compile('foo'); } @@ -101,7 +101,7 @@ public function testCompileKeepsCacheIfUnchanged() $files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(false); $files->shouldReceive('makeDirectory')->once()->with(__DIR__, 0777, true, true); $files->shouldReceive('exists')->once()->with($compiledPath)->andReturn(true); - $files->shouldReceive('hash')->once()->with($compiledPath, 'sha256')->andReturn(hash('sha256', 'Hello World')); + $files->shouldReceive('hash')->once()->with($compiledPath, 'xxh128')->andReturn(hash('xxh128', 'Hello World')); $compiler->compile('foo'); } From 63b4d72f0a5cb656bbc303353a4fa8dc48e021f8 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Wed, 23 Apr 2025 10:13:45 -0300 Subject: [PATCH 412/455] [12.x] Ensure related models is iterable on `HasRelationships@relationLoaded()` (#55519) * ensure related models is iterable * add test case --- .../Eloquent/Concerns/HasRelationships.php | 6 +++++- .../Database/EloquentModelRelationLoadedTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 6893c1284e3f..fc211e179a53 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -1086,7 +1086,11 @@ public function relationLoaded($key) } if ($nestedRelation !== null) { - foreach ($this->$relation as $related) { + $relatedModels = is_iterable($relatedModels = $this->$relation) + ? $relatedModels + : [$relatedModels]; + + foreach ($relatedModels as $related) { if (! $related->relationLoaded($nestedRelation)) { return false; } diff --git a/tests/Integration/Database/EloquentModelRelationLoadedTest.php b/tests/Integration/Database/EloquentModelRelationLoadedTest.php index 06a0a740d3ba..548a50d11957 100644 --- a/tests/Integration/Database/EloquentModelRelationLoadedTest.php +++ b/tests/Integration/Database/EloquentModelRelationLoadedTest.php @@ -119,6 +119,22 @@ public function testWhenChildRecursiveRelationIsLoaded() $this->assertTrue($model->relationLoaded('twos.threes')); $this->assertTrue($model->relationLoaded('twos.threes.one')); } + + public function testWhenParentRelationIsASingleInstance() + { + $one = One::query()->create(); + $two = $one->twos()->create(); + $three = $two->threes()->create(); + + $model = Three::query() + ->with('two.one') + ->find($three->id); + + $this->assertTrue($model->relationLoaded('two')); + $this->assertTrue($model->two->is($two)); + $this->assertTrue($model->relationLoaded('two.one')); + $this->assertTrue($model->two->one->is($one)); + } } class One extends Model From 573684fa403bef4eb58ee7c3cd9b656fd67848e5 Mon Sep 17 00:00:00 2001 From: Azim Kordpour Date: Wed, 23 Apr 2025 15:17:11 +0200 Subject: [PATCH 413/455] [12.x] Add Enum support for assertJsonPath in AssertableJsonString.php (#55516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Enum support for assertJsonPath in AssertableJsonString.php * Fix code style in assertJsonPath * Use enum_value in assertPath Co-authored-by: Sebastian Hädrich <11225821+shaedrich@users.noreply.github.com> * Import enum_value in AssertableJsonString --------- Co-authored-by: Sebastian Hädrich <11225821+shaedrich@users.noreply.github.com> --- .../Testing/AssertableJsonString.php | 4 ++- tests/Testing/TestResponseTest.php | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/AssertableJsonString.php b/src/Illuminate/Testing/AssertableJsonString.php index 0bf221bea0da..d089ab071dc3 100644 --- a/src/Illuminate/Testing/AssertableJsonString.php +++ b/src/Illuminate/Testing/AssertableJsonString.php @@ -12,6 +12,8 @@ use Illuminate\Testing\Assert as PHPUnit; use JsonSerializable; +use function Illuminate\Support\enum_value; + class AssertableJsonString implements ArrayAccess, Countable { /** @@ -238,7 +240,7 @@ public function assertPath($path, $expect) if ($expect instanceof Closure) { PHPUnit::assertTrue($expect($this->json($path))); } else { - PHPUnit::assertSame($expect, $this->json($path)); + PHPUnit::assertSame(enum_value($expect), $this->json($path)); } return $this; diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 9de88ddff3f3..cae497bdd133 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1437,6 +1437,27 @@ public function testAssertJsonPathWithClosureCanFail() $response->assertJsonPath('data.foo', fn ($value) => $value === null); } + public function testAssertJsonPathWithEnum() + { + $response = TestResponse::fromBaseResponse(new Response([ + 'data' => ['status' => 'booked'], + ])); + + $response->assertJsonPath('data.status', TestStatus::Booked); + } + + public function testAssertJsonPathWithEnumCanFail() + { + $response = TestResponse::fromBaseResponse(new Response([ + 'data' => ['status' => 'failed'], + ])); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that two strings are identical.'); + + $response->assertJsonPath('data.status', TestStatus::Booked); + } + public function testAssertJsonPathCanonicalizing() { $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableSingleResourceStub)); @@ -2954,3 +2975,8 @@ class AnotherTestModel extends Model { protected $guarded = []; } + +enum TestStatus: string +{ + case Booked = 'booked'; +} From 3264999c3123f55b7651c275efb6942034c47eda Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:49:24 +0000 Subject: [PATCH 414/455] Update version to v12.10.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index f06a87f63c1e..fb6f7548a34c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.10.0'; + const VERSION = '12.10.1'; /** * The base path for the Laravel installation. From 44e6a294e4441e9e3338008af0288979b3f677e8 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:50:58 +0000 Subject: [PATCH 415/455] Update CHANGELOG --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0caa4b2b4d2e..0c196a99d749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.10.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.10.1...12.x) + +## [v12.10.1](https://github.com/laravel/framework/compare/v12.10.0...v12.10.1) - 2025-04-23 + +* Revert "Use value() helper in 'when' method to simplify code" #55465 by [@mohammadrasoulasghari](https://github.com/mohammadrasoulasghari) in https://github.com/laravel/framework/pull/55514 +* [12.x] Use xxh128 when comparing views for changes by [@shawnlindstrom](https://github.com/shawnlindstrom) in https://github.com/laravel/framework/pull/55517 +* [12.x] Ensure related models is iterable on `HasRelationships@relationLoaded()` by [@rodrigopedra](https://github.com/rodrigopedra) in https://github.com/laravel/framework/pull/55519 +* [12.x] Add Enum support for assertJsonPath in AssertableJsonString.php by [@azim-kordpour](https://github.com/azim-kordpour) in https://github.com/laravel/framework/pull/55516 ## [v12.10.0](https://github.com/laravel/framework/compare/v12.9.2...v12.10.0) - 2025-04-22 From f5fba9cb1aea3ae9963d9958e1ce6d2e9715d316 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Thu, 24 Apr 2025 11:05:39 -0300 Subject: [PATCH 416/455] [12.x] Address Model@relationLoaded when relation is null (#55531) * address when relation is null * added tests and return false when $relatedModels is empty --- .../Eloquent/Concerns/HasRelationships.php | 6 +++++- .../Database/EloquentModelRelationLoadedTest.php | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index fc211e179a53..b27b71109096 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -1088,7 +1088,11 @@ public function relationLoaded($key) if ($nestedRelation !== null) { $relatedModels = is_iterable($relatedModels = $this->$relation) ? $relatedModels - : [$relatedModels]; + : array_filter([$relatedModels]); + + if (count($relatedModels) === 0) { + return false; + } foreach ($relatedModels as $related) { if (! $related->relationLoaded($nestedRelation)) { diff --git a/tests/Integration/Database/EloquentModelRelationLoadedTest.php b/tests/Integration/Database/EloquentModelRelationLoadedTest.php index 548a50d11957..265926d9cd4c 100644 --- a/tests/Integration/Database/EloquentModelRelationLoadedTest.php +++ b/tests/Integration/Database/EloquentModelRelationLoadedTest.php @@ -135,6 +135,21 @@ public function testWhenParentRelationIsASingleInstance() $this->assertTrue($model->relationLoaded('two.one')); $this->assertTrue($model->two->one->is($one)); } + + public function testWhenRelationIsNull() + { + $one = One::query()->create(); + $two = $one->twos()->create(); + $three = $two->threes()->create(); + + $model = Three::query() + ->with('one.twos') + ->find($three->id); + + $this->assertTrue($model->relationLoaded('one')); + $this->assertNull($model->one); + $this->assertFalse($model->relationLoaded('one.twos')); + } } class One extends Model From dc5b445c0a9aa794f3b6d04b3bf10ed5b00c7814 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 24 Apr 2025 09:07:27 -0500 Subject: [PATCH 417/455] revert complicated changes --- .../Eloquent/Concerns/HasRelationships.php | 31 +-- .../EloquentModelRelationLoadedTest.php | 199 ------------------ 2 files changed, 1 insertion(+), 229 deletions(-) delete mode 100644 tests/Integration/Database/EloquentModelRelationLoadedTest.php diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index b27b71109096..79a2f5d98cd0 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -1072,36 +1072,7 @@ public function getRelation($relation) */ public function relationLoaded($key) { - if (array_key_exists($key, $this->relations)) { - return true; - } - - [$relation, $nestedRelation] = array_replace( - [null, null], - explode('.', $key, 2), - ); - - if (! array_key_exists($relation, $this->relations)) { - return false; - } - - if ($nestedRelation !== null) { - $relatedModels = is_iterable($relatedModels = $this->$relation) - ? $relatedModels - : array_filter([$relatedModels]); - - if (count($relatedModels) === 0) { - return false; - } - - foreach ($relatedModels as $related) { - if (! $related->relationLoaded($nestedRelation)) { - return false; - } - } - } - - return true; + return array_key_exists($key, $this->relations); } /** diff --git a/tests/Integration/Database/EloquentModelRelationLoadedTest.php b/tests/Integration/Database/EloquentModelRelationLoadedTest.php deleted file mode 100644 index 265926d9cd4c..000000000000 --- a/tests/Integration/Database/EloquentModelRelationLoadedTest.php +++ /dev/null @@ -1,199 +0,0 @@ -increments('id'); - }); - - Schema::create('twos', function (Blueprint $table) { - $table->increments('id'); - $table->integer('one_id'); - }); - - Schema::create('threes', function (Blueprint $table) { - $table->increments('id'); - $table->integer('two_id'); - $table->integer('one_id')->nullable(); - }); - } - - public function testWhenRelationIsInvalid() - { - $one = One::query()->create(); - $one->twos()->create(); - - $model = One::query() - ->with('twos') - ->find($one->id); - - $this->assertFalse($model->relationLoaded('.')); - $this->assertFalse($model->relationLoaded('invalid')); - } - - public function testWhenNestedRelationIsInvalid() - { - $one = One::query()->create(); - $one->twos()->create(); - - $model = One::query() - ->with('twos') - ->find($one->id); - - $this->assertFalse($model->relationLoaded('twos.')); - $this->assertFalse($model->relationLoaded('twos.invalid')); - } - - public function testWhenRelationNotLoaded() - { - $one = One::query()->create(); - $one->twos()->create(); - - $model = One::query()->find($one->id); - - $this->assertFalse($model->relationLoaded('twos')); - } - - public function testWhenRelationLoaded() - { - $one = One::query()->create(); - $one->twos()->create(); - - $model = One::query() - ->with('twos') - ->find($one->id); - - $this->assertTrue($model->relationLoaded('twos')); - } - - public function testWhenChildRelationIsNotLoaded() - { - $one = One::query()->create(); - $two = $one->twos()->create(); - $two->threes()->create(); - - $model = One::query() - ->with('twos') - ->find($one->id); - - $this->assertTrue($model->relationLoaded('twos')); - $this->assertFalse($model->relationLoaded('twos.threes')); - } - - public function testWhenChildRelationIsLoaded() - { - $one = One::query()->create(); - $two = $one->twos()->create(); - $two->threes()->create(); - - $model = One::query() - ->with('twos.threes') - ->find($one->id); - - $this->assertTrue($model->relationLoaded('twos')); - $this->assertTrue($model->relationLoaded('twos.threes')); - } - - public function testWhenChildRecursiveRelationIsLoaded() - { - $one = One::query()->create(); - $two = $one->twos()->create(); - $two->threes()->create(['one_id' => $one->id]); - - $model = One::query() - ->with('twos.threes.one') - ->find($one->id); - - $this->assertTrue($model->relationLoaded('twos')); - $this->assertTrue($model->relationLoaded('twos.threes')); - $this->assertTrue($model->relationLoaded('twos.threes.one')); - } - - public function testWhenParentRelationIsASingleInstance() - { - $one = One::query()->create(); - $two = $one->twos()->create(); - $three = $two->threes()->create(); - - $model = Three::query() - ->with('two.one') - ->find($three->id); - - $this->assertTrue($model->relationLoaded('two')); - $this->assertTrue($model->two->is($two)); - $this->assertTrue($model->relationLoaded('two.one')); - $this->assertTrue($model->two->one->is($one)); - } - - public function testWhenRelationIsNull() - { - $one = One::query()->create(); - $two = $one->twos()->create(); - $three = $two->threes()->create(); - - $model = Three::query() - ->with('one.twos') - ->find($three->id); - - $this->assertTrue($model->relationLoaded('one')); - $this->assertNull($model->one); - $this->assertFalse($model->relationLoaded('one.twos')); - } -} - -class One extends Model -{ - public $table = 'ones'; - public $timestamps = false; - protected $guarded = []; - - public function twos(): HasMany - { - return $this->hasMany(Two::class, 'one_id'); - } -} - -class Two extends Model -{ - public $table = 'twos'; - public $timestamps = false; - protected $guarded = []; - - public function one(): BelongsTo - { - return $this->belongsTo(One::class, 'one_id'); - } - - public function threes(): HasMany - { - return $this->hasMany(Three::class, 'two_id'); - } -} - -class Three extends Model -{ - public $table = 'threes'; - public $timestamps = false; - protected $guarded = []; - - public function one(): BelongsTo - { - return $this->belongsTo(One::class, 'one_id'); - } - - public function two(): BelongsTo - { - return $this->belongsTo(Two::class, 'two_id'); - } -} From 0f123cc857bc177abe4d417448d4f7164f71802a Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:11:20 +0000 Subject: [PATCH 418/455] Update version to v12.10.2 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index fb6f7548a34c..3c491b0544b2 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.10.1'; + const VERSION = '12.10.2'; /** * The base path for the Laravel installation. From 1a6198b50129dbbb3a77c620ce2098796739dacb Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:13:01 +0000 Subject: [PATCH 419/455] Update CHANGELOG --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c196a99d749..b292512610ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.10.1...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.10.2...12.x) + +## [v12.10.2](https://github.com/laravel/framework/compare/v12.10.1...v12.10.2) - 2025-04-24 + +* [12.x] Address Model@relationLoaded when relation is null by [@rodrigopedra](https://github.com/rodrigopedra) in https://github.com/laravel/framework/pull/55531 ## [v12.10.1](https://github.com/laravel/framework/compare/v12.10.0...v12.10.1) - 2025-04-23 From b204b8524993a2af5dce833271d9604d7333048d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 24 Apr 2025 09:15:22 -0500 Subject: [PATCH 420/455] Add payload creation and original delay info to job payload (#55529) * add payload creation and original delay info to job payload * Apply fixes from StyleCI * nullable type --------- Co-authored-by: StyleCI Bot --- src/Illuminate/Queue/BeanstalkdQueue.php | 2 +- src/Illuminate/Queue/DatabaseQueue.php | 2 +- src/Illuminate/Queue/Queue.php | 14 +++++++-- src/Illuminate/Queue/RedisQueue.php | 2 +- src/Illuminate/Queue/SqsQueue.php | 2 +- tests/Queue/QueueBeanstalkdQueueTest.php | 13 ++++++-- tests/Queue/QueueDatabaseQueueUnitTest.php | 19 +++++++++--- tests/Queue/QueueRedisQueueTest.php | 36 ++++++++++++++++------ 8 files changed, 68 insertions(+), 22 deletions(-) diff --git a/src/Illuminate/Queue/BeanstalkdQueue.php b/src/Illuminate/Queue/BeanstalkdQueue.php index d1f64e982492..56e9c4e0664b 100755 --- a/src/Illuminate/Queue/BeanstalkdQueue.php +++ b/src/Illuminate/Queue/BeanstalkdQueue.php @@ -125,7 +125,7 @@ public function later($delay, $job, $data = '', $queue = null) { return $this->enqueueUsing( $job, - $this->createPayload($job, $this->getQueue($queue), $data), + $this->createPayload($job, $this->getQueue($queue), $data, $delay), $queue, $delay, function ($payload, $queue, $delay) { diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index 0e6163a2c265..41d04e2b001c 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -126,7 +126,7 @@ public function later($delay, $job, $data = '', $queue = null) { return $this->enqueueUsing( $job, - $this->createPayload($job, $this->getQueue($queue), $data), + $this->createPayload($job, $this->getQueue($queue), $data, $delay), $queue, $delay, function ($payload, $queue, $delay) { diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index a5f831957b09..49b3cdda6f2c 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -2,6 +2,7 @@ namespace Illuminate\Queue; +use Carbon\Carbon; use Closure; use DateTimeInterface; use Illuminate\Bus\UniqueLock; @@ -97,17 +98,24 @@ public function bulk($jobs, $data = '', $queue = null) * @param \Closure|string|object $job * @param string $queue * @param mixed $data + * @param \DateTimeInterface|\DateInterval|int|null $delay * @return string * * @throws \Illuminate\Queue\InvalidPayloadException */ - protected function createPayload($job, $queue, $data = '') + protected function createPayload($job, $queue, $data = '', $delay = null) { if ($job instanceof Closure) { $job = CallQueuedClosure::create($job); } - $payload = json_encode($value = $this->createPayloadArray($job, $queue, $data), \JSON_UNESCAPED_UNICODE); + $value = $this->createPayloadArray($job, $queue, $data); + + $value['delay'] = isset($delay) + ? $this->secondsUntil($delay) + : null; + + $payload = json_encode($value, \JSON_UNESCAPED_UNICODE); if (json_last_error() !== JSON_ERROR_NONE) { throw new InvalidPayloadException( @@ -156,6 +164,7 @@ protected function createObjectPayload($job, $queue) 'commandName' => $job, 'command' => $job, ], + 'createdAt' => Carbon::now()->getTimestamp(), ]); $command = $this->jobShouldBeEncrypted($job) && $this->container->bound(Encrypter::class) @@ -277,6 +286,7 @@ protected function createStringPayload($job, $queue, $data) 'backoff' => null, 'timeout' => null, 'data' => $data, + 'createdAt' => Carbon::now()->getTimestamp(), ]); } diff --git a/src/Illuminate/Queue/RedisQueue.php b/src/Illuminate/Queue/RedisQueue.php index e8d6d77c7a51..84cfbde358cf 100644 --- a/src/Illuminate/Queue/RedisQueue.php +++ b/src/Illuminate/Queue/RedisQueue.php @@ -192,7 +192,7 @@ public function later($delay, $job, $data = '', $queue = null) { return $this->enqueueUsing( $job, - $this->createPayload($job, $this->getQueue($queue), $data), + $this->createPayload($job, $this->getQueue($queue), $data, $delay), $queue, $delay, function ($payload, $queue, $delay) { diff --git a/src/Illuminate/Queue/SqsQueue.php b/src/Illuminate/Queue/SqsQueue.php index 0d74b8dda43f..a128be81109f 100755 --- a/src/Illuminate/Queue/SqsQueue.php +++ b/src/Illuminate/Queue/SqsQueue.php @@ -128,7 +128,7 @@ public function later($delay, $job, $data = '', $queue = null) { return $this->enqueueUsing( $job, - $this->createPayload($job, $queue ?: $this->default, $data), + $this->createPayload($job, $queue ?: $this->default, $data, $delay), $queue, $delay, function ($payload, $queue, $delay) { diff --git a/tests/Queue/QueueBeanstalkdQueueTest.php b/tests/Queue/QueueBeanstalkdQueueTest.php index ba34a7069305..dfa4eace4a16 100755 --- a/tests/Queue/QueueBeanstalkdQueueTest.php +++ b/tests/Queue/QueueBeanstalkdQueueTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Queue; +use Carbon\Carbon; use Illuminate\Container\Container; use Illuminate\Queue\BeanstalkdQueue; use Illuminate\Queue\Jobs\BeanstalkdJob; @@ -38,6 +39,9 @@ public function testPushProperlyPushesJobOntoBeanstalkd() { $uuid = Str::uuid(); + $time = Carbon::now(); + Carbon::setTestNow($time); + Str::createUuidsUsing(function () use ($uuid) { return $uuid; }); @@ -46,13 +50,14 @@ public function testPushProperlyPushesJobOntoBeanstalkd() $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with(m::type(TubeName::class)); $pheanstalk->shouldReceive('useTube')->once()->with(m::type(TubeName::class)); - $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), 1024, 0, 60); + $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'delay' => null]), 1024, 0, 60); $this->queue->push('foo', ['data'], 'stack'); $this->queue->push('foo', ['data']); $this->container->shouldHaveReceived('bound')->with('events')->times(4); + Carbon::setTestNow(); Str::createUuidsNormally(); } @@ -64,17 +69,21 @@ public function testDelayedPushProperlyPushesJobOntoBeanstalkd() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $this->setQueue('default', 60); $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with(m::type(TubeName::class)); $pheanstalk->shouldReceive('useTube')->once()->with(m::type(TubeName::class)); - $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), Pheanstalk::DEFAULT_PRIORITY, 5, Pheanstalk::DEFAULT_TTR); + $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'delay' => 5]), Pheanstalk::DEFAULT_PRIORITY, 5, Pheanstalk::DEFAULT_TTR); $this->queue->later(5, 'foo', ['data'], 'stack'); $this->queue->later(5, 'foo', ['data']); $this->container->shouldHaveReceived('bound')->with('events')->times(4); + Carbon::setTestNow(); Str::createUuidsNormally(); } diff --git a/tests/Queue/QueueDatabaseQueueUnitTest.php b/tests/Queue/QueueDatabaseQueueUnitTest.php index 3714b99a80b5..9702a4d6695e 100644 --- a/tests/Queue/QueueDatabaseQueueUnitTest.php +++ b/tests/Queue/QueueDatabaseQueueUnitTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Queue; +use Carbon\Carbon; use Illuminate\Container\Container; use Illuminate\Database\Connection; use Illuminate\Queue\DatabaseQueue; @@ -69,6 +70,9 @@ public function testDelayedPushProperlyPushesJobOntoDatabase() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $queue = $this->getMockBuilder(DatabaseQueue::class) ->onlyMethods(['currentTime']) ->setConstructorArgs([$database = m::mock(Connection::class), 'table', 'default']) @@ -76,9 +80,9 @@ public function testDelayedPushProperlyPushesJobOntoDatabase() $queue->expects($this->any())->method('currentTime')->willReturn('time'); $queue->setContainer($container = m::spy(Container::class)); $database->shouldReceive('table')->with('table')->andReturn($query = m::mock(stdClass::class)); - $query->shouldReceive('insertGetId')->once()->andReturnUsing(function ($array) use ($uuid) { + $query->shouldReceive('insertGetId')->once()->andReturnUsing(function ($array) use ($uuid, $time) { $this->assertSame('default', $array['queue']); - $this->assertSame(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), $array['payload']); + $this->assertSame(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'delay' => 10]), $array['payload']); $this->assertEquals(0, $array['attempts']); $this->assertNull($array['reserved_at']); $this->assertIsInt($array['available_at']); @@ -88,6 +92,7 @@ public function testDelayedPushProperlyPushesJobOntoDatabase() $container->shouldHaveReceived('bound')->with('events')->twice(); + Carbon::setTestNow(); Str::createUuidsNormally(); } @@ -130,22 +135,25 @@ public function testBulkBatchPushesOntoDatabase() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $database = m::mock(Connection::class); $queue = $this->getMockBuilder(DatabaseQueue::class)->onlyMethods(['currentTime', 'availableAt'])->setConstructorArgs([$database, 'table', 'default'])->getMock(); $queue->expects($this->any())->method('currentTime')->willReturn('created'); $queue->expects($this->any())->method('availableAt')->willReturn('available'); $database->shouldReceive('table')->with('table')->andReturn($query = m::mock(stdClass::class)); - $query->shouldReceive('insert')->once()->andReturnUsing(function ($records) use ($uuid) { + $query->shouldReceive('insert')->once()->andReturnUsing(function ($records) use ($uuid, $time) { $this->assertEquals([[ 'queue' => 'queue', - 'payload' => json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), + 'payload' => json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'delay' => null]), 'attempts' => 0, 'reserved_at' => null, 'available_at' => 'available', 'created_at' => 'created', ], [ 'queue' => 'queue', - 'payload' => json_encode(['uuid' => $uuid, 'displayName' => 'bar', 'job' => 'bar', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), + 'payload' => json_encode(['uuid' => $uuid, 'displayName' => 'bar', 'job' => 'bar', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'delay' => null]), 'attempts' => 0, 'reserved_at' => null, 'available_at' => 'available', @@ -155,6 +163,7 @@ public function testBulkBatchPushesOntoDatabase() $queue->bulk(['foo', 'bar'], ['data'], 'queue'); + Carbon::setTestNow(); Str::createUuidsNormally(); } diff --git a/tests/Queue/QueueRedisQueueTest.php b/tests/Queue/QueueRedisQueueTest.php index 007f743653d8..7ea0bfdbe076 100644 --- a/tests/Queue/QueueRedisQueueTest.php +++ b/tests/Queue/QueueRedisQueueTest.php @@ -27,16 +27,20 @@ public function testPushProperlyPushesJobOntoRedis() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $queue = $this->getMockBuilder(RedisQueue::class)->onlyMethods(['getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->expects($this->once())->method('getRandomId')->willReturn('foo'); $queue->setContainer($container = m::spy(Container::class)); $redis->shouldReceive('connection')->once()->andReturn($redis); - $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0])); + $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'id' => 'foo', 'attempts' => 0, 'delay' => null])); $id = $queue->push('foo', ['data']); $this->assertSame('foo', $id); $container->shouldHaveReceived('bound')->with('events')->twice(); + Carbon::setTestNow(); Str::createUuidsNormally(); } @@ -48,11 +52,14 @@ public function testPushProperlyPushesJobOntoRedisWithCustomPayloadHook() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $queue = $this->getMockBuilder(RedisQueue::class)->onlyMethods(['getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->expects($this->once())->method('getRandomId')->willReturn('foo'); $queue->setContainer($container = m::spy(Container::class)); $redis->shouldReceive('connection')->once()->andReturn($redis); - $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'id' => 'foo', 'attempts' => 0])); + $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'custom' => 'taylor', 'id' => 'foo', 'attempts' => 0, 'delay' => null])); Queue::createPayloadUsing(function ($connection, $queue, $payload) { return ['custom' => 'taylor']; @@ -64,6 +71,7 @@ public function testPushProperlyPushesJobOntoRedisWithCustomPayloadHook() Queue::createPayloadUsing(null); + Carbon::setTestNow(); Str::createUuidsNormally(); } @@ -75,11 +83,14 @@ public function testPushProperlyPushesJobOntoRedisWithTwoCustomPayloadHook() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $queue = $this->getMockBuilder(RedisQueue::class)->onlyMethods(['getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->expects($this->once())->method('getRandomId')->willReturn('foo'); $queue->setContainer($container = m::spy(Container::class)); $redis->shouldReceive('connection')->once()->andReturn($redis); - $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'bar' => 'foo', 'id' => 'foo', 'attempts' => 0])); + $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'custom' => 'taylor', 'bar' => 'foo', 'id' => 'foo', 'attempts' => 0, 'delay' => null])); Queue::createPayloadUsing(function ($connection, $queue, $payload) { return ['custom' => 'taylor']; @@ -95,6 +106,7 @@ public function testPushProperlyPushesJobOntoRedisWithTwoCustomPayloadHook() Queue::createPayloadUsing(null); + Carbon::setTestNow(); Str::createUuidsNormally(); } @@ -106,6 +118,9 @@ public function testDelayedPushProperlyPushesJobOntoRedis() return $uuid; }); + $time = Carbon::now(); + Carbon::setTestNow($time); + $queue = $this->getMockBuilder(RedisQueue::class)->onlyMethods(['availableAt', 'getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->setContainer($container = m::spy(Container::class)); $queue->expects($this->once())->method('getRandomId')->willReturn('foo'); @@ -115,13 +130,14 @@ public function testDelayedPushProperlyPushesJobOntoRedis() $redis->shouldReceive('zadd')->once()->with( 'queues:default:delayed', 2, - json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0]) + json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'id' => 'foo', 'attempts' => 0, 'delay' => 1]) ); $id = $queue->later(1, 'foo', ['data']); $this->assertSame('foo', $id); $container->shouldHaveReceived('bound')->with('events')->twice(); + Carbon::setTestNow(); Str::createUuidsNormally(); } @@ -133,22 +149,24 @@ public function testDelayedPushWithDateTimeProperlyPushesJobOntoRedis() return $uuid; }); - $date = Carbon::now(); + $time = $date = Carbon::now(); + Carbon::setTestNow($time); $queue = $this->getMockBuilder(RedisQueue::class)->onlyMethods(['availableAt', 'getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->setContainer($container = m::spy(Container::class)); $queue->expects($this->once())->method('getRandomId')->willReturn('foo'); - $queue->expects($this->once())->method('availableAt')->with($date)->willReturn(2); + $queue->expects($this->once())->method('availableAt')->with($date)->willReturn(5); $redis->shouldReceive('connection')->once()->andReturn($redis); $redis->shouldReceive('zadd')->once()->with( 'queues:default:delayed', - 2, - json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0]) + 5, + json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'failOnTimeout' => false, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'createdAt' => $time->getTimestamp(), 'id' => 'foo', 'attempts' => 0, 'delay' => 5]) ); - $queue->later($date, 'foo', ['data']); + $queue->later($date->addSeconds(5), 'foo', ['data']); $container->shouldHaveReceived('bound')->with('events')->twice(); + Carbon::setTestNow(); Str::createUuidsNormally(); } } From 5dea84f6fdcb2c5826f8a3ac77f7818a2c3c6f29 Mon Sep 17 00:00:00 2001 From: PizZaKatZe <78648379+pizkaz@users.noreply.github.com> Date: Thu, 24 Apr 2025 16:29:34 +0200 Subject: [PATCH 421/455] Add config option to ignore view cache timestamps (#55536) * Add config option to ignore view cache timestamps * Fix BladeCompiler testIsExpiredReturnsTrueWhenUseCacheIsFalse * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/View/Compilers/Compiler.php | 14 ++++++++++++++ src/Illuminate/View/ViewServiceProvider.php | 1 + tests/View/ViewBladeCompilerTest.php | 9 ++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/View/Compilers/Compiler.php b/src/Illuminate/View/Compilers/Compiler.php index dbd349e69e2a..1e61eae95932 100755 --- a/src/Illuminate/View/Compilers/Compiler.php +++ b/src/Illuminate/View/Compilers/Compiler.php @@ -44,6 +44,13 @@ abstract class Compiler */ protected $compiledExtension = 'php'; + /** + * Indicates if view cache timestamps should be checked. + * + * @var bool + */ + protected $shouldCheckTimestamps; + /** * Create a new compiler instance. * @@ -51,6 +58,7 @@ abstract class Compiler * @param string $cachePath * @param string $basePath * @param bool $shouldCache + * @param bool $shouldCheckTimestamps * @param string $compiledExtension * * @throws \InvalidArgumentException @@ -61,6 +69,7 @@ public function __construct( $basePath = '', $shouldCache = true, $compiledExtension = 'php', + $shouldCheckTimestamps = true, ) { if (! $cachePath) { throw new InvalidArgumentException('Please provide a valid cache path.'); @@ -71,6 +80,7 @@ public function __construct( $this->basePath = $basePath; $this->shouldCache = $shouldCache; $this->compiledExtension = $compiledExtension; + $this->shouldCheckTimestamps = $shouldCheckTimestamps; } /** @@ -107,6 +117,10 @@ public function isExpired($path) return true; } + if (! $this->shouldCheckTimestamps) { + return false; + } + try { return $this->files->lastModified($path) >= $this->files->lastModified($compiled); diff --git a/src/Illuminate/View/ViewServiceProvider.php b/src/Illuminate/View/ViewServiceProvider.php index 41cd8b93c9aa..2ef3d31177b4 100755 --- a/src/Illuminate/View/ViewServiceProvider.php +++ b/src/Illuminate/View/ViewServiceProvider.php @@ -100,6 +100,7 @@ public function registerBladeCompiler() $app['config']->get('view.relative_hash', false) ? $app->basePath() : '', $app['config']->get('view.cache', true), $app['config']->get('view.compiled_extension', 'php'), + $app['config']->get('view.check_cache_timestamps', true), ), function ($blade) { $blade->component('dynamic-component', DynamicComponent::class); }); diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index ed59a62fbbe7..b26693489c81 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -51,10 +51,17 @@ public function testIsExpiredReturnsFalseWhenUseCacheIsTrueAndNoFileModification public function testIsExpiredReturnsTrueWhenUseCacheIsFalse() { - $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__, $basePath = '', $useCache = false); + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__, shouldCache: false); $this->assertTrue($compiler->isExpired('foo')); } + public function testIsExpiredReturnsFalseWhenIgnoreCacheTimestampsIsTrue() + { + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__, shouldCheckTimestamps: false); + $files->shouldReceive('exists')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php')->andReturn(true); + $this->assertFalse($compiler->isExpired('foo')); + } + public function testCompilePathIsProperlyCreated() { $compiler = new BladeCompiler($this->getFiles(), __DIR__); From 90dc8f9e6b2b928f0c54816dc01310143d88aa27 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Thu, 24 Apr 2025 16:24:00 -0300 Subject: [PATCH 422/455] [12.x] Dispatch NotificationFailed when sending fails (#55507) * dispatch NotificationFailed when sending fails * Update NotificationSender.php --------- Co-authored-by: Taylor Otwell --- .../Notifications/NotificationSender.php | 25 +++++++- .../NotificationChannelManagerTest.php | 58 +++++++++++++++++++ .../Notifications/NotificationSenderTest.php | 6 ++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index c7e75fd851b2..46ef9e88cf15 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -6,11 +6,13 @@ use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Events\NotificationFailed; use Illuminate\Notifications\Events\NotificationSending; use Illuminate\Notifications\Events\NotificationSent; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\Localizable; +use Throwable; class NotificationSender { @@ -44,6 +46,13 @@ class NotificationSender */ protected $locale; + /** + * Indicates whether a NotificationFailed event has been dispatched. + * + * @var bool + */ + protected $failedEventWasDispatched = false; + /** * Create a new notification sender instance. * @@ -58,6 +67,8 @@ public function __construct($manager, $bus, $events, $locale = null) $this->events = $events; $this->locale = $locale; $this->manager = $manager; + + $this->events->listen(NotificationFailed::class, fn () => $this->failedEventWasDispatched = true); } /** @@ -144,7 +155,19 @@ protected function sendToNotifiable($notifiable, $id, $notification, $channel) return; } - $response = $this->manager->driver($channel)->send($notifiable, $notification); + try { + $response = $this->manager->driver($channel)->send($notifiable, $notification); + } catch (Throwable $exception) { + if (! $this->failedEventWasDispatched) { + $this->events->dispatch( + new NotificationFailed($notifiable, $notification, $channel, ['exception' => $exception]) + ); + } + + $this->failedEventWasDispatched = false; + + throw $exception; + } $this->events->dispatch( new NotificationSent($notifiable, $notification, $channel, $response) diff --git a/tests/Notifications/NotificationChannelManagerTest.php b/tests/Notifications/NotificationChannelManagerTest.php index efcce081aeee..4b272db8399f 100644 --- a/tests/Notifications/NotificationChannelManagerTest.php +++ b/tests/Notifications/NotificationChannelManagerTest.php @@ -2,17 +2,20 @@ namespace Illuminate\Tests\Notifications; +use Exception; use Illuminate\Bus\Queueable; use Illuminate\Container\Container; use Illuminate\Contracts\Bus\Dispatcher as Bus; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\ChannelManager; +use Illuminate\Notifications\Events\NotificationFailed; use Illuminate\Notifications\Events\NotificationSending; use Illuminate\Notifications\Events\NotificationSent; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; use Illuminate\Notifications\SendQueuedNotifications; +use Illuminate\Support\Collection; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -34,6 +37,7 @@ public function testNotificationCanBeDispatchedToDriver() Container::setInstance($container); $manager = m::mock(ChannelManager::class.'[driver]', [$container]); $manager->shouldReceive('driver')->andReturn($driver = m::mock()); + $events->shouldReceive('listen')->once(); $events->shouldReceive('until')->with(m::type(NotificationSending::class))->andReturn(true); $driver->shouldReceive('send')->once(); $events->shouldReceive('dispatch')->with(m::type(NotificationSent::class)); @@ -49,6 +53,7 @@ public function testNotificationNotSentOnHalt() $container->instance(Dispatcher::class, $events = m::mock()); Container::setInstance($container); $manager = m::mock(ChannelManager::class.'[driver]', [$container]); + $events->shouldReceive('listen')->once(); $events->shouldReceive('until')->once()->with(m::type(NotificationSending::class))->andReturn(false); $events->shouldReceive('until')->with(m::type(NotificationSending::class))->andReturn(true); $manager->shouldReceive('driver')->once()->andReturn($driver = m::mock()); @@ -66,6 +71,7 @@ public function testNotificationNotSentWhenCancelled() $container->instance(Dispatcher::class, $events = m::mock()); Container::setInstance($container); $manager = m::mock(ChannelManager::class.'[driver]', [$container]); + $events->shouldReceive('listen')->once(); $events->shouldReceive('until')->with(m::type(NotificationSending::class))->andReturn(true); $manager->shouldNotReceive('driver'); $events->shouldNotReceive('dispatch'); @@ -81,6 +87,7 @@ public function testNotificationSentWhenNotCancelled() $container->instance(Dispatcher::class, $events = m::mock()); Container::setInstance($container); $manager = m::mock(ChannelManager::class.'[driver]', [$container]); + $events->shouldReceive('listen')->once(); $events->shouldReceive('until')->with(m::type(NotificationSending::class))->andReturn(true); $manager->shouldReceive('driver')->once()->andReturn($driver = m::mock()); $driver->shouldReceive('send')->once(); @@ -89,6 +96,56 @@ public function testNotificationSentWhenNotCancelled() $manager->send([new NotificationChannelManagerTestNotifiable], new NotificationChannelManagerTestNotCancelledNotification); } + public function testNotificationNotSentWhenFailed() + { + $this->expectException(Exception::class); + + $container = new Container; + $container->instance('config', ['app.name' => 'Name', 'app.logo' => 'Logo']); + $container->instance(Bus::class, $bus = m::mock()); + $container->instance(Dispatcher::class, $events = m::mock()); + Container::setInstance($container); + $manager = m::mock(ChannelManager::class.'[driver]', [$container]); + $manager->shouldReceive('driver')->andReturn($driver = m::mock()); + $driver->shouldReceive('send')->andThrow(new Exception()); + $events->shouldReceive('listen')->once(); + $events->shouldReceive('until')->with(m::type(NotificationSending::class))->andReturn(true); + $events->shouldReceive('dispatch')->once()->with(m::type(NotificationFailed::class)); + $events->shouldReceive('dispatch')->never()->with(m::type(NotificationSent::class)); + + $manager->send(new NotificationChannelManagerTestNotifiable, new NotificationChannelManagerTestNotification); + } + + public function testNotificationFailedDispatchedOnlyOnceWhenFailed() + { + $this->expectException(Exception::class); + + $container = new Container; + $container->instance('config', ['app.name' => 'Name', 'app.logo' => 'Logo']); + $container->instance(Bus::class, $bus = m::mock()); + $container->instance(Dispatcher::class, $events = m::mock(Dispatcher::class)); + Container::setInstance($container); + $manager = m::mock(ChannelManager::class.'[driver]', [$container]); + $manager->shouldReceive('driver')->andReturn($driver = m::mock()); + $driver->shouldReceive('send')->andReturnUsing(function ($notifiable, $notification) use ($events) { + $events->dispatch(new NotificationFailed($notifiable, $notification, 'test')); + throw new Exception(); + }); + $listeners = new Collection(); + $events->shouldReceive('until')->with(m::type(NotificationSending::class))->andReturn(true); + $events->shouldReceive('listen')->once()->andReturnUsing(function ($event, $callback) use ($listeners) { + $listeners->push($callback); + }); + $events->shouldReceive('dispatch')->once()->with(m::type(NotificationFailed::class))->andReturnUsing(function ($event) use ($listeners) { + foreach ($listeners as $listener) { + $listener($event); + } + }); + $events->shouldReceive('dispatch')->never()->with(m::type(NotificationSent::class)); + + $manager->send(new NotificationChannelManagerTestNotifiable, new NotificationChannelManagerTestNotification); + } + public function testNotificationCanBeQueued() { $container = new Container; @@ -98,6 +155,7 @@ public function testNotificationCanBeQueued() $bus->shouldReceive('dispatch')->with(m::type(SendQueuedNotifications::class)); Container::setInstance($container); $manager = m::mock(ChannelManager::class.'[driver]', [$container]); + $events->shouldReceive('listen')->once(); $manager->send([new NotificationChannelManagerTestNotifiable], new NotificationChannelManagerTestQueuedNotification); } diff --git a/tests/Notifications/NotificationSenderTest.php b/tests/Notifications/NotificationSenderTest.php index 4770fc96cd17..6e3a9954938c 100644 --- a/tests/Notifications/NotificationSenderTest.php +++ b/tests/Notifications/NotificationSenderTest.php @@ -30,6 +30,7 @@ public function testItCanSendQueuedNotificationsWithAStringVia() $bus = m::mock(BusDispatcher::class); $bus->shouldReceive('dispatch'); $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); $sender = new NotificationSender($manager, $bus, $events); @@ -43,6 +44,7 @@ public function testItCanSendNotificationsWithAnEmptyStringVia() $bus = m::mock(BusDispatcher::class); $bus->shouldNotReceive('dispatch'); $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); $sender = new NotificationSender($manager, $bus, $events); @@ -56,6 +58,7 @@ public function testItCannotSendNotificationsViaDatabaseForAnonymousNotifiables( $bus = m::mock(BusDispatcher::class); $bus->shouldNotReceive('dispatch'); $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); $sender = new NotificationSender($manager, $bus, $events); @@ -72,6 +75,7 @@ public function testItCanSendQueuedNotificationsThroughMiddleware() return $job->middleware[0] instanceof TestNotificationMiddleware; }); $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); $sender = new NotificationSender($manager, $bus, $events); @@ -99,6 +103,7 @@ public function testItCanSendQueuedMultiChannelNotificationsThroughDifferentMidd return empty($job->middleware); }); $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); $sender = new NotificationSender($manager, $bus, $events); @@ -122,6 +127,7 @@ public function testItCanSendQueuedWithViaConnectionsNotifications() }); $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); $sender = new NotificationSender($manager, $bus, $events); From 6f55dbc38154e355f83dd8e1e9121099dd218c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Thu, 24 Apr 2025 21:45:06 +0200 Subject: [PATCH 423/455] [12.x] Option to disable dispatchAfterResponse in a test (#55456) * Option to disable/enable dispatchAfterresponse * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Bus/Dispatcher.php | 37 +++++++++++++++++++ .../Integration/Queue/JobDispatchingTest.php | 32 ++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/Illuminate/Bus/Dispatcher.php b/src/Illuminate/Bus/Dispatcher.php index 32f917d796a6..0107b9e5acd4 100644 --- a/src/Illuminate/Bus/Dispatcher.php +++ b/src/Illuminate/Bus/Dispatcher.php @@ -51,6 +51,13 @@ class Dispatcher implements QueueingDispatcher */ protected $queueResolver; + /** + * Indicates if dispatching after response is disabled. + * + * @var bool + */ + protected $allowsDispatchingAfterResponses = true; + /** * Create a new command dispatcher instance. * @@ -252,6 +259,12 @@ protected function pushCommandToQueue($queue, $command) */ public function dispatchAfterResponse($command, $handler = null) { + if (! $this->allowsDispatchingAfterResponses) { + $this->dispatchSync($command); + + return; + } + $this->container->terminating(function () use ($command, $handler) { $this->dispatchSync($command, $handler); }); @@ -282,4 +295,28 @@ public function map(array $map) return $this; } + + /** + * Allow dispatching after responses. + * + * @return $this + */ + public function withDispatchingAfterResponses() + { + $this->allowsDispatchingAfterResponses = true; + + return $this; + } + + /** + * Disable dispatching after responses. + * + * @return $this + */ + public function withoutDispatchingAfterResponses() + { + $this->allowsDispatchingAfterResponses = false; + + return $this; + } } diff --git a/tests/Integration/Queue/JobDispatchingTest.php b/tests/Integration/Queue/JobDispatchingTest.php index ebef0f344318..eddfd83c23c1 100644 --- a/tests/Integration/Queue/JobDispatchingTest.php +++ b/tests/Integration/Queue/JobDispatchingTest.php @@ -10,6 +10,7 @@ use Illuminate\Queue\Events\JobQueued; use Illuminate\Queue\Events\JobQueueing; use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Config; use Orchestra\Testbench\Attributes\WithMigration; @@ -165,6 +166,37 @@ public function testQueueMayBeNullForJobQueueingAndJobQueuedEvent() $this->assertNull($events[3]->queue); } + public function testCanDisableDispatchingAfterResponse() + { + Job::dispatchAfterResponse('test'); + + $this->assertFalse(Job::$ran); + + $this->app->terminate(); + + $this->assertTrue(Job::$ran); + + Bus::withoutDispatchingAfterResponses(); + + Job::$ran = false; + Job::dispatchAfterResponse('test'); + + $this->assertTrue(Job::$ran); + + $this->app->terminate(); + + Bus::withDispatchingAfterResponses(); + + Job::$ran = false; + Job::dispatchAfterResponse('test'); + + $this->assertFalse(Job::$ran); + + $this->app->terminate(); + + $this->assertTrue(Job::$ran); + } + /** * Helpers. */ From bedb09d38abeb3a230423030e5fa6c55ce160d9f Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:45:35 +0000 Subject: [PATCH 424/455] Update facade docblocks --- src/Illuminate/Support/Facades/Bus.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Facades/Bus.php b/src/Illuminate/Support/Facades/Bus.php index 90e64ac9cf0e..affeb6076985 100644 --- a/src/Illuminate/Support/Facades/Bus.php +++ b/src/Illuminate/Support/Facades/Bus.php @@ -20,6 +20,8 @@ * @method static void dispatchAfterResponse(mixed $command, mixed $handler = null) * @method static \Illuminate\Bus\Dispatcher pipeThrough(array $pipes) * @method static \Illuminate\Bus\Dispatcher map(array $map) + * @method static \Illuminate\Bus\Dispatcher withDispatchingAfterResponses() + * @method static \Illuminate\Bus\Dispatcher withoutDispatchingAfterResponses() * @method static \Illuminate\Support\Testing\Fakes\BusFake except(array|string $jobsToDispatch) * @method static void assertDispatched(string|\Closure $command, callable|int|null $callback = null) * @method static void assertDispatchedTimes(string|\Closure $command, int $times = 1) From b73ac015a09840b0cd7af1d2a9d970eecb85f80d Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Thu, 24 Apr 2025 18:34:17 -0300 Subject: [PATCH 425/455] Pass flags to custom Json::$encoder (#55548) --- src/Illuminate/Database/Eloquent/Casts/Json.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Casts/Json.php b/src/Illuminate/Database/Eloquent/Casts/Json.php index 970b309dbb94..783d5b9986f6 100644 --- a/src/Illuminate/Database/Eloquent/Casts/Json.php +++ b/src/Illuminate/Database/Eloquent/Casts/Json.php @@ -23,7 +23,9 @@ class Json */ public static function encode(mixed $value, int $flags = 0): mixed { - return isset(static::$encoder) ? (static::$encoder)($value) : json_encode($value, $flags); + return isset(static::$encoder) + ? (static::$encoder)($value, $flags) + : json_encode($value, $flags); } /** From 00c7e312f09ca881ab61dd258ce2dfbd199d9746 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 25 Apr 2025 09:41:17 +1000 Subject: [PATCH 426/455] wip --- src/Illuminate/Support/Facades/Cache.php | 1 - tests/Integration/Cache/RedisStoreTest.php | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php index 07553d8bb812..1463306365ca 100755 --- a/src/Illuminate/Support/Facades/Cache.php +++ b/src/Illuminate/Support/Facades/Cache.php @@ -5,7 +5,6 @@ /** * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) * @method static \Illuminate\Contracts\Cache\Repository driver(string|null $driver = null) - * @method static \Illuminate\Contracts\Cache\Repository memo(string|null $driver = null) * @method static \Illuminate\Contracts\Cache\Repository resolve(string $name) * @method static \Illuminate\Cache\Repository build(array $config) * @method static \Illuminate\Cache\Repository repository(\Illuminate\Contracts\Cache\Store $store, array $config = []) diff --git a/tests/Integration/Cache/RedisStoreTest.php b/tests/Integration/Cache/RedisStoreTest.php index f4a217c9e9f2..1bff1d472557 100644 --- a/tests/Integration/Cache/RedisStoreTest.php +++ b/tests/Integration/Cache/RedisStoreTest.php @@ -6,8 +6,6 @@ use Illuminate\Cache\RedisStore; use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; use Illuminate\Redis\Connections\PhpRedisClusterConnection; -use Illuminate\Support\Facades\Cache; -use Illuminate\Support\Facades\Redis; use Illuminate\Support\Sleep; use Mockery as m; use Orchestra\Testbench\TestCase; From 53f41419db21cb76fceddeb0ae52c655f10b2cc9 Mon Sep 17 00:00:00 2001 From: timacdonald <24803032+timacdonald@users.noreply.github.com> Date: Thu, 24 Apr 2025 23:41:56 +0000 Subject: [PATCH 427/455] Update facade docblocks --- src/Illuminate/Support/Facades/Cache.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php index 1463306365ca..07553d8bb812 100755 --- a/src/Illuminate/Support/Facades/Cache.php +++ b/src/Illuminate/Support/Facades/Cache.php @@ -5,6 +5,7 @@ /** * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) * @method static \Illuminate\Contracts\Cache\Repository driver(string|null $driver = null) + * @method static \Illuminate\Contracts\Cache\Repository memo(string|null $driver = null) * @method static \Illuminate\Contracts\Cache\Repository resolve(string $name) * @method static \Illuminate\Cache\Repository build(array $config) * @method static \Illuminate\Cache\Repository repository(\Illuminate\Contracts\Cache\Store $store, array $config = []) From 18a2f33c6c02e99bdb62bd2a0dc734fb189e29d2 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 25 Apr 2025 09:42:50 +1000 Subject: [PATCH 428/455] Restore imports --- tests/Integration/Cache/RedisStoreTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Integration/Cache/RedisStoreTest.php b/tests/Integration/Cache/RedisStoreTest.php index 1bff1d472557..f4a217c9e9f2 100644 --- a/tests/Integration/Cache/RedisStoreTest.php +++ b/tests/Integration/Cache/RedisStoreTest.php @@ -6,6 +6,8 @@ use Illuminate\Cache\RedisStore; use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; use Illuminate\Redis\Connections\PhpRedisClusterConnection; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Redis; use Illuminate\Support\Sleep; use Mockery as m; use Orchestra\Testbench\TestCase; From c1d8da6934fec932ecd6d2485b9dad10381f2dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Fri, 25 Apr 2025 17:08:45 +0200 Subject: [PATCH 429/455] Respect pendingAttributes in factories (#55558) --- .../Factories/BelongsToManyRelationship.php | 4 +- .../Database/Eloquent/Factories/Factory.php | 15 ++++ .../Eloquent/Factories/Relationship.php | 8 +- .../Database/DatabaseEloquentFactoryTest.php | 76 +++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php b/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php index da004c83bc74..fd350e6fce6c 100644 --- a/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php +++ b/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php @@ -50,7 +50,9 @@ public function __construct($factory, $pivot, $relationship) */ public function createFor(Model $model) { - Collection::wrap($this->factory instanceof Factory ? $this->factory->create([], $model) : $this->factory)->each(function ($attachable) use ($model) { + $relationship = $model->{$this->relationship}(); + + Collection::wrap($this->factory instanceof Factory ? $this->factory->prependState($relationship->getQuery()->pendingAttributes)->create([], $model) : $this->factory)->each(function ($attachable) use ($model) { $model->{$this->relationship}()->attach( $attachable, is_callable($this->pivot) ? call_user_func($this->pivot, $model) : $this->pivot diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index ffe9018e67f0..a52d840f421e 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -530,6 +530,21 @@ public function state($state) ]); } + /** + * Prepend a new state transformation to the model definition. + * + * @param (callable(array, TModel|null): array)|array $state + * @return static + */ + public function prependState($state) + { + return $this->newInstance([ + 'states' => $this->states->prepend( + is_callable($state) ? $state : fn () => $state, + ), + ]); + } + /** * Set a single model attribute. * diff --git a/src/Illuminate/Database/Eloquent/Factories/Relationship.php b/src/Illuminate/Database/Eloquent/Factories/Relationship.php index 4024f1c929c0..e23bc99d78b0 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Relationship.php +++ b/src/Illuminate/Database/Eloquent/Factories/Relationship.php @@ -49,13 +49,15 @@ public function createFor(Model $parent) $this->factory->state([ $relationship->getMorphType() => $relationship->getMorphClass(), $relationship->getForeignKeyName() => $relationship->getParentKey(), - ])->create([], $parent); + ])->prependState($relationship->getQuery()->pendingAttributes)->create([], $parent); } elseif ($relationship instanceof HasOneOrMany) { $this->factory->state([ $relationship->getForeignKeyName() => $relationship->getParentKey(), - ])->create([], $parent); + ])->prependState($relationship->getQuery()->pendingAttributes)->create([], $parent); } elseif ($relationship instanceof BelongsToMany) { - $relationship->attach($this->factory->create([], $parent)); + $relationship->attach( + $this->factory->prependState($relationship->getQuery()->pendingAttributes)->create([], $parent) + ); } } diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index b0860d236b03..da5467794d77 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -850,6 +850,62 @@ public function test_factory_global_model_resolver() $this->assertEquals(FactoryTestGuessModelFactory::new()->modelName(), FactoryTestGuessModel::class); } + public function test_factory_model_has_many_relationship_has_pending_attributes() + { + FactoryTestUser::factory()->has(new FactoryTestPostFactory(), 'postsWithFooBarBazAsTitle')->create(); + + $this->assertEquals('foo bar baz', FactoryTestPost::first()->title); + } + + public function test_factory_model_has_many_relationship_has_pending_attributes_override() + { + FactoryTestUser::factory()->has((new FactoryTestPostFactory())->state(['title' => 'other title']), 'postsWithFooBarBazAsTitle')->create(); + + $this->assertEquals('other title', FactoryTestPost::first()->title); + } + + public function test_factory_model_has_one_relationship_has_pending_attributes() + { + FactoryTestUser::factory()->has(new FactoryTestPostFactory(), 'postWithFooBarBazAsTitle')->create(); + + $this->assertEquals('foo bar baz', FactoryTestPost::first()->title); + } + + public function test_factory_model_has_one_relationship_has_pending_attributes_override() + { + FactoryTestUser::factory()->has((new FactoryTestPostFactory())->state(['title' => 'other title']), 'postWithFooBarBazAsTitle')->create(); + + $this->assertEquals('other title', FactoryTestPost::first()->title); + } + + public function test_factory_model_belongs_to_many_relationship_has_pending_attributes() + { + FactoryTestUser::factory()->has(new FactoryTestRoleFactory(), 'rolesWithFooBarBazAsName')->create(); + + $this->assertEquals('foo bar baz', FactoryTestRole::first()->name); + } + + public function test_factory_model_belongs_to_many_relationship_has_pending_attributes_override() + { + FactoryTestUser::factory()->has((new FactoryTestRoleFactory())->state(['name' => 'other name']), 'rolesWithFooBarBazAsName')->create(); + + $this->assertEquals('other name', FactoryTestRole::first()->name); + } + + public function test_factory_model_morph_many_relationship_has_pending_attributes() + { + (new FactoryTestPostFactory())->has(new FactoryTestCommentFactory(), 'commentsWithFooBarBazAsBody')->create(); + + $this->assertEquals('foo bar baz', FactoryTestComment::first()->body); + } + + public function test_factory_model_morph_many_relationship_has_pending_attributes_override() + { + (new FactoryTestPostFactory())->has((new FactoryTestCommentFactory())->state(['body' => 'other body']), 'commentsWithFooBarBazAsBody')->create(); + + $this->assertEquals('other body', FactoryTestComment::first()->body); + } + /** * Get a database connection instance. * @@ -895,11 +951,26 @@ public function posts() return $this->hasMany(FactoryTestPost::class, 'user_id'); } + public function postsWithFooBarBazAsTitle() + { + return $this->hasMany(FactoryTestPost::class, 'user_id')->withAttributes(['title' => 'foo bar baz']); + } + + public function postWithFooBarBazAsTitle() + { + return $this->hasOne(FactoryTestPost::class, 'user_id')->withAttributes(['title' => 'foo bar baz']); + } + public function roles() { return $this->belongsToMany(FactoryTestRole::class, 'role_user', 'user_id', 'role_id')->withPivot('admin'); } + public function rolesWithFooBarBazAsName() + { + return $this->belongsToMany(FactoryTestRole::class, 'role_user', 'user_id', 'role_id')->withPivot('admin')->withAttributes(['name' => 'foo bar baz']); + } + public function factoryTestRoles() { return $this->belongsToMany(FactoryTestRole::class, 'role_user', 'user_id', 'role_id')->withPivot('admin'); @@ -944,6 +1015,11 @@ public function comments() { return $this->morphMany(FactoryTestComment::class, 'commentable'); } + + public function commentsWithFooBarBazAsBody() + { + return $this->morphMany(FactoryTestComment::class, 'commentable')->withAttributes(['body' => 'foo bar baz']); + } } class FactoryTestCommentFactory extends Factory From 39fa9f402a953e01ad3f60f7369eca456b2368bf Mon Sep 17 00:00:00 2001 From: Andrew Mast Date: Fri, 25 Apr 2025 10:21:17 -0500 Subject: [PATCH 430/455] [12.x] Fix double query in model relation serialization (#55547) * fix: only load missing relations when restoring model * fix: disable lazy loading for model serialization test to prevent failure * feat: add test for reloading serialized relationships only once --- .../SerializesAndRestoresModelIdentifiers.php | 2 +- .../Queue/ModelSerializationTest.php | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php b/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php index 09fbf4829e7c..25549425b7c0 100644 --- a/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php +++ b/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php @@ -107,7 +107,7 @@ public function restoreModel($value) { return $this->getQueryForModelRestoration( (new $value->class)->setConnection($value->connection), $value->id - )->useWritePdo()->firstOrFail()->load($value->relations ?? []); + )->useWritePdo()->firstOrFail()->loadMissing($value->relations ?? []); } /** diff --git a/tests/Integration/Queue/ModelSerializationTest.php b/tests/Integration/Queue/ModelSerializationTest.php index bd3b401c6576..e13cbb4ec293 100644 --- a/tests/Integration/Queue/ModelSerializationTest.php +++ b/tests/Integration/Queue/ModelSerializationTest.php @@ -31,6 +31,8 @@ protected function setUp(): void { parent::setUp(); + Model::preventLazyLoading(false); + Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('email'); @@ -161,6 +163,28 @@ public function testItReloadsRelationships() $this->assertEquals($unSerialized->order->getRelations(), $order->getRelations()); } + public function testItReloadsRelationshipsOnlyOnce() + { + $order = tap(ModelSerializationTestCustomOrder::create(), function (ModelSerializationTestCustomOrder $order) { + $order->wasRecentlyCreated = false; + }); + + $product1 = Product::create(); + $product2 = Product::create(); + + Line::create(['order_id' => $order->id, 'product_id' => $product1->id]); + Line::create(['order_id' => $order->id, 'product_id' => $product2->id]); + + $order->load('line', 'lines', 'products'); + + $this->expectsDatabaseQueryCount(4); + + $serialized = serialize(new ModelRelationSerializationTestClass($order)); + $unSerialized = unserialize($serialized); + + $this->assertEquals($unSerialized->order->getRelations(), $order->getRelations()); + } + public function testItReloadsNestedRelationships() { $order = tap(Order::create(), function (Order $order) { @@ -433,6 +457,29 @@ public function newCollection(array $models = []) } } +class ModelSerializationTestCustomOrder extends Model +{ + public $table = 'orders'; + public $guarded = []; + public $timestamps = false; + public $with = ['line', 'lines', 'products']; + + public function line() + { + return $this->hasOne(Line::class, 'order_id'); + } + + public function lines() + { + return $this->hasMany(Line::class, 'order_id'); + } + + public function products() + { + return $this->belongsToMany(Product::class, 'lines', 'order_id'); + } +} + class Order extends Model { public $guarded = []; From fef0498be5f61ce5fae45a8a8a0056a963164098 Mon Sep 17 00:00:00 2001 From: Serhii Litvinchuk Date: Fri, 25 Apr 2025 18:59:34 +0300 Subject: [PATCH 431/455] [12.x] Improve circular relation check in Automatic Relation Loading (#55542) * [12.x] Improve circular relation check in Automatic Relation Loading * [12.x] Improve circular relation check in Automatic Relation Loading * Remove unnecesary argument * Add more tests * Fix cs * update tests * Update HasRelationships.php --------- Co-authored-by: Taylor Otwell --- .../Database/Eloquent/Collection.php | 2 +- .../Eloquent/Concerns/HasRelationships.php | 25 ++++++--- .../EloquentModelRelationAutoloadTest.php | 55 +++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 05ec0d345a1a..1c9dad35263f 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -761,7 +761,7 @@ public function withRelationshipAutoloading() foreach ($this as $model) { if (! $model->hasRelationAutoloadCallback()) { - $model->autoloadRelationsUsing($callback); + $model->autoloadRelationsUsing($callback, $this); } } diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 79a2f5d98cd0..8382cc183f4a 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -46,6 +46,13 @@ trait HasRelationships */ protected $relationAutoloadCallback = null; + /** + * The relationship autoloader callback context. + * + * @var mixed + */ + protected $relationAutoloadContext = null; + /** * The many to many relationship methods. * @@ -118,10 +125,16 @@ public function hasRelationAutoloadCallback() */ public function autoloadRelationsUsing(Closure $callback, $context = null) { + // Prevent circular relation autoloading... + if ($context && $this->relationAutoloadContext === $context) { + return $this; + } + $this->relationAutoloadCallback = $callback; + $this->relationAutoloadContext = $context; foreach ($this->relations as $key => $value) { - $this->propagateRelationAutoloadCallbackToRelation($key, $value, $context); + $this->propagateRelationAutoloadCallbackToRelation($key, $value); } return $this; @@ -163,10 +176,9 @@ protected function invokeRelationAutoloadCallbackFor($key, $tuples) * * @param string $key * @param mixed $models - * @param mixed $context * @return void */ - protected function propagateRelationAutoloadCallbackToRelation($key, $models, $context = null) + protected function propagateRelationAutoloadCallbackToRelation($key, $models) { if (! $this->hasRelationAutoloadCallback() || ! $models) { return; @@ -183,10 +195,7 @@ protected function propagateRelationAutoloadCallbackToRelation($key, $models, $c $callback = fn (array $tuples) => $this->invokeRelationAutoloadCallbackFor($key, $tuples); foreach ($models as $model) { - // Check if relation autoload contexts are different to avoid circular relation autoload... - if ((is_null($context) || $context !== $model) && is_object($model) && method_exists($model, 'autoloadRelationsUsing')) { - $model->autoloadRelationsUsing($callback, $context); - } + $model->autoloadRelationsUsing($callback, $this->relationAutoloadContext); } } @@ -1086,7 +1095,7 @@ public function setRelation($relation, $value) { $this->relations[$relation] = $value; - $this->propagateRelationAutoloadCallbackToRelation($relation, $value, $this); + $this->propagateRelationAutoloadCallbackToRelation($relation, $value); return $this; } diff --git a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php index a3f8a5f882f7..03f1d7ca611f 100644 --- a/tests/Integration/Database/EloquentModelRelationAutoloadTest.php +++ b/tests/Integration/Database/EloquentModelRelationAutoloadTest.php @@ -61,6 +61,8 @@ public function testRelationAutoloadForCollection() $this->assertCount(2, DB::getQueryLog()); $this->assertCount(3, $likes); $this->assertTrue($posts[0]->comments[0]->relationLoaded('likes')); + + DB::disableQueryLog(); } public function testRelationAutoloadForSingleModel() @@ -84,6 +86,8 @@ public function testRelationAutoloadForSingleModel() $this->assertCount(2, DB::getQueryLog()); $this->assertCount(2, $likes); $this->assertTrue($post->comments[0]->relationLoaded('likes')); + + DB::disableQueryLog(); } public function testRelationAutoloadWithSerialization() @@ -109,6 +113,50 @@ public function testRelationAutoloadWithSerialization() $this->assertCount(2, DB::getQueryLog()); Model::automaticallyEagerLoadRelationships(false); + + DB::disableQueryLog(); + } + + public function testRelationAutoloadWithCircularRelations() + { + $post = Post::create(); + $comment1 = $post->comments()->create(['parent_id' => null]); + $comment2 = $post->comments()->create(['parent_id' => $comment1->id]); + $post->likes()->create(); + + DB::enableQueryLog(); + + $post->withRelationshipAutoloading(); + $comment = $post->comments->first(); + $comment->setRelation('post', $post); + + $this->assertCount(1, $post->likes); + + $this->assertCount(2, DB::getQueryLog()); + + DB::disableQueryLog(); + } + + public function testRelationAutoloadWithChaperoneRelations() + { + Model::automaticallyEagerLoadRelationships(); + + $post = Post::create(); + $comment1 = $post->comments()->create(['parent_id' => null]); + $comment2 = $post->comments()->create(['parent_id' => $comment1->id]); + $post->likes()->create(); + + DB::enableQueryLog(); + + $post->load('commentsWithChaperone'); + + $this->assertCount(1, $post->likes); + + $this->assertCount(2, DB::getQueryLog()); + + Model::automaticallyEagerLoadRelationships(false); + + DB::disableQueryLog(); } public function testRelationAutoloadVariousNestedMorphRelations() @@ -163,6 +211,8 @@ public function testRelationAutoloadVariousNestedMorphRelations() $this->assertCount(2, $videos); $this->assertTrue($videoLike->relationLoaded('likeable')); $this->assertTrue($videoLike->likeable->relationLoaded('commentable')); + + DB::disableQueryLog(); } } @@ -197,6 +247,11 @@ public function comments() return $this->morphMany(Comment::class, 'commentable'); } + public function commentsWithChaperone() + { + return $this->morphMany(Comment::class, 'commentable')->chaperone(); + } + public function likes() { return $this->morphMany(Like::class, 'likeable'); From bb696544c9b4fec10a19461c19fb9e4f9f70f16b Mon Sep 17 00:00:00 2001 From: Serhii Litvinchuk Date: Mon, 28 Apr 2025 20:55:41 +0300 Subject: [PATCH 432/455] [12.x] Prevent relation autoload context from being serialized (#55582) --- src/Illuminate/Database/Eloquent/Model.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index be5a2b3f1dbe..72d7e3315e36 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -2502,6 +2502,7 @@ public function __sleep() $this->classCastCache = []; $this->attributeCastCache = []; $this->relationAutoloadCallback = null; + $this->relationAutoloadContext = null; return array_keys(get_object_vars($this)); } From 17a53e1d0ba0c788e30093430a1991676c3f5227 Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Mon, 28 Apr 2025 20:57:01 +0300 Subject: [PATCH 433/455] Remove docblock (#55580) --- src/Illuminate/Console/Concerns/InteractsWithIO.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Console/Concerns/InteractsWithIO.php b/src/Illuminate/Console/Concerns/InteractsWithIO.php index f839ce463499..33a4b726377b 100644 --- a/src/Illuminate/Console/Concerns/InteractsWithIO.php +++ b/src/Illuminate/Console/Concerns/InteractsWithIO.php @@ -19,8 +19,6 @@ trait InteractsWithIO * The console components factory. * * @var \Illuminate\Console\View\Components\Factory - * - * @internal This property is not meant to be used or overwritten outside the framework. */ protected $components; From 9a06826f6587a77544e753178f0987481007c151 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Tue, 29 Apr 2025 03:58:16 +1000 Subject: [PATCH 434/455] Ensure fake job implements job contract (#55574) --- src/Illuminate/Queue/Jobs/FakeJob.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Jobs/FakeJob.php b/src/Illuminate/Queue/Jobs/FakeJob.php index ef1d4e8bc04a..e3567d1f70e2 100644 --- a/src/Illuminate/Queue/Jobs/FakeJob.php +++ b/src/Illuminate/Queue/Jobs/FakeJob.php @@ -2,9 +2,10 @@ namespace Illuminate\Queue\Jobs; +use Illuminate\Contracts\Queue\Job as JobContract; use Illuminate\Support\Str; -class FakeJob extends Job +class FakeJob extends Job implements JobContract { /** * The number of seconds the released job was delayed. From 797c2bbd6701d13650a24697ab62529dc3df9fb9 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Mon, 28 Apr 2025 19:58:31 +0200 Subject: [PATCH 435/455] Fix `AnyOf` constructor parameter type (#55577) --- src/Illuminate/Validation/Rules/AnyOf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Rules/AnyOf.php b/src/Illuminate/Validation/Rules/AnyOf.php index 9d653bdaadbe..a27b20c98100 100644 --- a/src/Illuminate/Validation/Rules/AnyOf.php +++ b/src/Illuminate/Validation/Rules/AnyOf.php @@ -27,7 +27,7 @@ class AnyOf implements Rule, ValidatorAwareRule /** * Sets the validation rules to match against. * - * @param Illuminate\Contracts\Validation\ValidationRule[][] $rules + * @param array $rules * * @throws \InvalidArgumentException */ From f3ae4142cad82933c03a1bb4a33cf6d857faa0ec Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 29 Apr 2025 15:13:30 +0200 Subject: [PATCH 436/455] Sync changes to Illuminate components before release (#55591) --- .github/workflows/releases.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 44eac187dddc..95cff5c85f35 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -57,6 +57,9 @@ jobs: script: | core.setFailed('Workflow failed. Release version does not match with selected target branch. Did you select the correct branch?') + - name: Sync any changes to Illuminate components + run: ./bin/split.sh + - name: Update Application.php version run: sed -i "s/const VERSION = '.*';/const VERSION = '${{ steps.version.outputs.version }}';/g" src/Illuminate/Foundation/Application.php From 30aeb8a41e6dcdbf6d9cab8cb3204f76719ff3c3 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> Date: Tue, 29 Apr 2025 10:13:22 -0400 Subject: [PATCH 437/455] set class-string generics (#55588) --- src/Illuminate/Validation/Rules/Enum.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Validation/Rules/Enum.php b/src/Illuminate/Validation/Rules/Enum.php index d100dca4d8ff..4ffd6ec70efe 100644 --- a/src/Illuminate/Validation/Rules/Enum.php +++ b/src/Illuminate/Validation/Rules/Enum.php @@ -16,7 +16,7 @@ class Enum implements Rule, ValidatorAwareRule /** * The type of the enum. * - * @var class-string + * @var class-string<\UnitEnum> */ protected $type; @@ -44,7 +44,7 @@ class Enum implements Rule, ValidatorAwareRule /** * Create a new rule instance. * - * @param class-string $type + * @param class-string<\UnitEnum> $type */ public function __construct($type) { From 5d5a00e947bc5319218ca0deca80ff7884671939 Mon Sep 17 00:00:00 2001 From: Takayasu Oyama Date: Tue, 29 Apr 2025 23:23:22 +0900 Subject: [PATCH 438/455] [12.x] added detailed doc types to bindings related methods (#55576) * [12.x] added detailed doc types to bindings related methods * fix styling --- src/Illuminate/Database/Query/Builder.php | 31 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index c1fa22a9d7f8..1f00b7bd655f 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -63,7 +63,17 @@ class Builder implements BuilderContract /** * The current query value bindings. * - * @var array + * @var array{ + * select: list, + * from: list, + * join: list, + * where: list, + * groupBy: list, + * having: list, + * order: list, + * union: list, + * unionOrder: list, + * } */ public $bindings = [ 'select' => [], @@ -4127,7 +4137,7 @@ public function getOffset() /** * Get the current query value bindings in a flattened array. * - * @return array + * @return list */ public function getBindings() { @@ -4137,7 +4147,17 @@ public function getBindings() /** * Get the raw array of bindings. * - * @return array + * @return array{ + * select: list, + * from: list, + * join: list, + * where: list, + * groupBy: list, + * having: list, + * order: list, + * union: list, + * unionOrder: list, + * } */ public function getRawBindings() { @@ -4147,6 +4167,7 @@ public function getRawBindings() /** * Set the bindings on the query builder. * + * @param list $bindings * @param string $type * @return $this * @@ -4208,6 +4229,7 @@ public function castBinding($value) /** * Merge an array of bindings into our bindings. * + * @param self $query * @return $this */ public function mergeBindings(self $query) @@ -4220,7 +4242,8 @@ public function mergeBindings(self $query) /** * Remove all of the expressions from a list of bindings. * - * @return array + * @param array $bindings + * @return list */ public function cleanBindings(array $bindings) { From d74311dab099b0561f90fff0ea4611ac86033719 Mon Sep 17 00:00:00 2001 From: Ro Date: Tue, 29 Apr 2025 13:38:45 -0600 Subject: [PATCH 439/455] [12.x] Improve @use directive to support function and const modifiers (#55583) * refactor use statement compiler to support modifiers function and const * fix target php version * fix code style * Formatting --------- Co-authored-by: Taylor Otwell --- .../Concerns/CompilesUseStatements.php | 31 ++++++--- tests/View/Blade/BladeUseTest.php | 66 +++++++++++++++++++ 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php b/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php index 49a524a5fd9f..cefd5fd6eb94 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesUseStatements.php @@ -12,20 +12,35 @@ trait CompilesUseStatements */ protected function compileUse($expression) { - $expression = preg_replace('/[()]/', '', $expression); + $expression = trim(preg_replace('/[()]/', '', $expression), " '\""); - // Preserve grouped imports as-is... + // Isolate alias... if (str_contains($expression, '{')) { - $use = ltrim(trim($expression, " '\""), '\\'); + $pathWithOptionalModifier = $expression; + $aliasWithLeadingSpace = ''; + } else { + $segments = explode(',', $expression); + $pathWithOptionalModifier = trim($segments[0], " '\""); - return ""; + $aliasWithLeadingSpace = isset($segments[1]) + ? ' as '.trim($segments[1], " '\"") + : ''; } - $segments = explode(',', $expression); + // Split modifier and path... + if (str_starts_with($pathWithOptionalModifier, 'function ')) { + $modifierWithTrailingSpace = 'function '; + $path = explode(' ', $pathWithOptionalModifier, 2)[1] ?? $pathWithOptionalModifier; + } elseif (str_starts_with($pathWithOptionalModifier, 'const ')) { + $modifierWithTrailingSpace = 'const '; + $path = explode(' ', $pathWithOptionalModifier, 2)[1] ?? $pathWithOptionalModifier; + } else { + $modifierWithTrailingSpace = ''; + $path = $pathWithOptionalModifier; + } - $use = ltrim(trim($segments[0], " '\""), '\\'); - $as = isset($segments[1]) ? ' as '.trim($segments[1], " '\"") : ''; + $path = ltrim($path, '\\'); - return ""; + return ""; } } diff --git a/tests/View/Blade/BladeUseTest.php b/tests/View/Blade/BladeUseTest.php index 980a266128a6..28072b64559c 100644 --- a/tests/View/Blade/BladeUseTest.php +++ b/tests/View/Blade/BladeUseTest.php @@ -69,4 +69,70 @@ public function testUseStatementWithBracesAndBackslashAreCompiledCorrectly() $string = "Foo @use(\SomeNamespace\{Foo, Bar}) bar"; $this->assertEquals($expected, $this->compiler->compileString($string)); } + + public function testUseStatementsWithModifiersAreCompiled() + { + $expected = 'Foo bar'; + + $string = "Foo @use('function SomeNamespace\SomeFunction', 'Foo') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = 'Foo @use(function SomeNamespace\SomeFunction, Foo) bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testUseStatementsWithModifiersWithoutAliasAreCompiled() + { + $expected = 'Foo bar'; + + $string = "Foo @use('const SomeNamespace\SOME_CONST') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = 'Foo @use(const SomeNamespace\SOME_CONST) bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testUseStatementsWithModifiersAndBackslashAtBeginningAreCompiled() + { + $expected = 'Foo bar'; + + $string = "Foo @use('function \SomeNamespace\SomeFunction') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = 'Foo @use(function \SomeNamespace\SomeFunction) bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testUseStatementsWithModifiersBackslashAtBeginningAndAliasedAreCompiled() + { + $expected = 'Foo bar'; + + $string = "Foo @use('const \SomeNamespace\SOME_CONST', 'Foo') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = 'Foo @use(const \SomeNamespace\SOME_CONST, Foo) bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testUseStatementsWithModifiersWithBracesAreCompiledCorrectly() + { + $expected = 'Foo bar'; + + $string = "Foo @use('function SomeNamespace\{Foo, Bar}') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = 'Foo @use(function SomeNamespace\{Foo, Bar}) bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testUseFunctionStatementWithBracesAndBackslashAreCompiledCorrectly() + { + $expected = 'Foo bar'; + + $string = "Foo @use('const \SomeNamespace\{FOO, BAR}') bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + + $string = 'Foo @use(const \SomeNamespace\{FOO, BAR}) bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } } From 1deaa36de67da614cccc7b84bb38093735a02b99 Mon Sep 17 00:00:00 2001 From: Achraf AAMRI <36072352+achrafAa@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:56:38 +0000 Subject: [PATCH 440/455] 12.x scheduled task failed not dispatched on scheduled task failing (#55572) * Enhance ScheduleRunCommand to dispatch failure events and add integration test - Updated `ScheduleRunCommand` to dispatch `ScheduledTaskFailed` event when a scheduled command fails. - Added handling for exit codes to improve error reporting. - Introduced `ScheduleRunCommandTest` to verify that failure events are dispatched correctly for failing scheduled tasks. * Enhance ScheduleRunCommand to dispatch failure events and add integration test - Updated `ScheduleRunCommand` to dispatch `ScheduledTaskFailed` event when a scheduled command fails. - Added handling for exit codes to improve error reporting. - Introduced `ScheduleRunCommandTest` to verify that failure events are dispatched correctly for failing scheduled tasks. * Enhance ScheduleRunCommand to dispatch failure events and add integration test - Updated `ScheduleRunCommand` to dispatch `ScheduledTaskFailed` event when a scheduled command fails. - Added handling for exit codes to improve error reporting. - Introduced `ScheduleRunCommandTest` to verify that failure events are dispatched correctly for failing scheduled tasks. * remove the test class as it's not consistent due to the event scheduling testing complication * remove the test class as it's not consistent due to the event scheduling testing complication * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Console/Scheduling/ScheduleRunCommand.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php index 75cb579925cf..047577372b18 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php @@ -2,6 +2,7 @@ namespace Illuminate\Console\Scheduling; +use Exception; use Illuminate\Console\Application; use Illuminate\Console\Command; use Illuminate\Console\Events\ScheduledTaskFailed; @@ -196,6 +197,10 @@ protected function runEvent($event) round(microtime(true) - $start, 2) )); + if ($event->exitCode !== 0) { + throw new Exception("Scheduled command [{$event->command}] failed with exit code [{$event->exitCode}]."); + } + $this->eventsRan = true; } catch (Throwable $e) { $this->dispatcher->dispatch(new ScheduledTaskFailed($event, $e)); From 186debcf9a5f82107676e9c44d87f4fa0c4e7900 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Tue, 29 Apr 2025 22:11:04 +0200 Subject: [PATCH 441/455] [12.x] Introduce Reflector methods for accessing class attributes (#55568) * [12.x] Introduce helper functions for accessing class attributes * fix tests * move functions to Reflector class * rename to getClassAttribute(s) * formatting --------- Co-authored-by: Sergey Danilchenko Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Reflector.php | 41 +++++++++++++ .../Fixtures/ClassesWithAttributes.php | 41 +++++++++++++ tests/Support/SupportReflectorTest.php | 57 +++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 tests/Support/Fixtures/ClassesWithAttributes.php diff --git a/src/Illuminate/Support/Reflector.php b/src/Illuminate/Support/Reflector.php index a767d5ea7073..f5eb72f0fcdd 100644 --- a/src/Illuminate/Support/Reflector.php +++ b/src/Illuminate/Support/Reflector.php @@ -2,6 +2,7 @@ namespace Illuminate\Support; +use ReflectionAttribute; use ReflectionClass; use ReflectionEnum; use ReflectionMethod; @@ -56,6 +57,46 @@ public static function isCallable($var, $syntaxOnly = false) return false; } + /** + * Get the specified class attribute, optionally following an inheritance chain. + * + * @template TAttribute of object + * + * @param object|class-string $objectOrClass + * @param class-string $attribute + * @return TAttribute|null + */ + public static function getClassAttribute($objectOrClass, $attribute, $ascend = false) + { + return static::getClassAttributes($objectOrClass, $attribute, $ascend)->flatten()->first(); + } + + /** + * Get the specified class attribute(s), optionally following an inheritance chain. + * + * @template TTarget of object + * @template TAttribute of object + * + * @param TTarget|class-string $objectOrClass + * @param class-string $attribute + * @return ($includeParents is true ? Collection, Collection> : Collection) + */ + public static function getClassAttributes($objectOrClass, $attribute, $includeParents = false) + { + $reflectionClass = new ReflectionClass($objectOrClass); + + $attributes = []; + + do { + $attributes[$reflectionClass->name] = new Collection(array_map( + fn (ReflectionAttribute $reflectionAttribute) => $reflectionAttribute->newInstance(), + $reflectionClass->getAttributes($attribute) + )); + } while ($includeParents && false !== $reflectionClass = $reflectionClass->getParentClass()); + + return $includeParents ? new Collection($attributes) : reset($attributes); + } + /** * Get the class name of the given parameter's type, if possible. * diff --git a/tests/Support/Fixtures/ClassesWithAttributes.php b/tests/Support/Fixtures/ClassesWithAttributes.php new file mode 100644 index 000000000000..baed29f97fd3 --- /dev/null +++ b/tests/Support/Fixtures/ClassesWithAttributes.php @@ -0,0 +1,41 @@ +assertFalse(Reflector::isCallable(['TotallyMissingClass', 'foo'])); $this->assertTrue(Reflector::isCallable(['TotallyMissingClass', 'foo'], true)); } + + public function testGetClassAttributes() + { + require_once __DIR__.'/Fixtures/ClassesWithAttributes.php'; + + $this->assertSame([], Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\UnusedAttr::class)->toArray()); + + $this->assertSame( + [Fixtures\ChildClass::class => [], Fixtures\ParentClass::class => []], + Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\UnusedAttr::class, true)->toArray() + ); + + $this->assertSame( + ['quick', 'brown', 'fox'], + Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\StrAttr::class)->map->string->all() + ); + + $this->assertSame( + ['quick', 'brown', 'fox', 'lazy', 'dog'], + Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\StrAttr::class, true)->flatten()->map->string->all() + ); + + $this->assertSame(7, Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\NumAttr::class)->sum->number); + $this->assertSame(12, Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\NumAttr::class, true)->flatten()->sum->number); + $this->assertSame(5, Reflector::getClassAttributes(Fixtures\ParentClass::class, Fixtures\NumAttr::class)->sum->number); + $this->assertSame(5, Reflector::getClassAttributes(Fixtures\ParentClass::class, Fixtures\NumAttr::class, true)->flatten()->sum->number); + + $this->assertSame( + [Fixtures\ChildClass::class, Fixtures\ParentClass::class], + Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\StrAttr::class, true)->keys()->all() + ); + + $this->assertContainsOnlyInstancesOf( + Fixtures\StrAttr::class, + Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\StrAttr::class)->all() + ); + + $this->assertContainsOnlyInstancesOf( + Fixtures\StrAttr::class, + Reflector::getClassAttributes(Fixtures\ChildClass::class, Fixtures\StrAttr::class, true)->flatten()->all() + ); + } + + public function testGetClassAttribute() + { + require_once __DIR__.'/Fixtures/ClassesWithAttributes.php'; + + $this->assertNull(Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\UnusedAttr::class)); + $this->assertNull(Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\UnusedAttr::class, true)); + $this->assertNull(Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\ParentOnlyAttr::class)); + $this->assertInstanceOf(Fixtures\ParentOnlyAttr::class, Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\ParentOnlyAttr::class, true)); + $this->assertInstanceOf(Fixtures\StrAttr::class, Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\StrAttr::class)); + $this->assertInstanceOf(Fixtures\StrAttr::class, Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\StrAttr::class, true)); + $this->assertSame('quick', Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\StrAttr::class)->string); + $this->assertSame('quick', Reflector::getClassAttribute(Fixtures\ChildClass::class, Fixtures\StrAttr::class, true)->string); + $this->assertSame('lazy', Reflector::getClassAttribute(Fixtures\ParentClass::class, Fixtures\StrAttr::class)->string); + } } class A From 7f5c15f173ec628b1d876a04ad4c36995e246cad Mon Sep 17 00:00:00 2001 From: Anthony Tibbs Date: Tue, 29 Apr 2025 16:14:54 -0400 Subject: [PATCH 442/455] [12.x] Typed getters for Arr helper (#55567) * add typed array value getters to Arr support class * add tests for Arr typed array value getters * cleanup: remove nullable returns (not possible) * cleanup: style CI fixup * cleanup: style CI fixup * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Collections/Arr.php | 80 +++++++++++++++++++++++ tests/Support/SupportArrTest.php | 100 +++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index e4ef759c8f61..d9b7561db2cf 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -40,6 +40,38 @@ public static function add($array, $key, $value) return $array; } + /** + * Get an array item from an array using "dot" notation. + */ + public static function array(ArrayAccess|array $array, string|int|null $key, ?array $default = null): array + { + $value = Arr::get($array, $key, $default); + + if (! is_array($value)) { + throw new InvalidArgumentException( + sprintf('Array value for key [%s] must be an array, %s found.', $key, gettype($value)) + ); + } + + return $value; + } + + /** + * Get a boolean item from an array using "dot" notation. + */ + public static function boolean(ArrayAccess|array $array, string|int|null $key, ?bool $default = null): bool + { + $value = Arr::get($array, $key, $default); + + if (! is_bool($value)) { + throw new InvalidArgumentException( + sprintf('Array value for key [%s] must be a boolean, %s found.', $key, gettype($value)) + ); + } + + return $value; + } + /** * Collapse an array of arrays into a single array. * @@ -286,6 +318,22 @@ public static function flatten($array, $depth = INF) return $result; } + /** + * Get a float item from an array using "dot" notation. + */ + public static function float(ArrayAccess|array $array, string|int|null $key, ?float $default = null): float + { + $value = Arr::get($array, $key, $default); + + if (! is_float($value)) { + throw new InvalidArgumentException( + sprintf('Array value for key [%s] must be a float, %s found.', $key, gettype($value)) + ); + } + + return $value; + } + /** * Remove one or many array items from a given array using "dot" notation. * @@ -433,6 +481,22 @@ public static function hasAny($array, $keys) return false; } + /** + * Get an integer item from an array using "dot" notation. + */ + public static function integer(ArrayAccess|array $array, string|int|null $key, ?int $default = null): int + { + $value = Arr::get($array, $key, $default); + + if (! is_integer($value)) { + throw new InvalidArgumentException( + sprintf('Array value for key [%s] must be an integer, %s found.', $key, gettype($value)) + ); + } + + return $value; + } + /** * Determines if an array is associative. * @@ -906,6 +970,22 @@ public static function sortRecursiveDesc($array, $options = SORT_REGULAR) return static::sortRecursive($array, $options, true); } + /** + * Get a string item from an array using "dot" notation. + */ + public static function string(ArrayAccess|array $array, string|int|null $key, ?string $default = null): string + { + $value = Arr::get($array, $key, $default); + + if (! is_string($value)) { + throw new InvalidArgumentException( + sprintf('Array value for key [%s] must be a string, %s found.', $key, gettype($value)) + ); + } + + return $value; + } + /** * Conditionally compile classes from an array into a CSS class list. * diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 856119824752..e5d15a06362f 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -516,6 +516,106 @@ public function testGet() $this->assertSame('bar', Arr::get(['' => ['' => 'bar']], '.')); } + public function testItGetsAString() + { + $test_array = ['string' => 'foo bar', 'integer' => 1234]; + + // Test string values are returned as strings + $this->assertSame( + 'foo bar', Arr::string($test_array, 'string') + ); + + // Test that default string values are returned for missing keys + $this->assertSame( + 'default', Arr::string($test_array, 'missing_key', 'default') + ); + + // Test that an exception is raised if the value is not a string + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('#^Array value for key \[integer\] must be a string, (.*) found.#'); + Arr::string($test_array, 'integer'); + } + + public function testItGetsAnInteger() + { + $test_array = ['string' => 'foo bar', 'integer' => 1234]; + + // Test integer values are returned as integers + $this->assertSame( + 1234, Arr::integer($test_array, 'integer') + ); + + // Test that default integer values are returned for missing keys + $this->assertSame( + 999, Arr::integer($test_array, 'missing_key', 999) + ); + + // Test that an exception is raised if the value is not an integer + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('#^Array value for key \[string\] must be an integer, (.*) found.#'); + Arr::integer($test_array, 'string'); + } + + public function testItGetsAFloat() + { + $test_array = ['string' => 'foo bar', 'float' => 12.34]; + + // Test float values are returned as floats + $this->assertSame( + 12.34, Arr::float($test_array, 'float') + ); + + // Test that default float values are returned for missing keys + $this->assertSame( + 56.78, Arr::float($test_array, 'missing_key', 56.78) + ); + + // Test that an exception is raised if the value is not a float + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('#^Array value for key \[string\] must be a float, (.*) found.#'); + Arr::float($test_array, 'string'); + } + + public function testItGetsABoolean() + { + $test_array = ['string' => 'foo bar', 'boolean' => true]; + + // Test boolean values are returned as booleans + $this->assertSame( + true, Arr::boolean($test_array, 'boolean') + ); + + // Test that default boolean values are returned for missing keys + $this->assertSame( + true, Arr::boolean($test_array, 'missing_key', true) + ); + + // Test that an exception is raised if the value is not a boolean + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('#^Array value for key \[string\] must be a boolean, (.*) found.#'); + Arr::boolean($test_array, 'string'); + } + + public function testItGetsAnArray() + { + $test_array = ['string' => 'foo bar', 'array' => ['foo', 'bar']]; + + // Test array values are returned as arrays + $this->assertSame( + ['foo', 'bar'], Arr::array($test_array, 'array') + ); + + // Test that default array values are returned for missing keys + $this->assertSame( + [1, 'two'], Arr::array($test_array, 'missing_key', [1, 'two']) + ); + + // Test that an exception is raised if the value is not an array + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('#^Array value for key \[string\] must be an array, (.*) found.#'); + Arr::array($test_array, 'string'); + } + public function testHas() { $array = ['products.desk' => ['price' => 100]]; From 9d21158651aa5904579ef95a30dd0249c0cc50f0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 29 Apr 2025 15:17:35 -0500 Subject: [PATCH 443/455] wip --- .github/workflows/releases.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 95cff5c85f35..44eac187dddc 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -57,9 +57,6 @@ jobs: script: | core.setFailed('Workflow failed. Release version does not match with selected target branch. Did you select the correct branch?') - - name: Sync any changes to Illuminate components - run: ./bin/split.sh - - name: Update Application.php version run: sed -i "s/const VERSION = '.*';/const VERSION = '${{ steps.version.outputs.version }}';/g" src/Illuminate/Foundation/Application.php From 050b2dfeaf6fff9e08e84b355822636492fb45f4 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 29 Apr 2025 20:18:16 +0000 Subject: [PATCH 444/455] Update version to v12.11.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 3c491b0544b2..9a18e7737177 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.10.2'; + const VERSION = '12.11.0'; /** * The base path for the Laravel installation. From bcc92201ab6d786477fed578cc2e3ea4c4e1b093 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Tue, 29 Apr 2025 20:20:00 +0000 Subject: [PATCH 445/455] Update CHANGELOG --- CHANGELOG.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b292512610ef..ce120028ef16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.10.2...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.11.0...12.x) + +## [v12.11.0](https://github.com/laravel/framework/compare/v12.10.2...v12.11.0) - 2025-04-29 + +* Add payload creation and original delay info to job payload by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/framework/pull/55529 +* Add config option to ignore view cache timestamps by [@pizkaz](https://github.com/pizkaz) in https://github.com/laravel/framework/pull/55536 +* [12.x] Dispatch NotificationFailed when sending fails by [@rodrigopedra](https://github.com/rodrigopedra) in https://github.com/laravel/framework/pull/55507 +* [12.x] Option to disable dispatchAfterResponse in a test by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/55456 +* [12.x] Pass flags to custom Json::$encoder by [@rodrigopedra](https://github.com/rodrigopedra) in https://github.com/laravel/framework/pull/55548 +* [12.x] Use pendingAttributes of relationships when creating relationship models via model factories by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/55558 +* [12.x] Fix double query in model relation serialization by [@AndrewMast](https://github.com/AndrewMast) in https://github.com/laravel/framework/pull/55547 +* [12.x] Improve circular relation check in Automatic Relation Loading by [@litvinchuk](https://github.com/litvinchuk) in https://github.com/laravel/framework/pull/55542 +* [12.x] Prevent relation autoload context from being serialized by [@litvinchuk](https://github.com/litvinchuk) in https://github.com/laravel/framework/pull/55582 +* Remove `@internal` Annotation from `$components` Property in `InteractsWithIO` by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/55580 +* Ensure fake job implements job contract by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/55574 +* [12.x] Fix `AnyOf` constructor parameter type by [@axlon](https://github.com/axlon) in https://github.com/laravel/framework/pull/55577 +* Sync changes to Illuminate components before release by [@driesvints](https://github.com/driesvints) in https://github.com/laravel/framework/pull/55591 +* [12.x] Set class-string generics on `Enum` rule by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/55588 +* [12.x] added detailed doc types to bindings related methods by [@taka-oyama](https://github.com/taka-oyama) in https://github.com/laravel/framework/pull/55576 +* [12.x] Improve [@use](https://github.com/use) directive to support function and const modifiers by [@rodolfosrg](https://github.com/rodolfosrg) in https://github.com/laravel/framework/pull/55583 +* 12.x scheduled task failed not dispatched on scheduled task failing by [@achrafAa](https://github.com/achrafAa) in https://github.com/laravel/framework/pull/55572 +* [12.x] Introduce Reflector methods for accessing class attributes by [@daniser](https://github.com/daniser) in https://github.com/laravel/framework/pull/55568 +* [12.x] Typed getters for Arr helper by [@tibbsa](https://github.com/tibbsa) in https://github.com/laravel/framework/pull/55567 ## [v12.10.2](https://github.com/laravel/framework/compare/v12.10.1...v12.10.2) - 2025-04-24 From 12befdaad103df2e9c1310b26a78836e1a8c46f5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 30 Apr 2025 08:47:09 -0500 Subject: [PATCH 446/455] =?UTF-8?q?Revert=20"12.x=20scheduled=20task=20fai?= =?UTF-8?q?led=20not=20dispatched=20on=20scheduled=20task=20failing=20(?= =?UTF-8?q?=E2=80=A6"=20(#55612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1deaa36de67da614cccc7b84bb38093735a02b99. --- src/Illuminate/Console/Scheduling/ScheduleRunCommand.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php index 047577372b18..75cb579925cf 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php @@ -2,7 +2,6 @@ namespace Illuminate\Console\Scheduling; -use Exception; use Illuminate\Console\Application; use Illuminate\Console\Command; use Illuminate\Console\Events\ScheduledTaskFailed; @@ -197,10 +196,6 @@ protected function runEvent($event) round(microtime(true) - $start, 2) )); - if ($event->exitCode !== 0) { - throw new Exception("Scheduled command [{$event->command}] failed with exit code [{$event->exitCode}]."); - } - $this->eventsRan = true; } catch (Throwable $e) { $this->dispatcher->dispatch(new ScheduledTaskFailed($event, $e)); From 5b0d72c4479f5244b838373ce6eb138e27aa59d0 Mon Sep 17 00:00:00 2001 From: Jack Bayliss Date: Wed, 30 Apr 2025 14:47:49 +0100 Subject: [PATCH 447/455] [12.x] Resolve issue with BelongsToManyRelationship factory (#55608) * Update BelongsToManyRelationship.php * cs --- .../Eloquent/Factories/BelongsToManyRelationship.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php b/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php index fd350e6fce6c..5498dc856516 100644 --- a/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php +++ b/src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php @@ -50,9 +50,13 @@ public function __construct($factory, $pivot, $relationship) */ public function createFor(Model $model) { - $relationship = $model->{$this->relationship}(); + $factoryInstance = $this->factory instanceof Factory; - Collection::wrap($this->factory instanceof Factory ? $this->factory->prependState($relationship->getQuery()->pendingAttributes)->create([], $model) : $this->factory)->each(function ($attachable) use ($model) { + if ($factoryInstance) { + $relationship = $model->{$this->relationship}(); + } + + Collection::wrap($factoryInstance ? $this->factory->prependState($relationship->getQuery()->pendingAttributes)->create([], $model) : $this->factory)->each(function ($attachable) use ($model) { $model->{$this->relationship}()->attach( $attachable, is_callable($this->pivot) ? call_user_func($this->pivot, $model) : $this->pivot From bd0d62bd9c5196728e428cd695d89ec8640daac1 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:48:39 +0000 Subject: [PATCH 448/455] Update version to v12.11.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 9a18e7737177..85a7387a50fc 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.11.0'; + const VERSION = '12.11.1'; /** * The base path for the Laravel installation. From f9a96f7b5c3b5cce391d22cdc4cc3e3da9f2656a Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:50:25 +0000 Subject: [PATCH 449/455] Update CHANGELOG --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce120028ef16..9ca39ba4620a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Release Notes for 12.x -## [Unreleased](https://github.com/laravel/framework/compare/v12.11.0...12.x) +## [Unreleased](https://github.com/laravel/framework/compare/v12.11.1...12.x) + +## [v12.11.1](https://github.com/laravel/framework/compare/v12.11.0...v12.11.1) - 2025-04-30 + +* Revert "[12.x]`ScheduledTaskFailed` not dispatched on scheduled task failing" by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/framework/pull/55612 +* [12.x] Resolve issue with BelongsToManyRelationship factory by [@jackbayliss](https://github.com/jackbayliss) in https://github.com/laravel/framework/pull/55608 ## [v12.11.0](https://github.com/laravel/framework/compare/v12.10.2...v12.11.0) - 2025-04-29 From ea9c4813bd278d9e172d46f73d295dfb9cd7d372 Mon Sep 17 00:00:00 2001 From: Igor Finagin Date: Wed, 30 Apr 2025 18:33:18 +0400 Subject: [PATCH 450/455] Make Blueprint Resolver Statically (#55607) --- src/Illuminate/Database/Schema/Builder.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 109932a27d12..d70cb9314231 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -9,6 +9,9 @@ use InvalidArgumentException; use LogicException; +/** + * @template TResolver of \Closure(string, \Closure, string): \Illuminate\Database\Schema\Blueprint + */ class Builder { use Macroable; @@ -30,9 +33,9 @@ class Builder /** * The Blueprint resolver callback. * - * @var \Closure + * @var TResolver|null */ - protected $resolver; + protected static $resolver = null; /** * The default string length for migrations. @@ -629,8 +632,8 @@ protected function createBlueprint($table, ?Closure $callback = null) { $connection = $this->connection; - if (isset($this->resolver)) { - return call_user_func($this->resolver, $connection, $table, $callback); + if (static::$resolver !== null) { + return call_user_func(static::$resolver, $connection, $table, $callback); } return Container::getInstance()->make(Blueprint::class, compact('connection', 'table', 'callback')); @@ -698,11 +701,11 @@ public function getConnection() /** * Set the Schema Blueprint resolver callback. * - * @param \Closure $resolver + * @param TResolver|null $resolver * @return void */ - public function blueprintResolver(Closure $resolver) + public function blueprintResolver(?Closure $resolver) { - $this->resolver = $resolver; + static::$resolver = $resolver; } } From b9342ff755dfea947e9d22687d0a0169d568b09e Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Wed, 30 Apr 2025 14:33:58 +0000 Subject: [PATCH 451/455] Update facade docblocks --- src/Illuminate/Support/Facades/Schema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 09d0844c8610..d0e3e5f84bf1 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -44,7 +44,7 @@ * @method static string|null getCurrentSchemaName() * @method static array parseSchemaAndTable(string $reference, string|bool|null $withDefaultSchema = null) * @method static \Illuminate\Database\Connection getConnection() - * @method static void blueprintResolver(\Closure $resolver) + * @method static void blueprintResolver(\Closure|null $resolver) * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) * @method static bool hasMacro(string $name) From c895e4d971649a36f6e3612868d11d849069fed7 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 2 May 2025 00:54:03 +1000 Subject: [PATCH 452/455] [12.x] Allow limiting number of assets to preload (#55618) * Allow limiting number of assets to preload * Lint --- .../AddLinkHeadersForPreloadedAssets.php | 17 +++++++- tests/Http/Middleware/VitePreloadingTest.php | 43 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Middleware/AddLinkHeadersForPreloadedAssets.php b/src/Illuminate/Http/Middleware/AddLinkHeadersForPreloadedAssets.php index 7c1de1dae942..247c1507c506 100644 --- a/src/Illuminate/Http/Middleware/AddLinkHeadersForPreloadedAssets.php +++ b/src/Illuminate/Http/Middleware/AddLinkHeadersForPreloadedAssets.php @@ -8,18 +8,31 @@ class AddLinkHeadersForPreloadedAssets { + /** + * Configure the middleware. + * + * @param int $limit + * @return string + */ + public static function using($limit) + { + return static::class.':'.$limit; + } + /** * Handle the incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next + * @param int $limit * @return \Illuminate\Http\Response */ - public function handle($request, $next) + public function handle($request, $next, $limit = null) { - return tap($next($request), function ($response) { + return tap($next($request), function ($response) use ($limit) { if ($response instanceof Response && Vite::preloadedAssets() !== []) { $response->header('Link', (new Collection(Vite::preloadedAssets())) + ->when($limit, fn ($assets, $limit) => $assets->take($limit)) ->map(fn ($attributes, $url) => "<{$url}>; ".implode('; ', $attributes)) ->join(', '), false); } diff --git a/tests/Http/Middleware/VitePreloadingTest.php b/tests/Http/Middleware/VitePreloadingTest.php index 4fb11f8b0b37..765ee029590a 100644 --- a/tests/Http/Middleware/VitePreloadingTest.php +++ b/tests/Http/Middleware/VitePreloadingTest.php @@ -106,4 +106,47 @@ public function testItDoesNotOverwriteOtherLinkHeaders() $response->headers->all('Link'), ); } + + public function testItCanLimitNumberOfAssetsPreloaded() + { + $app = new Container; + $app->instance(Vite::class, new class extends Vite + { + protected $preloadedAssets = [ + 'https://laravel.com/first.js' => [ + 'rel="modulepreload"', + 'foo="bar"', + ], + 'https://laravel.com/second.js' => [ + 'rel="modulepreload"', + 'foo="bar"', + ], + 'https://laravel.com/third.js' => [ + 'rel="modulepreload"', + 'foo="bar"', + ], + 'https://laravel.com/fourth.js' => [ + 'rel="modulepreload"', + 'foo="bar"', + ], + ]; + }); + Facade::setFacadeApplication($app); + + $response = (new AddLinkHeadersForPreloadedAssets)->handle(new Request, fn () => new Response('ok'), 2); + + $this->assertSame( + [ + '; rel="modulepreload"; foo="bar", ; rel="modulepreload"; foo="bar"', + ], + $response->headers->all('Link'), + ); + } + + public function test_it_can_configure_the_middleware() + { + $definition = AddLinkHeadersForPreloadedAssets::using(limit: 5); + + $this->assertSame('Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets:5', $definition); + } } From b0cb2377f1532ec71de2ec078431a2679becbabe Mon Sep 17 00:00:00 2001 From: Will Rowe Date: Thu, 1 May 2025 11:12:16 -0400 Subject: [PATCH 453/455] [12.x] Set job instance on "failed" command instance (#55617) * Add failing test * Update test to expect the new argument * Set the job instance when creating a new instance of command after failure * Update CallQueuedHandler.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Queue/CallQueuedHandler.php | 7 +++- src/Illuminate/Queue/Jobs/Job.php | 2 +- tests/Queue/QueueBeanstalkdJobTest.php | 3 +- tests/Queue/QueueSyncQueueTest.php | 39 ++++++++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index 0da7e735ca39..c7b887a4d953 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -274,12 +274,17 @@ protected function ensureUniqueJobLockIsReleasedViaContext() * @param array $data * @param \Throwable|null $e * @param string $uuid + * @param \Illuminate\Contracts\Queue\Job|null $job * @return void */ - public function failed(array $data, $e, string $uuid) + public function failed(array $data, $e, string $uuid, ?Job $job = null) { $command = $this->getCommand($data); + if (! is_null($job)) { + $command = $this->setJobInstanceIfNecessary($job, $command); + } + if (! $command instanceof ShouldBeUniqueUntilProcessing) { $this->ensureUniqueJobLockIsReleased($command); } diff --git a/src/Illuminate/Queue/Jobs/Job.php b/src/Illuminate/Queue/Jobs/Job.php index 8ec6ac54f805..112501b26580 100755 --- a/src/Illuminate/Queue/Jobs/Job.php +++ b/src/Illuminate/Queue/Jobs/Job.php @@ -251,7 +251,7 @@ protected function failed($e) [$class, $method] = JobName::parse($payload['job']); if (method_exists($this->instance = $this->resolve($class), 'failed')) { - $this->instance->failed($payload['data'], $e, $payload['uuid'] ?? ''); + $this->instance->failed($payload['data'], $e, $payload['uuid'] ?? '', $this); } } diff --git a/tests/Queue/QueueBeanstalkdJobTest.php b/tests/Queue/QueueBeanstalkdJobTest.php index 514555001e67..1405cb3f0712 100755 --- a/tests/Queue/QueueBeanstalkdJobTest.php +++ b/tests/Queue/QueueBeanstalkdJobTest.php @@ -7,6 +7,7 @@ use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Queue\Events\JobFailed; use Illuminate\Queue\Jobs\BeanstalkdJob; +use Illuminate\Queue\Jobs\Job; use Mockery as m; use Pheanstalk\Contract\JobIdInterface; use Pheanstalk\Contract\PheanstalkManagerInterface; @@ -39,7 +40,7 @@ public function testFailProperlyCallsTheJobHandler() $job->getPheanstalkJob()->shouldReceive('getData')->andReturn(json_encode(['job' => 'foo', 'uuid' => 'test-uuid', 'data' => ['data']])); $job->getContainer()->shouldReceive('make')->once()->with('foo')->andReturn($handler = m::mock(BeanstalkdJobTestFailedTest::class)); $job->getPheanstalk()->shouldReceive('delete')->once()->with($job->getPheanstalkJob())->andReturnSelf(); - $handler->shouldReceive('failed')->once()->with(['data'], m::type(Exception::class), 'test-uuid'); + $handler->shouldReceive('failed')->once()->with(['data'], m::type(Exception::class), 'test-uuid', m::type(Job::class)); $job->getContainer()->shouldReceive('make')->once()->with(Dispatcher::class)->andReturn($events = m::mock(Dispatcher::class)); $events->shouldReceive('dispatch')->once()->with(m::type(JobFailed::class))->andReturnNull(); diff --git a/tests/Queue/QueueSyncQueueTest.php b/tests/Queue/QueueSyncQueueTest.php index e7aab86ad779..901f66c2d75e 100755 --- a/tests/Queue/QueueSyncQueueTest.php +++ b/tests/Queue/QueueSyncQueueTest.php @@ -61,6 +61,28 @@ public function testFailedJobGetsHandledWhenAnExceptionIsThrown() Container::setInstance(); } + public function testFailedJobHasAccessToJobInstance() + { + unset($_SERVER['__sync.failed']); + + $sync = new SyncQueue; + $container = new Container; + $container->bind(\Illuminate\Contracts\Events\Dispatcher::class, \Illuminate\Events\Dispatcher::class); + $container->bind(\Illuminate\Contracts\Bus\Dispatcher::class, \Illuminate\Bus\Dispatcher::class); + $container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class); + $sync->setContainer($container); + + SyncQueue::createPayloadUsing(function ($connection, $queue, $payload) { + return ['data' => ['extra' => 'extraValue']]; + }); + + try { + $sync->push(new FailingSyncQueueJob()); + } catch (LogicException $e) { + $this->assertSame('extraValue', $_SERVER['__sync.failed']); + } + } + public function testCreatesPayloadObject() { $sync = new SyncQueue; @@ -177,6 +199,23 @@ public function failed() } } +class FailingSyncQueueJob implements ShouldQueue +{ + use InteractsWithQueue; + + public function handle() + { + throw new LogicException(); + } + + public function failed() + { + $payload = $this->job->payload(); + + $_SERVER['__sync.failed'] = $payload['data']['extra']; + } +} + class SyncQueueJob implements ShouldQueue { use InteractsWithQueue; From 05bd808ec1b3d1ea164912a39480c42f5a0f15e4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 1 May 2025 11:12:19 -0500 Subject: [PATCH 454/455] update api install command --- src/Illuminate/Foundation/Console/ApiInstallCommand.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 9c460555e80a..f8e19c4853f8 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -37,7 +37,7 @@ class ApiInstallCommand extends Command /** * Execute the console command. * - * @return int + * @return void */ public function handle() { @@ -67,12 +67,11 @@ public function handle() } if ($this->option('passport')) { - Process::run(array_filter([ + Process::run([ php_binary(), artisan_binary(), 'passport:install', - $this->confirm('Would you like to use UUIDs for all client IDs?') ? '--uuids' : null, - ])); + ]); $this->components->info('API scaffolding installed. Please add the [Laravel\Passport\HasApiTokens] trait to your User model.'); } else { @@ -150,7 +149,7 @@ protected function installSanctum() protected function installPassport() { $this->requireComposerPackages($this->option('composer'), [ - 'laravel/passport:^12.0', + 'laravel/passport:^13.0', ]); } } From 8f6cd73696068c28f30f5964556ec9d14e5d90d7 Mon Sep 17 00:00:00 2001 From: taylorotwell <463230+taylorotwell@users.noreply.github.com> Date: Thu, 1 May 2025 16:13:12 +0000 Subject: [PATCH 455/455] Update version to v12.12.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 85a7387a50fc..0fed290349c5 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '12.11.1'; + const VERSION = '12.12.0'; /** * The base path for the Laravel installation.