From 3b87b6f972de4445bed7458c810671f2bbc861cb Mon Sep 17 00:00:00 2001 From: dmason30 Date: Tue, 22 Dec 2020 15:11:18 +0000 Subject: [PATCH 001/443] Add command to clean batches table --- src/Illuminate/Bus/BatchRepository.php | 8 ++++ .../Bus/DatabaseBatchRepository.php | 22 ++++++++++ .../Providers/ArtisanServiceProvider.php | 14 +++++++ .../Queue/Console/FlushBatchCommand.php | 40 +++++++++++++++++++ .../Testing/Fakes/BatchRepositoryFake.php | 12 ++++++ 5 files changed, 96 insertions(+) create mode 100644 src/Illuminate/Queue/Console/FlushBatchCommand.php diff --git a/src/Illuminate/Bus/BatchRepository.php b/src/Illuminate/Bus/BatchRepository.php index 098ccef20ed6..978da8204843 100644 --- a/src/Illuminate/Bus/BatchRepository.php +++ b/src/Illuminate/Bus/BatchRepository.php @@ -89,4 +89,12 @@ public function delete(string $batchId); * @return mixed */ public function transaction(Closure $callback); + + /** + * Prune all of the entries older than the given date. + * + * @param \DateTimeInterface $before + * @return int + */ + public function prune(\DateTimeInterface $before); } diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index d911c380d551..a1efdb459654 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -243,6 +243,28 @@ public function transaction(Closure $callback) }); } + /** + * Prune all of the entries older than the given date. + * + * @param \DateTimeInterface $before + * @return int + */ + public function prune(\DateTimeInterface $before) + { + $query = $this->connection->table($this->table) + ->where('finished_at', '<', $before); + + $totalDeleted = 0; + + do { + $deleted = $query->take(1000)->delete(); + + $totalDeleted += $deleted; + } while ($deleted !== 0); + + return $totalDeleted; + } + /** * Convert the given raw batch to a Batch object. * diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 9cce44c00e3f..ec4d7a0ca64b 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -64,6 +64,7 @@ use Illuminate\Queue\Console\ClearCommand as QueueClearCommand; use Illuminate\Queue\Console\FailedTableCommand; use Illuminate\Queue\Console\FlushFailedCommand as FlushFailedQueueCommand; +use Illuminate\Queue\Console\FlushBatchCommand as FlushBatchQueueCommand; use Illuminate\Queue\Console\ForgetFailedCommand as ForgetFailedQueueCommand; use Illuminate\Queue\Console\ListenCommand as QueueListenCommand; use Illuminate\Queue\Console\ListFailedCommand as ListFailedQueueCommand; @@ -105,6 +106,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'QueueClear' => 'command.queue.clear', 'QueueFailed' => 'command.queue.failed', 'QueueFlush' => 'command.queue.flush', + 'QueueFlushBatch' => 'command.queue.flush-batch', 'QueueForget' => 'command.queue.forget', 'QueueListen' => 'command.queue.listen', 'QueueRestart' => 'command.queue.restart', @@ -672,6 +674,18 @@ protected function registerQueueFlushCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerQueueFlushBatchCommand() + { + $this->app->singleton('command.queue.flush-batch', function () { + return new FlushBatchQueueCommand; + }); + } + /** * Register the command. * diff --git a/src/Illuminate/Queue/Console/FlushBatchCommand.php b/src/Illuminate/Queue/Console/FlushBatchCommand.php new file mode 100644 index 000000000000..edfefb03fb1f --- /dev/null +++ b/src/Illuminate/Queue/Console/FlushBatchCommand.php @@ -0,0 +1,40 @@ +option('hours'); + + $before = Carbon::now()->subHours($hours); + + $count = $this->laravel[BatchRepository::class]->prune($before); + + $this->info("{$count} entries deleted successfully."); + } +} diff --git a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php index 55681f4d5534..c3533fa2ea2e 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php @@ -8,6 +8,7 @@ use Illuminate\Bus\BatchRepository; use Illuminate\Bus\PendingBatch; use Illuminate\Bus\UpdatedBatchJobCounts; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\Facade; use Illuminate\Support\Str; @@ -134,4 +135,15 @@ public function transaction(Closure $callback) { return $callback(); } + + /** + * Prune all of the entries older than the given date. + * + * @param \DateTimeInterface $before + * @return int + */ + public function prune(\DateTimeInterface $before) + { + return 0; + } } From a41160515d626f5957129db8ed0c3a5601567dad Mon Sep 17 00:00:00 2001 From: dmason30 Date: Tue, 22 Dec 2020 15:33:14 +0000 Subject: [PATCH 002/443] use timestamp --- src/Illuminate/Bus/DatabaseBatchRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index a1efdb459654..cc56ead8d649 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -252,7 +252,7 @@ public function transaction(Closure $callback) public function prune(\DateTimeInterface $before) { $query = $this->connection->table($this->table) - ->where('finished_at', '<', $before); + ->where('finished_at', '<', $before->getTimestamp()); $totalDeleted = 0; From ee8c0b5abe54a892fb51df1a9ea8337d6d5851d4 Mon Sep 17 00:00:00 2001 From: dmason30 Date: Tue, 22 Dec 2020 15:44:51 +0000 Subject: [PATCH 003/443] linting --- src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php | 2 +- src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index ec4d7a0ca64b..fc46527915a0 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -63,8 +63,8 @@ use Illuminate\Queue\Console\BatchesTableCommand; use Illuminate\Queue\Console\ClearCommand as QueueClearCommand; use Illuminate\Queue\Console\FailedTableCommand; -use Illuminate\Queue\Console\FlushFailedCommand as FlushFailedQueueCommand; use Illuminate\Queue\Console\FlushBatchCommand as FlushBatchQueueCommand; +use Illuminate\Queue\Console\FlushFailedCommand as FlushFailedQueueCommand; use Illuminate\Queue\Console\ForgetFailedCommand as ForgetFailedQueueCommand; use Illuminate\Queue\Console\ListenCommand as QueueListenCommand; use Illuminate\Queue\Console\ListFailedCommand as ListFailedQueueCommand; diff --git a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php index c3533fa2ea2e..41850ab334f0 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php @@ -8,7 +8,6 @@ use Illuminate\Bus\BatchRepository; use Illuminate\Bus\PendingBatch; use Illuminate\Bus\UpdatedBatchJobCounts; -use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\Facade; use Illuminate\Support\Str; From 910fad8cb2934f2c231f806b8b398ba95ef38dfe Mon Sep 17 00:00:00 2001 From: dmason30 Date: Tue, 22 Dec 2020 16:22:59 +0000 Subject: [PATCH 004/443] Remove interface method and add import --- src/Illuminate/Bus/BatchRepository.php | 8 -------- src/Illuminate/Bus/DatabaseBatchRepository.php | 6 ++++-- .../Queue/Console/FlushBatchCommand.php | 16 +++++++++++----- .../Testing/Fakes/BatchRepositoryFake.php | 5 +++-- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Bus/BatchRepository.php b/src/Illuminate/Bus/BatchRepository.php index 978da8204843..098ccef20ed6 100644 --- a/src/Illuminate/Bus/BatchRepository.php +++ b/src/Illuminate/Bus/BatchRepository.php @@ -89,12 +89,4 @@ public function delete(string $batchId); * @return mixed */ public function transaction(Closure $callback); - - /** - * Prune all of the entries older than the given date. - * - * @param \DateTimeInterface $before - * @return int - */ - public function prune(\DateTimeInterface $before); } diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index cc56ead8d649..3f025b06f9f2 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -4,6 +4,7 @@ use Carbon\CarbonImmutable; use Closure; +use DateTimeInterface; use Illuminate\Database\Connection; use Illuminate\Database\Query\Expression; use Illuminate\Support\Str; @@ -246,12 +247,13 @@ public function transaction(Closure $callback) /** * Prune all of the entries older than the given date. * - * @param \DateTimeInterface $before + * @param DateTimeInterface $before * @return int */ - public function prune(\DateTimeInterface $before) + public function prune(DateTimeInterface $before) { $query = $this->connection->table($this->table) + ->whereNotNull('finished_at') ->where('finished_at', '<', $before->getTimestamp()); $totalDeleted = 0; diff --git a/src/Illuminate/Queue/Console/FlushBatchCommand.php b/src/Illuminate/Queue/Console/FlushBatchCommand.php index edfefb03fb1f..eaafe61908c7 100644 --- a/src/Illuminate/Queue/Console/FlushBatchCommand.php +++ b/src/Illuminate/Queue/Console/FlushBatchCommand.php @@ -25,16 +25,22 @@ class FlushBatchCommand extends Command /** * Execute the console command. * - * @return int|null + * @return void */ public function handle() { - $hours = $this->option('hours'); + $count = 0; - $before = Carbon::now()->subHours($hours); + $repository = $this->laravel[BatchRepository::class]; - $count = $this->laravel[BatchRepository::class]->prune($before); + if (method_exists($repository, 'prune')) { + $hours = $this->option('hours'); - $this->info("{$count} entries deleted successfully."); + $before = Carbon::now()->subHours($hours); + + $count = $repository->prune($before); + } + + $this->info("{$count} entries deleted!"); } } diff --git a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php index 41850ab334f0..7c109db7b882 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php @@ -4,6 +4,7 @@ use Carbon\CarbonImmutable; use Closure; +use DateTimeInterface; use Illuminate\Bus\Batch; use Illuminate\Bus\BatchRepository; use Illuminate\Bus\PendingBatch; @@ -138,10 +139,10 @@ public function transaction(Closure $callback) /** * Prune all of the entries older than the given date. * - * @param \DateTimeInterface $before + * @param DateTimeInterface $before * @return int */ - public function prune(\DateTimeInterface $before) + public function prune(DateTimeInterface $before) { return 0; } From 3d95575f4688e53e46d8d9a10f748a87698709f4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 22 Dec 2020 11:00:14 -0600 Subject: [PATCH 005/443] version --- 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 451a0120b177..82860b6f7eb7 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.7'; + const VERSION = '6.20.8'; /** * The base path for the Laravel installation. From e73855b18dcfc645c36d2474f437e4e73dd3c11d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 22 Dec 2020 11:00:40 -0600 Subject: [PATCH 006/443] version --- 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 6ef4be78946e..89b2ede18866 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '7.30.0'; + const VERSION = '7.30.1'; /** * The base path for the Laravel installation. From 53e91ef529ece38cb613e57840fae8be64da1d32 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 23 Dec 2020 00:38:35 +0200 Subject: [PATCH 007/443] [6.x] update changelog --- CHANGELOG-6.x.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 8ec4a08e9afe..078fe3776c23 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,13 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.7...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.8...6.x) + + +## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) + +### Fixed +- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) +- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) ## [v6.20.7 (2020-12-08)](https://github.com/laravel/framework/compare/v6.20.6...v6.20.7) From 85193e8fdd91c9ca9f705e3d861a3ca4377be646 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 23 Dec 2020 00:45:03 +0200 Subject: [PATCH 008/443] [7.x] update changelog --- CHANGELOG-6.x.md | 9 ++++++++- CHANGELOG-7.x.md | 11 ++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 8ec4a08e9afe..078fe3776c23 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,13 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.7...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.8...6.x) + + +## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) + +### Fixed +- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) +- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) ## [v6.20.7 (2020-12-08)](https://github.com/laravel/framework/compare/v6.20.6...v6.20.7) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index 7ef94e06eee9..2a0534809019 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,15 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.30.0...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.30.1...7.x) + + +## [v7.30.1 (2020-12-22)](https://github.com/laravel/framework/compare/v7.30.0...v7.30.1) + +### Fixed +- Backport for fix issue with polymorphic morphMaps with literal 0 ([#35487](https://github.com/laravel/framework/pull/35487)) +- Fixed mime validation for jpeg files ([#35518](https://github.com/laravel/framework/pull/35518)) +- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) +- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) ## [v7.30.0 (2020-12-01)](https://github.com/laravel/framework/compare/v7.29.3...v7.30.0) From e932a728f63cf8b6b3989f89d4ea02aa87091854 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 23 Dec 2020 01:05:34 +0200 Subject: [PATCH 009/443] [8.x] update changelog --- CHANGELOG-6.x.md | 9 ++++++++- CHANGELOG-8.x.md | 21 ++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 8ec4a08e9afe..078fe3776c23 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,13 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.7...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.8...6.x) + + +## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) + +### Fixed +- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) +- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) ## [v6.20.7 (2020-12-08)](https://github.com/laravel/framework/compare/v6.20.6...v6.20.7) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 12793d5c2139..ababd01e8e4c 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,25 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.19.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.20.0...8.x) + + +## [v8.20.0 (2020-12-22)](https://github.com/laravel/framework/compare/v8.19.0...v8.20.0) + +### Added +- Added `Illuminate\Database\DBAL\TimestampType` ([a5761d4](https://github.com/laravel/framework/commit/a5761d4187abea654cb422c2f70054a880ffd2e0), [cff3705](https://github.com/laravel/framework/commit/cff37055cbf031109ae769e8fd6ad1951be47aa6) [382445f](https://github.com/laravel/framework/commit/382445f8487de45a05ebe121837f917b92560a97), [810047e](https://github.com/laravel/framework/commit/810047e1f184f8a4def372885591e4fbb6996b51)) +- Added ability to specify a separate lock connection ([#35621](https://github.com/laravel/framework/pull/35621), [3d95235](https://github.com/laravel/framework/commit/3d95235a6ad8525886071ad68e818a225786064f)) +- Added `Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable::syncWithPivotValues()` ([#35644](https://github.com/laravel/framework/pull/35644), [49b3ce0](https://github.com/laravel/framework/commit/49b3ce098d8a612797b195c4e3774b1e00c604c8)) + +### Fixed +- Fixed `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` for PHP8 ([#35646](https://github.com/laravel/framework/pull/35646)) +- Fixed `assertCookieExpired()` and `assertCookieNotExpired()` methods in `Illuminate\Testing\TestResponse` ([#35637](https://github.com/laravel/framework/pull/35637)) +- Fixed: Account for a numerical array of views in Mailable::renderForAssertions() ([#35662](https://github.com/laravel/framework/pull/35662)) +- Catch DecryptException with invalid X-XSRF-TOKEN in `Illuminate\Foundation\Http\Middleware\VerifyCsrfToken` ([#35671](https://github.com/laravel/framework/pull/35671)) + +### Changed +- Check configuration in `Illuminate\Foundation\Console\Kernel::scheduleCache()` ([a253d0e](https://github.com/laravel/framework/commit/a253d0e40d3deb293d54df9f4455879af5365aab)) +- Modify `Model::mergeCasts` to return `$this` ([#35683](https://github.com/laravel/framework/pull/35683)) +- Clear a cached user in RequestGuard if a request is changed ([#35692](https://github.com/laravel/framework/pull/35692)) ## [v8.19.0 (2020-12-15)](https://github.com/laravel/framework/compare/v8.18.1...v8.19.0) From e85247b13fd75329b16992dc255746865d43d1b8 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 23 Dec 2020 01:07:19 +0200 Subject: [PATCH 010/443] [8.x] update changelog --- CHANGELOG-8.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index ababd01e8e4c..c0499d7f01e5 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,12 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.20.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.20.1...8.x) + + +## [v8.20.1 (2020-12-22)](https://github.com/laravel/framework/compare/v8.20.0...v8.20.1) + +### Revert +- Revert [Clear a cached user in RequestGuard if a request is changed](https://github.com/laravel/framework/pull/35692) ([ca8ccd6](https://github.com/laravel/framework/commit/ca8ccd6757d5639f0e5fb241b3df6878da6ce34e)) ## [v8.20.0 (2020-12-22)](https://github.com/laravel/framework/compare/v8.19.0...v8.20.0) From 8dc442578670197c05e80be90fb711c427f3c99c Mon Sep 17 00:00:00 2001 From: dmason30 Date: Wed, 23 Dec 2020 01:05:02 +0000 Subject: [PATCH 011/443] Change command signature and add new interface --- src/Illuminate/Bus/DatabaseBatchRepository.php | 2 +- src/Illuminate/Bus/Prunable.php | 16 ++++++++++++++++ .../Providers/ArtisanServiceProvider.php | 16 ++++++++-------- ...hBatchCommand.php => PruneBatchesCommand.php} | 7 ++++--- .../Testing/Fakes/BatchRepositoryFake.php | 12 ------------ 5 files changed, 29 insertions(+), 24 deletions(-) create mode 100644 src/Illuminate/Bus/Prunable.php rename src/Illuminate/Queue/Console/{FlushBatchCommand.php => PruneBatchesCommand.php} (78%) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index 3f025b06f9f2..bfad496fc352 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -9,7 +9,7 @@ use Illuminate\Database\Query\Expression; use Illuminate\Support\Str; -class DatabaseBatchRepository implements BatchRepository +class DatabaseBatchRepository implements BatchRepository, Prunable { /** * The batch factory instance. diff --git a/src/Illuminate/Bus/Prunable.php b/src/Illuminate/Bus/Prunable.php new file mode 100644 index 000000000000..5441a00dc5bf --- /dev/null +++ b/src/Illuminate/Bus/Prunable.php @@ -0,0 +1,16 @@ + 'command.queue.clear', 'QueueFailed' => 'command.queue.failed', 'QueueFlush' => 'command.queue.flush', - 'QueueFlushBatch' => 'command.queue.flush-batch', 'QueueForget' => 'command.queue.forget', 'QueueListen' => 'command.queue.listen', + 'QueuePruneBatches' => 'command.queue.prune-batches', 'QueueRestart' => 'command.queue.restart', 'QueueRetry' => 'command.queue.retry', 'QueueRetryBatch' => 'command.queue.retry-batch', @@ -679,10 +679,10 @@ protected function registerQueueFlushCommand() * * @return void */ - protected function registerQueueFlushBatchCommand() + protected function registerQueueListenCommand() { - $this->app->singleton('command.queue.flush-batch', function () { - return new FlushBatchQueueCommand; + $this->app->singleton('command.queue.listen', function ($app) { + return new QueueListenCommand($app['queue.listener']); }); } @@ -691,10 +691,10 @@ protected function registerQueueFlushBatchCommand() * * @return void */ - protected function registerQueueListenCommand() + protected function registerQueuePruneBatchesCommand() { - $this->app->singleton('command.queue.listen', function ($app) { - return new QueueListenCommand($app['queue.listener']); + $this->app->singleton('command.queue.prune-batches', function () { + return new PruneBatchesQueueCommand; }); } diff --git a/src/Illuminate/Queue/Console/FlushBatchCommand.php b/src/Illuminate/Queue/Console/PruneBatchesCommand.php similarity index 78% rename from src/Illuminate/Queue/Console/FlushBatchCommand.php rename to src/Illuminate/Queue/Console/PruneBatchesCommand.php index eaafe61908c7..d30b6fdb0e8d 100644 --- a/src/Illuminate/Queue/Console/FlushBatchCommand.php +++ b/src/Illuminate/Queue/Console/PruneBatchesCommand.php @@ -4,16 +4,17 @@ use Carbon\Carbon; use Illuminate\Bus\BatchRepository; +use Illuminate\Bus\Prunable; use Illuminate\Console\Command; -class FlushBatchCommand extends Command +class PruneBatchesCommand extends Command { /** * The console command signature. * * @var string */ - protected $signature = 'queue:flush-batch {--hours=24 : The number of hours to retain batch data}'; + protected $signature = 'queue:prune-batches {--hours=24 : The number of hours to retain batch data}'; /** * The console command description. @@ -33,7 +34,7 @@ public function handle() $repository = $this->laravel[BatchRepository::class]; - if (method_exists($repository, 'prune')) { + if ($repository instanceof Prunable) { $hours = $this->option('hours'); $before = Carbon::now()->subHours($hours); diff --git a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php index 7c109db7b882..55681f4d5534 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php @@ -4,7 +4,6 @@ use Carbon\CarbonImmutable; use Closure; -use DateTimeInterface; use Illuminate\Bus\Batch; use Illuminate\Bus\BatchRepository; use Illuminate\Bus\PendingBatch; @@ -135,15 +134,4 @@ public function transaction(Closure $callback) { return $callback(); } - - /** - * Prune all of the entries older than the given date. - * - * @param DateTimeInterface $before - * @return int - */ - public function prune(DateTimeInterface $before) - { - return 0; - } } From 843f8bb4269bb983826ba709d49cd697a040e85a Mon Sep 17 00:00:00 2001 From: Karel Faille Date: Wed, 23 Dec 2020 15:08:30 +0100 Subject: [PATCH 012/443] Ensure DBAL custom type doesn't exists (#35704) As the DBAL type registry is a static singleton, when running multiple tests, type may be already registered. --- src/Illuminate/Database/DatabaseServiceProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/DatabaseServiceProvider.php b/src/Illuminate/Database/DatabaseServiceProvider.php index 72f131d0db49..9f2ab18503e1 100755 --- a/src/Illuminate/Database/DatabaseServiceProvider.php +++ b/src/Illuminate/Database/DatabaseServiceProvider.php @@ -123,7 +123,9 @@ protected function registerDoctrineTypes() $types = $this->app['config']->get('database.dbal.types', []); foreach ($types as $name => $class) { - Type::addType($name, $class); + if (! Type::hasType($name)) { + Type::addType($name, $class); + } } } } From 658bd91ff339782124047f5d8e5df7654d29463b Mon Sep 17 00:00:00 2001 From: Owen Voke Date: Wed, 23 Dec 2020 14:44:51 +0000 Subject: [PATCH 013/443] chore: remove duplicate doc block (#35705) --- .../Http/Middleware/PreventRequestsDuringMaintenance.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php b/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php index 99953bfd5e90..831468281fbc 100644 --- a/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php +++ b/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php @@ -42,7 +42,6 @@ public function __construct(Application $app) * @return mixed * * @throws \Symfony\Component\HttpKernel\Exception\HttpException - * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function handle($request, Closure $next) { From 33f5ac695a55d6cdbadcfe1b46e3409e4a66df16 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 24 Dec 2020 12:50:47 -0600 Subject: [PATCH 014/443] add files --- .../Bus/DatabaseBatchRepository.php | 30 +++++++++---------- ...unable.php => PrunableBatchRepository.php} | 4 +-- .../Queue/Console/PruneBatchesCommand.php | 6 +--- 3 files changed, 18 insertions(+), 22 deletions(-) rename src/Illuminate/Bus/{Prunable.php => PrunableBatchRepository.php} (68%) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index bfad496fc352..ece6301c126f 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -9,7 +9,7 @@ use Illuminate\Database\Query\Expression; use Illuminate\Support\Str; -class DatabaseBatchRepository implements BatchRepository, Prunable +class DatabaseBatchRepository implements PrunableBatchRepository { /** * The batch factory instance. @@ -231,23 +231,10 @@ public function delete(string $batchId) $this->connection->table($this->table)->where('id', $batchId)->delete(); } - /** - * Execute the given Closure within a storage specific transaction. - * - * @param \Closure $callback - * @return mixed - */ - public function transaction(Closure $callback) - { - return $this->connection->transaction(function () use ($callback) { - return $callback(); - }); - } - /** * Prune all of the entries older than the given date. * - * @param DateTimeInterface $before + * @param \DateTimeInterface $before * @return int */ public function prune(DateTimeInterface $before) @@ -267,6 +254,19 @@ public function prune(DateTimeInterface $before) return $totalDeleted; } + /** + * Execute the given Closure within a storage specific transaction. + * + * @param \Closure $callback + * @return mixed + */ + public function transaction(Closure $callback) + { + return $this->connection->transaction(function () use ($callback) { + return $callback(); + }); + } + /** * Convert the given raw batch to a Batch object. * diff --git a/src/Illuminate/Bus/Prunable.php b/src/Illuminate/Bus/PrunableBatchRepository.php similarity index 68% rename from src/Illuminate/Bus/Prunable.php rename to src/Illuminate/Bus/PrunableBatchRepository.php index 5441a00dc5bf..3f972553b597 100644 --- a/src/Illuminate/Bus/Prunable.php +++ b/src/Illuminate/Bus/PrunableBatchRepository.php @@ -4,12 +4,12 @@ use DateTimeInterface; -interface Prunable +interface PrunableBatchRepository extends BatchRepository { /** * Prune all of the entries older than the given date. * - * @param DateTimeInterface $before + * @param \DateTimeInterface $before * @return int */ public function prune(DateTimeInterface $before); diff --git a/src/Illuminate/Queue/Console/PruneBatchesCommand.php b/src/Illuminate/Queue/Console/PruneBatchesCommand.php index d30b6fdb0e8d..e519c9a7759d 100644 --- a/src/Illuminate/Queue/Console/PruneBatchesCommand.php +++ b/src/Illuminate/Queue/Console/PruneBatchesCommand.php @@ -35,11 +35,7 @@ public function handle() $repository = $this->laravel[BatchRepository::class]; if ($repository instanceof Prunable) { - $hours = $this->option('hours'); - - $before = Carbon::now()->subHours($hours); - - $count = $repository->prune($before); + $count = $repository->prune(Carbon::now()->subHours($this->option('hours'))); } $this->info("{$count} entries deleted!"); From 344710f021c5b5b8fb32f6f66c5301829aa5758a Mon Sep 17 00:00:00 2001 From: Daniel Mason Date: Fri, 25 Dec 2020 04:02:42 +0000 Subject: [PATCH 015/443] Fix prune batches command interface check (#35713) The `Prunable` interface I added was renamed to `PrunableBatchRepository` post merge but was not also changed in the command interface check to see if the repository can be pruned. --- src/Illuminate/Queue/Console/PruneBatchesCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/PruneBatchesCommand.php b/src/Illuminate/Queue/Console/PruneBatchesCommand.php index e519c9a7759d..cc25bc53cfb9 100644 --- a/src/Illuminate/Queue/Console/PruneBatchesCommand.php +++ b/src/Illuminate/Queue/Console/PruneBatchesCommand.php @@ -4,7 +4,7 @@ use Carbon\Carbon; use Illuminate\Bus\BatchRepository; -use Illuminate\Bus\Prunable; +use Illuminate\Bus\PrunableBatchRepository; use Illuminate\Console\Command; class PruneBatchesCommand extends Command @@ -34,7 +34,7 @@ public function handle() $repository = $this->laravel[BatchRepository::class]; - if ($repository instanceof Prunable) { + if ($repository instanceof PrunableBatchRepository) { $count = $repository->prune(Carbon::now()->subHours($this->option('hours'))); } From 08303c7cbaa0b3271060ce315160d0722b2a78f0 Mon Sep 17 00:00:00 2001 From: Daniel Esteve Date: Fri, 25 Dec 2020 18:37:09 +0100 Subject: [PATCH 016/443] [8.x] Add missing dispatchAfterCommit to DatabaseQueue (#35715) * add missing dispatchAfterCommit to DatabaseQueue * add new param to phpdoc --- src/Illuminate/Queue/DatabaseQueue.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index 961b4e460b04..cc77007c0b2f 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -47,14 +47,20 @@ class DatabaseQueue extends Queue implements QueueContract, ClearableQueue * @param string $table * @param string $default * @param int $retryAfter + * @param bool $dispatchAfterCommit * @return void */ - public function __construct(Connection $database, $table, $default = 'default', $retryAfter = 60) + public function __construct(Connection $database, + $table, + $default = 'default', + $retryAfter = 60, + $dispatchAfterCommit = false) { $this->table = $table; $this->default = $default; $this->database = $database; $this->retryAfter = $retryAfter; + $this->dispatchAfterCommit = $dispatchAfterCommit; } /** From aae5c4acf3492ffac107ac2e466914e455623da8 Mon Sep 17 00:00:00 2001 From: Hamid Alaei Varnosfaderani Date: Sat, 26 Dec 2020 19:27:28 +0330 Subject: [PATCH 017/443] convert time to seconds once (#35721) --- src/Illuminate/Cache/Repository.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 46af170f2b40..00cd39b013a4 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -292,8 +292,12 @@ public function setMultiple($values, $ttl = null) */ public function add($key, $value, $ttl = null) { + $seconds = null; + if ($ttl !== null) { - if ($this->getSeconds($ttl) <= 0) { + $seconds = $this->getSeconds($ttl); + + if ($seconds <= 0) { return false; } @@ -301,8 +305,6 @@ public function add($key, $value, $ttl = null) // has a chance to override this logic. Some drivers better support the way // this operation should work with a total "atomic" implementation of it. if (method_exists($this->store, 'add')) { - $seconds = $this->getSeconds($ttl); - return $this->store->add( $this->itemKey($key), $value, $seconds ); @@ -313,7 +315,7 @@ public function add($key, $value, $ttl = null) // so it exists for subsequent requests. Then, we will return true so it is // easy to know if the value gets added. Otherwise, we will return false. if (is_null($this->get($key))) { - return $this->put($key, $value, $ttl); + return $this->put($key, $value, $seconds); } return false; From 7f42f67d9b4e4e64a4d8706960d7720ba4204ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rihards=20=C5=A0=C4=8Deredins?= Date: Mon, 28 Dec 2020 03:42:09 +0200 Subject: [PATCH 018/443] Fix `php artisan db` command for the Postgres CLI (#35725) --- src/Illuminate/Database/Console/DbCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index ee6633557017..9152d1dc844c 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -83,7 +83,7 @@ public function commandEnvironment(array $connection) { $driver = ucfirst($connection['driver']); - if (method_exists($this, "get{$driver}Env")) { + if (method_exists($this, "get{$driver}Environment")) { return $this->{"get{$driver}Environment"}($connection); } From 0be33dedabf671cdf3278edf8c61a3ced85abb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rihards=20=C5=A0=C4=8Deredins?= Date: Tue, 29 Dec 2020 01:04:41 +0200 Subject: [PATCH 019/443] Since documentation was reviewed test case naming convention has changed to `snake_case`. I guess it makes sense to update test stubs for new projects too. (#35735) --- src/Illuminate/Foundation/Console/stubs/test.stub | 2 +- src/Illuminate/Foundation/Console/stubs/test.unit.stub | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/test.stub b/src/Illuminate/Foundation/Console/stubs/test.stub index c5b50ad3cb6b..84c75cbfe98d 100644 --- a/src/Illuminate/Foundation/Console/stubs/test.stub +++ b/src/Illuminate/Foundation/Console/stubs/test.stub @@ -13,7 +13,7 @@ class {{ class }} extends TestCase * * @return void */ - public function testExample() + public function test_example() { $response = $this->get('/'); diff --git a/src/Illuminate/Foundation/Console/stubs/test.unit.stub b/src/Illuminate/Foundation/Console/stubs/test.unit.stub index 98af6529355c..b6816aa72f29 100644 --- a/src/Illuminate/Foundation/Console/stubs/test.unit.stub +++ b/src/Illuminate/Foundation/Console/stubs/test.unit.stub @@ -11,7 +11,7 @@ class {{ class }} extends TestCase * * @return void */ - public function testExample() + public function test_example() { $this->assertTrue(true); } From 75a0753879419c91dfacb5aecf584aa260714620 Mon Sep 17 00:00:00 2001 From: MilesChou Date: Tue, 29 Dec 2020 07:09:49 +0800 Subject: [PATCH 020/443] Fix OPTIONS method bug when use same path but diff domain (#35714) --- .../Routing/CompiledRouteCollection.php | 4 ++ .../Routing/CompiledRouteCollectionTest.php | 53 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/Illuminate/Routing/CompiledRouteCollection.php b/src/Illuminate/Routing/CompiledRouteCollection.php index 099156cc4b81..c53954194e06 100644 --- a/src/Illuminate/Routing/CompiledRouteCollection.php +++ b/src/Illuminate/Routing/CompiledRouteCollection.php @@ -252,6 +252,10 @@ public function getRoutesByMethod() }) ->map(function (Collection $routes) { return $routes->mapWithKeys(function (Route $route) { + if ($domain = $route->getDomain()) { + return [$domain.'/'.$route->uri => $route]; + } + return [$route->uri => $route]; })->all(); }) diff --git a/tests/Integration/Routing/CompiledRouteCollectionTest.php b/tests/Integration/Routing/CompiledRouteCollectionTest.php index 22928a4c1f4f..e474e8a461c4 100644 --- a/tests/Integration/Routing/CompiledRouteCollectionTest.php +++ b/tests/Integration/Routing/CompiledRouteCollectionTest.php @@ -490,6 +490,59 @@ public function testTrailingSlashIsTrimmedWhenMatchingCachedRoutes() $this->assertSame('foo', $this->collection()->match($request)->getName()); } + public function testRouteWithSamePathAndSameMethodButDiffDomainNameWithOptionsMethod() + { + $routes = [ + 'foo_domain' => $this->newRoute('GET', 'same/path', [ + 'uses' => 'FooController@index', + 'as' => 'foo', + 'domain' => 'foo.localhost', + ]), + 'bar_domain' => $this->newRoute('GET', 'same/path', [ + 'uses' => 'BarController@index', + 'as' => 'bar', + 'domain' => 'bar.localhost', + ]), + 'no_domain' => $this->newRoute('GET', 'same/path', [ + 'uses' => 'BarController@index', + 'as' => 'no_domain', + ]), + ]; + + $this->routeCollection->add($routes['foo_domain']); + $this->routeCollection->add($routes['bar_domain']); + $this->routeCollection->add($routes['no_domain']); + + $expectedMethods = [ + 'OPTIONS', + ]; + + $this->assertSame($expectedMethods, $this->collection()->match( + Request::create('http://foo.localhost/same/path', 'OPTIONS') + )->methods); + + $this->assertSame($expectedMethods, $this->collection()->match( + Request::create('http://bar.localhost/same/path', 'OPTIONS') + )->methods); + + $this->assertSame($expectedMethods, $this->collection()->match( + Request::create('http://no.localhost/same/path', 'OPTIONS') + )->methods); + + $this->assertEquals([ + 'HEAD' => [ + 'foo.localhost/same/path' => $routes['foo_domain'], + 'bar.localhost/same/path' => $routes['bar_domain'], + 'same/path' => $routes['no_domain'], + ], + 'GET' => [ + 'foo.localhost/same/path' => $routes['foo_domain'], + 'bar.localhost/same/path' => $routes['bar_domain'], + 'same/path' => $routes['no_domain'], + ], + ], $this->collection()->getRoutesByMethod()); + } + /** * Create a new Route object. * From 13546a703c210298517b25307647778d4fe3ab9f Mon Sep 17 00:00:00 2001 From: Sab Date: Tue, 29 Dec 2020 13:57:03 +1100 Subject: [PATCH 021/443] Update DetectsLostConnections.php (#35744) AWS Aurora serverless DB sometimes aborts queries while performing scaling. The error returned is: "SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry." --- 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 c214c0396c84..6ba3c4939faa 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -47,6 +47,7 @@ protected function causedByLostConnection(Throwable $e) 'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected', 'SQLSTATE[HY000] [2002] Connection timed out', 'SSL: Connection timed out', + 'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.', ]); } } From d2092774c80c632bdc98853dfbad16743cc898e4 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 29 Dec 2020 16:07:22 +0100 Subject: [PATCH 022/443] Update DetectsLostConnections.php (#35744) (#35752) AWS Aurora serverless DB sometimes aborts queries while performing scaling. The error returned is: "SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry." Co-authored-by: Sab --- src/Illuminate/Database/DetectsLostConnections.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php index 36b46099983f..6ba3c4939faa 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -45,6 +45,9 @@ protected function causedByLostConnection(Throwable $e) 'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.', 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again', 'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected', + 'SQLSTATE[HY000] [2002] Connection timed out', + 'SSL: Connection timed out', + 'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.', ]); } } From 2ce11abecb868af99f311ea8731a8cd9cb8a99d8 Mon Sep 17 00:00:00 2001 From: Roelof Date: Tue, 29 Dec 2020 16:08:35 +0100 Subject: [PATCH 023/443] [8.x] Correct return type on View facade's first() (#35750) * Fixed docblock in View facade * Added test assertion to make sure View facade docblock is correct --- src/Illuminate/Support/Facades/View.php | 2 +- tests/View/ViewFactoryTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/View.php b/src/Illuminate/Support/Facades/View.php index b85b086c5547..9b66464c9d96 100755 --- a/src/Illuminate/Support/Facades/View.php +++ b/src/Illuminate/Support/Facades/View.php @@ -4,7 +4,7 @@ /** * @method static \Illuminate\Contracts\View\Factory addNamespace(string $namespace, string|array $hints) - * @method static \Illuminate\Contracts\View\Factory first(array $views, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) + * @method static \Illuminate\Contracts\View\View first(array $views, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) * @method static \Illuminate\Contracts\View\Factory replaceNamespace(string $namespace, string|array $hints) * @method static \Illuminate\Contracts\View\View file(string $path, array $data = [], array $mergeData = []) * @method static \Illuminate\Contracts\View\View make(string $view, array $data = [], array $mergeData = []) diff --git a/tests/View/ViewFactoryTest.php b/tests/View/ViewFactoryTest.php index 52061422074e..ab003c3b9f9d 100755 --- a/tests/View/ViewFactoryTest.php +++ b/tests/View/ViewFactoryTest.php @@ -7,6 +7,7 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; use Illuminate\Contracts\View\Engine; +use Illuminate\Contracts\View\View as ViewContract; use Illuminate\Events\Dispatcher; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\HtmlString; @@ -87,6 +88,7 @@ public function testFirstCreatesNewViewInstanceWithProperPath() $factory->addExtension('php', 'php'); $view = $factory->first(['bar', 'view'], ['foo' => 'bar'], ['baz' => 'boom']); + $this->assertInstanceOf(ViewContract::class, $view); $this->assertSame($engine, $view->getEngine()); $this->assertSame($_SERVER['__test.view'], $view); From d44ed21525a9bf1a12717c92318e9dcd3a1427d1 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 29 Dec 2020 17:18:15 +0200 Subject: [PATCH 024/443] [8.x] Set chain queue when inside a batch (#35746) * set chain copnnection when inside a batch * set chain connection from batch --- src/Illuminate/Bus/Batch.php | 5 ++++- tests/Bus/BusBatchTest.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Bus/Batch.php b/src/Illuminate/Bus/Batch.php index 1073ecd46d37..cac16e1e9f51 100644 --- a/src/Illuminate/Bus/Batch.php +++ b/src/Illuminate/Bus/Batch.php @@ -170,7 +170,10 @@ public function add($jobs) $count += count($job); return with($this->prepareBatchedChain($job), function ($chain) { - return $chain->first()->chain($chain->slice(1)->values()->all()); + return $chain->first() + ->allOnQueue($this->options['queue'] ?? null) + ->allOnConnection($this->options['connection'] ?? null) + ->chain($chain->slice(1)->values()->all()); }); } else { $job->withBatchId($this->id); diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index 381200daa171..8f4d6c5a11d4 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -332,6 +332,7 @@ public function test_chain_can_be_added_to_batch() $this->assertEquals(3, $batch->totalJobs); $this->assertEquals(3, $batch->pendingJobs); + $this->assertEquals('test-queue', $chainHeadJob->chainQueue); $this->assertTrue(is_string($chainHeadJob->batchId)); $this->assertTrue(is_string($secondJob->batchId)); $this->assertTrue(is_string($thirdJob->batchId)); From 60c3c81d083f63a5581b97e2d38375227fc86f9e Mon Sep 17 00:00:00 2001 From: Christoph Rumpel Date: Wed, 30 Dec 2020 00:19:59 +0100 Subject: [PATCH 025/443] Check for given message stream id and add to header if given (#35755) Co-authored-by: Christoph Rumpel --- src/Illuminate/Mail/MailManager.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index a8a4a291d0c9..97fcda7827c5 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -327,8 +327,13 @@ protected function createMailgunTransport(array $config) */ protected function createPostmarkTransport(array $config) { + $headers = isset($config['message_stream_id']) ? [ + 'X-PM-Message-Stream' => $config['message_stream_id'], + ] : []; + return tap(new PostmarkTransport( - $config['token'] ?? $this->app['config']->get('services.postmark.token') + $config['token'] ?? $this->app['config']->get('services.postmark.token'), + $headers ), function ($transport) { $transport->registerPlugin(new ThrowExceptionOnFailurePlugin()); }); From 2c9c12c5e41b3f13bcf9d7374417c0d211ae4dd9 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Wed, 30 Dec 2020 00:21:31 +0100 Subject: [PATCH 026/443] Fix setUp and tearDown methods visibility (#35753) --- tests/Cache/CacheMemcachedStoreTest.php | 2 +- tests/Integration/Foundation/MaintenanceModeTest.php | 2 +- tests/View/Blade/BladeComponentTagCompilerTest.php | 2 +- tests/View/ComponentTest.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Cache/CacheMemcachedStoreTest.php b/tests/Cache/CacheMemcachedStoreTest.php index 5b29dd70b279..b1aad12ad29d 100755 --- a/tests/Cache/CacheMemcachedStoreTest.php +++ b/tests/Cache/CacheMemcachedStoreTest.php @@ -11,7 +11,7 @@ class CacheMemcachedStoreTest extends TestCase { - public function tearDown(): void + protected function tearDown(): void { m::close(); diff --git a/tests/Integration/Foundation/MaintenanceModeTest.php b/tests/Integration/Foundation/MaintenanceModeTest.php index 31f08df44da9..ff93fe41a492 100644 --- a/tests/Integration/Foundation/MaintenanceModeTest.php +++ b/tests/Integration/Foundation/MaintenanceModeTest.php @@ -14,7 +14,7 @@ */ class MaintenanceModeTest extends TestCase { - public function tearDown(): void + protected function tearDown(): void { @unlink(storage_path('framework/down')); } diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index 6872d38ae4a1..b84030c13d2b 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -13,7 +13,7 @@ class BladeComponentTagCompilerTest extends AbstractBladeTestCase { - public function tearDown(): void + protected function tearDown(): void { Mockery::close(); } diff --git a/tests/View/ComponentTest.php b/tests/View/ComponentTest.php index 124d954d454e..8049c7aa5bc5 100644 --- a/tests/View/ComponentTest.php +++ b/tests/View/ComponentTest.php @@ -19,7 +19,7 @@ class ComponentTest extends TestCase protected $viewFactory; protected $config; - public function setUp(): void + protected function setUp(): void { $this->config = m::mock(Config::class); From 4da7a2b43699b896e5b3f62c4e43039effecaf14 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Fri, 1 Jan 2021 11:06:10 -0600 Subject: [PATCH 027/443] [8.x] Give a more meaningul message when route parameters are missing (#35706) * Give a more meaningul message when route parameters are missing The message for `UrlGenerationException` when parameters are missing is a nice start, but knowing which parameters are missing can be a huge help in figuring out where something is broken. Especially if a route has multiple possible parameters. Which parameter is actually missing? Are more than one missing? Now we'll know! * Fix small typo Co-authored-by: Michel Bardelmeijer Co-authored-by: Michel Bardelmeijer --- .../Exceptions/UrlGenerationException.php | 22 +++++++- src/Illuminate/Routing/RouteUrlGenerator.php | 4 +- tests/Routing/RoutingRouteTest.php | 2 +- tests/Routing/RoutingUrlGeneratorTest.php | 55 +++++++++++++++++++ 4 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Routing/Exceptions/UrlGenerationException.php b/src/Illuminate/Routing/Exceptions/UrlGenerationException.php index 1853b2aff0fc..330e8c223814 100644 --- a/src/Illuminate/Routing/Exceptions/UrlGenerationException.php +++ b/src/Illuminate/Routing/Exceptions/UrlGenerationException.php @@ -3,6 +3,8 @@ namespace Illuminate\Routing\Exceptions; use Exception; +use Illuminate\Routing\Route; +use Illuminate\Support\Str; class UrlGenerationException extends Exception { @@ -10,10 +12,26 @@ class UrlGenerationException extends Exception * Create a new exception for missing route parameters. * * @param \Illuminate\Routing\Route $route + * @param array $parameters * @return static */ - public static function forMissingParameters($route) + public static function forMissingParameters(Route $route, array $parameters = []) { - return new static("Missing required parameters for [Route: {$route->getName()}] [URI: {$route->uri()}]."); + $parameterLabel = Str::plural('parameter', count($parameters)); + + $message = sprintf( + 'Missing required %s for [Route: %s] [URI: %s]', + $parameterLabel, + $route->getName(), + $route->uri() + ); + + if (count($parameters) > 0) { + $message .= sprintf(' [Missing %s: %s]', $parameterLabel, implode(', ', $parameters)); + } + + $message .= '.'; + + return new static($message); } } diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index 5cc03c1e246c..5f1248966c77 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -87,8 +87,8 @@ public function to($route, $parameters = [], $absolute = false) $route ), $parameters); - if (preg_match('/\{.*?\}/', $uri)) { - throw UrlGenerationException::forMissingParameters($route); + if (preg_match_all('/{(.*?)}/', $uri, $matchedMissingParameters)) { + throw UrlGenerationException::forMissingParameters($route, $matchedMissingParameters[1]); } // Once we have ensured that there are no missing parameters in the URI we will encode diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index 6715aa7297d9..9a9f76e8123f 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -1831,7 +1831,7 @@ public function testRouteRedirectStripsMissingStartingForwardSlash() public function testRouteRedirectExceptionWhenMissingExpectedParameters() { $this->expectException(UrlGenerationException::class); - $this->expectExceptionMessage('Missing required parameters for [Route: laravel_route_redirect_destination] [URI: users/{user}].'); + $this->expectExceptionMessage('Missing required parameter for [Route: laravel_route_redirect_destination] [URI: users/{user}] [Missing parameter: user].'); $container = new Container; $router = new Router(new Dispatcher, $container); diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index b7663b686b17..676f609b15fa 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -550,6 +550,61 @@ public function testUrlGenerationForControllersRequiresPassingOfRequiredParamete $this->assertSame('http://www.foo.com:8080/foo?test=123', $url->route('foo', $parameters)); } + public function provideParametersAndExpectedMeaningfulExceptionMessages() + { + return [ + 'Missing parameters "one", "two" and "three"' => [ + [], + 'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, two, three].', + ], + 'Missing parameters "two" and "three"' => [ + ['one' => '123'], + 'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: two, three].', + ], + 'Missing parameters "one" and "three"' => [ + ['two' => '123'], + 'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, three].', + ], + 'Missing parameters "one" and "two"' => [ + ['three' => '123'], + 'Missing required parameters for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameters: one, two].', + ], + 'Missing parameter "three"' => [ + ['one' => '123', 'two' => '123'], + 'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: three].', + ], + 'Missing parameter "two"' => [ + ['one' => '123', 'three' => '123'], + 'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: two].', + ], + 'Missing parameter "one"' => [ + ['two' => '123', 'three' => '123'], + 'Missing required parameter for [Route: foo] [URI: foo/{one}/{two}/{three}/{four?}] [Missing parameter: one].', + ], + ]; + } + + /** + * @dataProvider provideParametersAndExpectedMeaningfulExceptionMessages + */ + public function testUrlGenerationThrowsExceptionForMissingParametersWithMeaningfulMessage($parameters, $expectedMeaningfulExceptionMessage) + { + $this->expectException(UrlGenerationException::class); + $this->expectExceptionMessage($expectedMeaningfulExceptionMessage); + + $url = new UrlGenerator( + $routes = new RouteCollection, + Request::create('http://www.foo.com:8080/') + ); + + $route = new Route(['GET'], 'foo/{one}/{two}/{three}/{four?}', ['as' => 'foo', function () { + // + }]); + $routes->add($route); + + $url->route('foo', $parameters); + } + public function testForceRootUrl() { $url = new UrlGenerator( From 334b0a9b9ebd02b8207816e37058700e52876cfc Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 1 Jan 2021 11:06:33 -0600 Subject: [PATCH 028/443] formatting --- src/Illuminate/Routing/Exceptions/UrlGenerationException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Exceptions/UrlGenerationException.php b/src/Illuminate/Routing/Exceptions/UrlGenerationException.php index 330e8c223814..e0057c9d6bbf 100644 --- a/src/Illuminate/Routing/Exceptions/UrlGenerationException.php +++ b/src/Illuminate/Routing/Exceptions/UrlGenerationException.php @@ -12,7 +12,7 @@ class UrlGenerationException extends Exception * Create a new exception for missing route parameters. * * @param \Illuminate\Routing\Route $route - * @param array $parameters + * @param array $parameters * @return static */ public static function forMissingParameters(Route $route, array $parameters = []) From 4ffe40fb169c6bcce9193ff56958eca41e64294f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 2 Jan 2021 15:32:04 -0600 Subject: [PATCH 029/443] add table prefix --- 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 e7b60c7efa7c..fe73fb2af033 100644 --- a/src/Illuminate/Database/Console/DumpCommand.php +++ b/src/Illuminate/Database/Console/DumpCommand.php @@ -66,7 +66,7 @@ public function handle(ConnectionResolverInterface $connections, Dispatcher $dis protected function schemaState(Connection $connection) { return $connection->getSchemaState() - ->withMigrationTable(Config::get('database.migrations', 'migrations')) + ->withMigrationTable($connection->getTablePrefix().Config::get('database.migrations', 'migrations')) ->handleOutputUsing(function ($type, $buffer) { $this->output->write($buffer); }); From 44dbb4b606d7a049fb3b95594b495567a7c29223 Mon Sep 17 00:00:00 2001 From: David Siegers Date: Mon, 4 Jan 2021 15:52:00 +0100 Subject: [PATCH 030/443] Remove if-condition that always evaluates to false (#35771) The if-condition at src/Illuminate/Queue/RedisQueue.php:212 never evaluates to true and its early-return statement is never executed because $nextJob is never empty. $nextJob is never empty because \Illuminate\Queue\RedisQueue::retrieveNextJob can only return [null, null] or [$job, $reserved] which are both none-empty-arrays. Consequently we can remove the if-condition and its unreachable statement without causing any change to behaviour. --- src/Illuminate/Queue/RedisQueue.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Queue/RedisQueue.php b/src/Illuminate/Queue/RedisQueue.php index 3aca40c9c388..79efc0581f24 100644 --- a/src/Illuminate/Queue/RedisQueue.php +++ b/src/Illuminate/Queue/RedisQueue.php @@ -209,11 +209,7 @@ public function pop($queue = null) { $this->migrate($prefixed = $this->getQueue($queue)); - if (empty($nextJob = $this->retrieveNextJob($prefixed))) { - return; - } - - [$job, $reserved] = $nextJob; + [$job, $reserved] = $this->retrieveNextJob($prefixed); if ($reserved) { return new RedisJob( From 72596ae3612bb6dfa21468f8d7d77f6cc545890d Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Mon, 4 Jan 2021 22:13:36 -0500 Subject: [PATCH 031/443] Refresh the retryUntil timer on job retry Signed-off-by: Kevin Ullyott --- src/Illuminate/Queue/Console/RetryCommand.php | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index e9120a976962..28491debd2e9 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -93,10 +93,25 @@ protected function getJobIdsByRanges(array $ranges) protected function retryJob($job) { $this->laravel['queue']->connection($job->connection)->pushRaw( - $this->resetAttempts($job->payload), $job->queue + $this->retryRefresh($job->payload), $job->queue ); } + /** + * Possibly refresh job attempts and retryUntil value + * + * @param string $payload + * @return string + */ + protected function retryRefresh($payload) + { + $payload = $this->resetAttempts($payload); + + $payload = $this->refreshRetryUntil($payload); + + return $payload; + } + /** * Reset the payload attempts. * @@ -115,4 +130,23 @@ protected function resetAttempts($payload) return json_encode($payload); } + + /** + * Refreshes a jobs retryUntil time with it's own retryUntil method + * + * @param string $payload + * @return string + */ + protected function refreshRetryUntil($payload) + { + $payload = json_decode($payload, true); + + $jobInstance = unserialize($payload['data']['command']); + + $newRetryUntil = $jobInstance->retryUntil()->timestamp; + + $payload['retryUntil'] = $newRetryUntil; + + return json_encode($payload); + } } From d91253be99029a27caa225caa47bf80645a0c21e Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Mon, 4 Jan 2021 22:26:28 -0500 Subject: [PATCH 032/443] Check if the job has a retryUntil method Signed-off-by: Kevin Ullyott --- src/Illuminate/Queue/Console/RetryCommand.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index 28491debd2e9..e5c4dc0af03a 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -143,9 +143,11 @@ protected function refreshRetryUntil($payload) $jobInstance = unserialize($payload['data']['command']); - $newRetryUntil = $jobInstance->retryUntil()->timestamp; + if (method_exists($jobInstance, 'retryUntil')) { + $newRetryUntil = $jobInstance->retryUntil()->timestamp; - $payload['retryUntil'] = $newRetryUntil; + $payload['retryUntil'] = $newRetryUntil; + } return json_encode($payload); } From cdcc60bad460348f72b07501aa0010673b27727f Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Mon, 4 Jan 2021 22:43:41 -0500 Subject: [PATCH 033/443] Proper punctuation Signed-off-by: Kevin Ullyott --- src/Illuminate/Queue/Console/RetryCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index e5c4dc0af03a..055790da6446 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -98,7 +98,7 @@ protected function retryJob($job) } /** - * Possibly refresh job attempts and retryUntil value + * Possibly refresh job attempts and retryUntil value. * * @param string $payload * @return string @@ -132,7 +132,7 @@ protected function resetAttempts($payload) } /** - * Refreshes a jobs retryUntil time with it's own retryUntil method + * Refreshes a jobs retryUntil time with it's own retryUntil method. * * @param string $payload * @return string From 45eb7a7b1706ae175268731a673f369c0e556805 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 5 Jan 2021 08:56:06 -0600 Subject: [PATCH 034/443] formatting --- src/Illuminate/Queue/Console/RetryCommand.php | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index 055790da6446..fe6248800c99 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -93,29 +93,14 @@ protected function getJobIdsByRanges(array $ranges) protected function retryJob($job) { $this->laravel['queue']->connection($job->connection)->pushRaw( - $this->retryRefresh($job->payload), $job->queue + $this->refreshRetryUntil($this->resetAttempts($job->payload)), $job->queue ); } - /** - * Possibly refresh job attempts and retryUntil value. - * - * @param string $payload - * @return string - */ - protected function retryRefresh($payload) - { - $payload = $this->resetAttempts($payload); - - $payload = $this->refreshRetryUntil($payload); - - return $payload; - } - /** * Reset the payload attempts. * - * Applicable to Redis jobs which store attempts in their payload. + * Applicable to Redis and other jobs which store attempts in their payload. * * @param string $payload * @return string @@ -132,7 +117,7 @@ protected function resetAttempts($payload) } /** - * Refreshes a jobs retryUntil time with it's own retryUntil method. + * Refresh the "retry until" timestamp for the job. * * @param string $payload * @return string @@ -141,12 +126,10 @@ protected function refreshRetryUntil($payload) { $payload = json_decode($payload, true); - $jobInstance = unserialize($payload['data']['command']); - - if (method_exists($jobInstance, 'retryUntil')) { - $newRetryUntil = $jobInstance->retryUntil()->timestamp; + $instance = unserialize($payload['data']['command']); - $payload['retryUntil'] = $newRetryUntil; + if (is_object($instance) && method_exists($instance, 'retryUntil')) { + $payload['retryUntil'] = $instance->retryUntil()->timestamp; } return json_encode($payload); From 4686f22eaaddca3fd71f99290e833413cfcf8f4c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 5 Jan 2021 09:42:30 -0600 Subject: [PATCH 035/443] version --- 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 82860b6f7eb7..140615a3ce68 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.8'; + const VERSION = '6.20.9'; /** * The base path for the Laravel installation. From a61cab167c35f465a923737ee6e6fb99cd5fde88 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 5 Jan 2021 09:43:10 -0600 Subject: [PATCH 036/443] version --- 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 c7049c14096c..3dfa37ef701c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.20.1'; + const VERSION = '8.21.0'; /** * The base path for the Laravel installation. From 1fa20dd356af21af6e38d95e9ff2b1d444344fbe Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 5 Jan 2021 10:41:31 -0600 Subject: [PATCH 037/443] update conventions --- src/Illuminate/Http/Resources/CollectsResources.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Resources/CollectsResources.php b/src/Illuminate/Http/Resources/CollectsResources.php index a5531f7a02ce..5c42da4225f5 100644 --- a/src/Illuminate/Http/Resources/CollectsResources.php +++ b/src/Illuminate/Http/Resources/CollectsResources.php @@ -47,7 +47,8 @@ protected function collects() } if (Str::endsWith(class_basename($this), 'Collection') && - class_exists($class = Str::replaceLast('Collection', '', get_class($this)))) { + (class_exists($class = Str::replaceLast('Collection', '', get_class($this))) || + class_exists($class = Str::replaceLast('Collection', 'Resource', get_class($this))))) { return $class; } } From 74f1bdcd40000f8acf5e0b10f12370d50c5fea47 Mon Sep 17 00:00:00 2001 From: Ahmad Shakib Date: Tue, 5 Jan 2021 22:59:11 +0330 Subject: [PATCH 038/443] add array to URL action method argument (#35787) --- src/Illuminate/Support/Facades/URL.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/URL.php b/src/Illuminate/Support/Facades/URL.php index 9e11006d8697..05866345fea5 100755 --- a/src/Illuminate/Support/Facades/URL.php +++ b/src/Illuminate/Support/Facades/URL.php @@ -5,7 +5,7 @@ /** * @method static \Illuminate\Contracts\Routing\UrlGenerator setRootControllerNamespace(string $rootNamespace) * @method static bool hasValidSignature(\Illuminate\Http\Request $request, bool $absolute = true) - * @method static string action(string $action, $parameters = [], bool $absolute = true) + * @method static string action(string|array $action, $parameters = [], bool $absolute = true) * @method static string asset(string $path, bool $secure = null) * @method static string secureAsset(string $path) * @method static string current() From 006180a54d917de4420c1aeddb7c0251d0189651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Tue, 5 Jan 2021 19:50:42 -0300 Subject: [PATCH 039/443] Retry if DNS lookup fails (#35790) --- 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 6ba3c4939faa..07630c590d5c 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -44,6 +44,7 @@ protected function causedByLostConnection(Throwable $e) 'running with the --read-only option so it cannot execute this statement', 'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.', 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again', + 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known', 'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected', 'SQLSTATE[HY000] [2002] Connection timed out', 'SSL: Connection timed out', From 08b1b19ce0581d49d15321bdc1194aab1cb1b4b2 Mon Sep 17 00:00:00 2001 From: Joren Dandois Date: Wed, 6 Jan 2021 14:35:15 +0100 Subject: [PATCH 040/443] [6.x] Fix #35795 (#35797) Add an extra is_null check for php 8 --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index d62ec0ee9513..84e0964ba147 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1164,7 +1164,7 @@ public function validateJson($attribute, $value) return false; } - if (! is_scalar($value) && ! method_exists($value, '__toString')) { + if (! is_scalar($value) && ! is_null($value) && ! method_exists($value, '__toString')) { return false; } From 6e563129f679ea0a6fbcb2747e3be77bab3bff1c Mon Sep 17 00:00:00 2001 From: Adnan RIHAN Date: Wed, 6 Jan 2021 14:44:49 +0100 Subject: [PATCH 041/443] [8.x] "null" constraint prevents aliasing SQLite ROWID (#35792) * "null" constraint prevents aliasing SQLite ROWID * Changed tests accordingly --- .../Database/Schema/Grammars/SQLiteGrammar.php | 2 +- tests/Database/DatabaseSQLiteSchemaGrammarTest.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 5075c0504204..556d749e23b2 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -875,7 +875,7 @@ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) protected function modifyNullable(Blueprint $blueprint, Fluent $column) { if (is_null($column->virtualAs) && is_null($column->storedAs)) { - return $column->nullable ? ' null' : ' not null'; + return $column->nullable ? '' : ' not null'; } if ($column->nullable === false) { diff --git a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php index 41e53cc725e7..226c58bf2b34 100755 --- a/tests/Database/DatabaseSQLiteSchemaGrammarTest.php +++ b/tests/Database/DatabaseSQLiteSchemaGrammarTest.php @@ -361,7 +361,7 @@ public function testAddingString() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "foo" varchar null default \'bar\'', $statements[0]); + $this->assertSame('alter table "users" add column "foo" varchar default \'bar\'', $statements[0]); } public function testAddingText() @@ -663,8 +663,8 @@ public function testAddingTimestamps() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(2, $statements); $this->assertEquals([ - 'alter table "users" add column "created_at" datetime null', - 'alter table "users" add column "updated_at" datetime null', + 'alter table "users" add column "created_at" datetime', + 'alter table "users" add column "updated_at" datetime', ], $statements); } @@ -675,8 +675,8 @@ public function testAddingTimestampsTz() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(2, $statements); $this->assertEquals([ - 'alter table "users" add column "created_at" datetime null', - 'alter table "users" add column "updated_at" datetime null', + 'alter table "users" add column "created_at" datetime', + 'alter table "users" add column "updated_at" datetime', ], $statements); } @@ -687,7 +687,7 @@ public function testAddingRememberToken() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "remember_token" varchar null', $statements[0]); + $this->assertSame('alter table "users" add column "remember_token" varchar', $statements[0]); } public function testAddingBinary() From 101121830deaf4a8f1ff7e03b8dcbe56f15be2a9 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Wed, 6 Jan 2021 20:19:55 +0100 Subject: [PATCH 042/443] wip (#35803) --- src/Illuminate/Foundation/helpers.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index d6af860d8915..2c1540f18e37 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -586,11 +586,15 @@ function redirect($to = null, $status = 302, $headers = [], $secure = null) /** * Report an exception. * - * @param \Throwable $exception + * @param \Throwable|string $exception * @return void */ - function report(Throwable $exception) + function report($exception) { + if (is_string($exception)) { + $exception = new Exception($exception); + } + app(ExceptionHandler::class)->report($exception); } } From 7a0517e43d11d945bee7912dcc03ad4573cdece2 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 6 Jan 2021 22:36:47 +0200 Subject: [PATCH 043/443] [6.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 078fe3776c23..d92867e61bf9 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.8...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.9...6.x) + + +## [v6.20.9 (2021-01-05)](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) + +### Added +- [Updated Illuminate\Database\DetectsLostConnections with new strings](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) ## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) From 930e7f6f716f5e7c1e087d29c63abb2b76b3f500 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 6 Jan 2021 23:05:39 +0200 Subject: [PATCH 044/443] [8.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- CHANGELOG-8.x.md | 22 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 078fe3776c23..d92867e61bf9 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.8...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.9...6.x) + + +## [v6.20.9 (2021-01-05)](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) + +### Added +- [Updated Illuminate\Database\DetectsLostConnections with new strings](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) ## [v6.20.8 (2020-12-22)](https://github.com/laravel/framework/compare/v6.20.7...v6.20.8) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index c0499d7f01e5..1f35a3bc3813 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,26 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.20.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.21.0...8.x) + + +## [v8.21.0 (2021-01-05)](https://github.com/laravel/framework/compare/v8.20.1...v8.21.0) + +### Added +- Added command to clean batches table ([#35694](https://github.com/laravel/framework/pull/35694), [33f5ac6](https://github.com/laravel/framework/commit/33f5ac695a55d6cdbadcfe1b46e3409e4a66df16)) +- Added item to list of causedByLostConnection errors ([#35744](https://github.com/laravel/framework/pull/35744)) +- Make it possible to set Postmark Message Stream ID ([#35755](https://github.com/laravel/framework/pull/35755)) + +### Fixed +- Fixed `php artisan db` command for the Postgres CLI ([#35725](https://github.com/laravel/framework/pull/35725)) +- Fixed OPTIONS method bug with use same path and diff domain when cache route ([#35714](https://github.com/laravel/framework/pull/35714)) + +### Changed +- Ensure DBAL custom type doesn't exists in `Illuminate\Database\DatabaseServiceProvider::registerDoctrineTypes()` ([#35704](https://github.com/laravel/framework/pull/35704)) +- Added missing `dispatchAfterCommit` to `DatabaseQueue` ([#35715](https://github.com/laravel/framework/pull/35715)) +- Set chain queue when inside a batch ([#35746](https://github.com/laravel/framework/pull/35746)) +- Give a more meaningul message when route parameters are missing ([#35706](https://github.com/laravel/framework/pull/35706)) +- Added table prefix to `Illuminate\Database\Console\DumpCommand::schemaState()` ([4ffe40f](https://github.com/laravel/framework/commit/4ffe40fb169c6bcce9193ff56958eca41e64294f)) +- Refresh the retryUntil time on job retry ([#35780](https://github.com/laravel/framework/pull/35780), [45eb7a7](https://github.com/laravel/framework/commit/45eb7a7b1706ae175268731a673f369c0e556805)) ## [v8.20.1 (2020-12-22)](https://github.com/laravel/framework/compare/v8.20.0...v8.20.1) From 524b1b3b4d677285ae2148d5a3b10774c696f8d8 Mon Sep 17 00:00:00 2001 From: Jesse Kramer Date: Thu, 7 Jan 2021 14:53:36 +0100 Subject: [PATCH 045/443] The request helper might return null, update docblock to reflect this. (#35812) --- 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 2c1540f18e37..3842915bf721 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -605,7 +605,7 @@ function report($exception) * * @param array|string|null $key * @param mixed $default - * @return \Illuminate\Http\Request|string|array + * @return \Illuminate\Http\Request|string|array|null */ function request($key = null, $default = null) { From 4415b94623358bfd1dc2e8f20e4deab0025d2d03 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 7 Jan 2021 08:08:57 -0600 Subject: [PATCH 046/443] fix breaking change --- src/Illuminate/Queue/Console/RetryCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index fe6248800c99..545f8489b8ae 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -126,6 +126,10 @@ protected function refreshRetryUntil($payload) { $payload = json_decode($payload, true); + if (! isset($payload['data']['command'])) { + return json_encode($payload); + } + $instance = unserialize($payload['data']['command']); if (is_object($instance) && method_exists($instance, 'retryUntil')) { From b3ebb1b01c8ce9d7ab931882105cf6aedd3e8242 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 7 Jan 2021 17:57:53 +0100 Subject: [PATCH 047/443] Fix expectsTable call (#35820) --- src/Illuminate/Testing/PendingCommand.php | 58 +++++++---------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index 55ea307c82f3..3e08c53ccee7 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -157,12 +157,24 @@ public function doesntExpectOutput($output) */ public function expectsTable($headers, $rows, $tableStyle = 'default', array $columnStyles = []) { - $this->test->expectedTables[] = [ - 'headers' => (array) $headers, - 'rows' => $rows instanceof Arrayable ? $rows->toArray() : $rows, - 'tableStyle' => $tableStyle, - 'columnStyles' => $columnStyles, - ]; + $table = (new Table($output = new BufferedOutput)) + ->setHeaders((array) $headers) + ->setRows($rows instanceof Arrayable ? $rows->toArray() : $rows) + ->setStyle($tableStyle); + + foreach ($columnStyles as $columnIndex => $columnStyle) { + $table->setColumnStyle($columnIndex, $columnStyle); + } + + $table->render(); + + $lines = array_filter( + explode(PHP_EOL, $output->fetch()) + ); + + foreach ($lines as $line) { + $this->expectsOutput($line); + } return $this; } @@ -305,8 +317,6 @@ private function createABufferedOutputMock() ->shouldAllowMockingProtectedMethods() ->shouldIgnoreMissing(); - $this->applyTableOutputExpectations($mock); - foreach ($this->test->expectedOutput as $i => $output) { $mock->shouldReceive('doWrite') ->once() @@ -330,38 +340,6 @@ private function createABufferedOutputMock() return $mock; } - /** - * Apply the output table expectations to the mock. - * - * @param \Mockery\MockInterface $mock - * @return void - */ - private function applyTableOutputExpectations($mock) - { - foreach ($this->test->expectedTables as $i => $consoleTable) { - $table = (new Table($output = new BufferedOutput)) - ->setHeaders($consoleTable['headers']) - ->setRows($consoleTable['rows']) - ->setStyle($consoleTable['tableStyle']); - - foreach ($consoleTable['columnStyles'] as $columnIndex => $columnStyle) { - $table->setColumnStyle($columnIndex, $columnStyle); - } - - $table->render(); - - $lines = array_filter( - explode(PHP_EOL, $output->fetch()) - ); - - foreach ($lines as $line) { - $this->expectsOutput($line); - } - - unset($this->test->expectedTables[$i]); - } - } - /** * Flush the expectations from the test case. * From bd7aaa8ff0c37907ac66fcccfebc7d6e25a7402c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 8 Jan 2021 15:07:38 +0100 Subject: [PATCH 048/443] Fix bug with RetryCommand (#35828) --- src/Illuminate/Queue/Console/RetryCommand.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index 545f8489b8ae..ad090f6fa5d0 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -2,6 +2,7 @@ namespace Illuminate\Queue\Console; +use DateTimeInterface; use Illuminate\Console\Command; use Illuminate\Support\Arr; @@ -133,7 +134,11 @@ protected function refreshRetryUntil($payload) $instance = unserialize($payload['data']['command']); if (is_object($instance) && method_exists($instance, 'retryUntil')) { - $payload['retryUntil'] = $instance->retryUntil()->timestamp; + $retryUntil = $instance->retryUntil(); + + $payload['retryUntil'] = $retryUntil instanceof DateTimeInterface + ? $retryUntil->getTimestamp() + : $retryUntil; } return json_encode($payload); From 74bb56ad68737ee76b11e21bc51c192149a63e43 Mon Sep 17 00:00:00 2001 From: Rhys Emmerson Date: Sat, 9 Jan 2021 02:21:58 +1000 Subject: [PATCH 049/443] do not map empty string in morph type to instance (#35824) Co-authored-by: Rhys --- .../Database/Eloquent/Concerns/HasRelationships.php | 2 +- tests/Database/DatabaseEloquentMorphToTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 9ee9e3d124e3..5262d4305273 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -256,7 +256,7 @@ public function morphTo($name = null, $type = null, $id = null, $ownerKey = null // If the type value is null it is probably safe to assume we're eager loading // 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)) + return is_null($class = $this->getAttributeFromArray($type)) || $class === '' ? $this->morphEagerTo($name, $type, $id, $ownerKey) : $this->morphInstanceTo($class, $name, $type, $id, $ownerKey); } diff --git a/tests/Database/DatabaseEloquentMorphToTest.php b/tests/Database/DatabaseEloquentMorphToTest.php index 172a2aa84d1d..a6bd248ff563 100644 --- a/tests/Database/DatabaseEloquentMorphToTest.php +++ b/tests/Database/DatabaseEloquentMorphToTest.php @@ -100,6 +100,16 @@ public function testMorphToWithZeroMorphType() $parent->relation(); } + public function testMorphToWithEmptyStringMorphType() + { + $parent = $this->getMockBuilder(EloquentMorphToModelStub::class)->onlyMethods(['getAttributeFromArray', 'morphEagerTo', 'morphInstanceTo'])->getMock(); + $parent->method('getAttributeFromArray')->with('relation_type')->willReturn(''); + $parent->expects($this->once())->method('morphEagerTo'); + $parent->expects($this->never())->method('morphInstanceTo'); + + $parent->relation(); + } + public function testMorphToWithSpecifiedClassDefault() { $parent = new EloquentMorphToModelStub; From e8ba1d80ba95c7bc1fb9884808662939c03db43e Mon Sep 17 00:00:00 2001 From: Krayvok <76506910+Krayvok@users.noreply.github.com> Date: Mon, 11 Jan 2021 06:46:02 -0800 Subject: [PATCH 050/443] Update Session.php (#35838) Add method tag for flash(). --- src/Illuminate/Support/Facades/Session.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Session.php b/src/Illuminate/Support/Facades/Session.php index 70e42e20ef16..12a4547a1fbb 100755 --- a/src/Illuminate/Support/Facades/Session.php +++ b/src/Illuminate/Support/Facades/Session.php @@ -13,6 +13,7 @@ * @method static bool save() * @method static bool start() * @method static mixed get(string $key, $default = null) + * @method static mixed flash(string $class, string $message) * @method static mixed pull(string $key, $default = null) * @method static mixed remove(string $key) * @method static string getId() From 374e9565b2718c549f329af5c137e84a7d753a28 Mon Sep 17 00:00:00 2001 From: Theraloss Date: Mon, 11 Jan 2021 15:57:10 +0100 Subject: [PATCH 051/443] [8.x] Add ::assertNothingDispatched() to Events::fake (#35835) * Add ::assertNothingDispatched() to events fake * Update EventFake.php * Update SupportTestingEventFakeTest.php Co-authored-by: Taylor Otwell --- .../Support/Testing/Fakes/EventFake.php | 15 +++++++++++++++ tests/Support/SupportTestingEventFakeTest.php | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 84f67482ebe3..90f30212ef7b 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -106,6 +106,21 @@ public function assertNotDispatched($event, $callback = null) ); } + /** + * Assert that no events were dispatched. + * + * @return void + */ + public function assertNothingDispatched() + { + $count = count(Arr::flatten($this->events)); + + PHPUnit::assertSame( + 0, $count, + "{$count} unexpected events were dispatched." + ); + } + /** * Get all of the events matching a truth-test callback. * diff --git a/tests/Support/SupportTestingEventFakeTest.php b/tests/Support/SupportTestingEventFakeTest.php index 3a9ccc6cdd3b..d51562d10c58 100644 --- a/tests/Support/SupportTestingEventFakeTest.php +++ b/tests/Support/SupportTestingEventFakeTest.php @@ -118,6 +118,21 @@ function ($event, $payload) { $fake->assertDispatched('Bar'); $fake->assertNotDispatched('Baz'); } + + public function testAssertNothingDispatched() + { + $this->fake->assertNothingDispatched(); + + $this->fake->dispatch(EventStub::class); + $this->fake->dispatch(EventStub::class); + + try { + $this->fake->assertNothingDispatched(); + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertThat($e, new ExceptionMessage('2 unexpected events were dispatched.')); + } + } } class EventStub From 08dbb8bea12104974ba86337bd37e0471254f39b Mon Sep 17 00:00:00 2001 From: Mo Khosh Date: Tue, 12 Jan 2021 18:51:34 +0330 Subject: [PATCH 052/443] [8.x] Add reduce with keys to collections and lazy collections (#35839) * add reduce with keys to collections * add reduce with keys to lazy collections * add test for reduce with keys * fix style --- src/Illuminate/Collections/Collection.php | 18 ++++++++++++++++++ src/Illuminate/Collections/LazyCollection.php | 18 ++++++++++++++++++ tests/Support/SupportCollectionTest.php | 14 ++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index f4c7b4007a91..6a8ab88818aa 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -884,6 +884,24 @@ public function reduce(callable $callback, $initial = null) return array_reduce($this->items, $callback, $initial); } + /** + * Reduce an associative collection to a single value. + * + * @param callable $callback + * @param mixed $initial + * @return mixed + */ + public function reduceWithKeys(callable $callback, $initial = null) + { + $result = $initial; + + foreach ($this->items as $key => $value) { + $result = $callback($result, $value, $key); + } + + return $result; + } + /** * Replace the collection items with the given items. * diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 2384948f951a..ca51626b071e 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -845,6 +845,24 @@ public function reduce(callable $callback, $initial = null) return $result; } + /** + * Reduce an associative collection to a single value. + * + * @param callable $callback + * @param mixed $initial + * @return mixed + */ + public function reduceWithKeys(callable $callback, $initial = null) + { + $result = $initial; + + foreach ($this as $key => $value) { + $result = $callback($result, $value, $key); + } + + return $result; + } + /** * Replace the collection items with the given items. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 6faf65a1a3c2..b622884fe6c1 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3592,6 +3592,20 @@ public function testReduce($collection) })); } + /** + * @dataProvider collectionClassProvider + */ + public function testReduceWithKeys($collection) + { + $data = new $collection([ + 'foo' => 'bar', + 'baz' => 'qux', + ]); + $this->assertEquals('foobarbazqux', $data->reduceWithKeys(function ($carry, $element, $key) { + return $carry .= $key.$element; + })); + } + /** * @dataProvider collectionClassProvider */ From 88dced8fc1016411ca159fc04651baf270aa54e5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 12 Jan 2021 09:30:21 -0600 Subject: [PATCH 053/443] version --- 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 140615a3ce68..ae6e70351474 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.9'; + const VERSION = '6.20.10'; /** * The base path for the Laravel installation. From 594c08af2aad632a27c71efcc53e93caa3329e3d Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 12 Jan 2021 23:43:09 +0200 Subject: [PATCH 054/443] [6.x] update changelog --- CHANGELOG-6.x.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index d92867e61bf9..3ab00165cccc 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,15 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.9...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.10...6.x) + + +## [v6.20.10 (2021-01-12)](https://github.com/laravel/framework/compare/v6.20.9...v6.20.10) + +### Added +- Added new line to `DetectsLostConnections` ([#35790](https://github.com/laravel/framework/pull/35790)) + +### Fixed +- Fixed error from missing null check on PHP 8 in `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` ([#35797](https://github.com/laravel/framework/pull/35797)) ## [v6.20.9 (2021-01-05)](https://github.com/laravel/framework/compare/v6.20.8...v6.20.9) From cd26138df21c87b12f96613a7592a16306be3563 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 13 Jan 2021 00:06:36 +0200 Subject: [PATCH 055/443] [8.x] update changelog --- CHANGELOG-8.x.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 1f35a3bc3813..6879551e0a1e 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,25 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.21.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.22.0...8.x) + + +## [v8.22.0 (2021-01-12)](https://github.com/laravel/framework/compare/v8.21.0...v8.22.0) + +### Added +- Added new lines to `DetectsLostConnections` ([#35752](https://github.com/laravel/framework/pull/35752), [#35790](https://github.com/laravel/framework/pull/35790)) +- Added `Illuminate\Support\Testing\Fakes\EventFake::assertNothingDispatched()` ([#35835](https://github.com/laravel/framework/pull/35835)) +- Added reduce with keys to collections and lazy collections ([#35839](https://github.com/laravel/framework/pull/35839)) + +### Fixed +- Fixed error from missing null check on PHP 8 in `Illuminate\Validation\Concerns\ValidatesAttributes::validateJson()` ([#35797](https://github.com/laravel/framework/pull/35797)) +- Fix bug with RetryCommand ([4415b94](https://github.com/laravel/framework/commit/4415b94623358bfd1dc2e8f20e4deab0025d2d03), [#35828](https://github.com/laravel/framework/pull/35828)) +- Fixed `Illuminate\Testing\PendingCommand::expectsTable()` ([#35820](https://github.com/laravel/framework/pull/35820)) +- Fixed `morphTo()` attempting to map an empty string morph type to an instance ([#35824](https://github.com/laravel/framework/pull/35824)) + +### Changes +- Update `Illuminate\Http\Resources\CollectsResources::collects()` ([1fa20dd](https://github.com/laravel/framework/commit/1fa20dd356af21af6e38d95e9ff2b1d444344fbe)) +- "null" constraint prevents aliasing SQLite ROWID ([#35792](https://github.com/laravel/framework/pull/35792)) +- Allow strings to be passed to the `report` function ([#35803](https://github.com/laravel/framework/pull/35803)) ## [v8.21.0 (2021-01-05)](https://github.com/laravel/framework/compare/v8.20.1...v8.21.0) From d0954f4574f315f0c2e9e65e92cc74b80eadcac1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 13 Jan 2021 07:35:45 -0600 Subject: [PATCH 056/443] [6.x] Limit expected bindings (#35865) * limit expected bindings * limit more bindings --- src/Illuminate/Database/Query/Builder.php | 18 ++++++++--- tests/Database/DatabaseQueryBuilderTest.php | 34 ++++++++++----------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0d4c7c3ae16c..83416d83be02 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -698,7 +698,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' ); if (! $value instanceof Expression) { - $this->addBinding($value, 'where'); + $this->addBinding(is_array($value) ? head($value) : $value, 'where'); } return $this; @@ -1043,7 +1043,7 @@ public function whereBetween($column, array $values, $boolean = 'and', $not = fa $this->wheres[] = compact('type', 'column', 'values', 'boolean', 'not'); - $this->addBinding($this->cleanBindings($values), 'where'); + $this->addBinding(array_slice($this->cleanBindings($values), 0, 2), 'where'); return $this; } @@ -1111,6 +1111,8 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + $value = is_array($value) ? head($value) : $value; + if ($value instanceof DateTimeInterface) { $value = $value->format('Y-m-d'); } @@ -1150,6 +1152,8 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + $value = is_array($value) ? head($value) : $value; + if ($value instanceof DateTimeInterface) { $value = $value->format('H:i:s'); } @@ -1189,6 +1193,8 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + $value = is_array($value) ? head($value) : $value; + if ($value instanceof DateTimeInterface) { $value = $value->format('d'); } @@ -1232,6 +1238,8 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + $value = is_array($value) ? head($value) : $value; + if ($value instanceof DateTimeInterface) { $value = $value->format('m'); } @@ -1275,6 +1283,8 @@ public function whereYear($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + $value = is_array($value) ? head($value) : $value; + if ($value instanceof DateTimeInterface) { $value = $value->format('Y'); } @@ -1583,7 +1593,7 @@ public function whereJsonLength($column, $operator, $value = null, $boolean = 'a $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { - $this->addBinding($value); + $this->addBinding((int) $value); } return $this; @@ -1732,7 +1742,7 @@ public function having($column, $operator = null, $value = null, $boolean = 'and $this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { - $this->addBinding($value, 'having'); + $this->addBinding(is_array($value) ? head($value) : $value, 'having'); } return $this; diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 87f7268a565b..407b312ee5bf 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -301,24 +301,24 @@ public function testBasicWheres() public function testWheresWithArrayValue() { $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where('id', [12, 30]); + $builder->select('*')->from('users')->where('id', [12]); $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); - $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); - - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where('id', '=', [12, 30]); - $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); - $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); - - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where('id', '!=', [12, 30]); - $this->assertSame('select * from "users" where "id" != ?', $builder->toSql()); - $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); - - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where('id', '<>', [12, 30]); - $this->assertSame('select * from "users" where "id" <> ?', $builder->toSql()); - $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); + $this->assertEquals([0 => 12], $builder->getBindings()); + + // $builder = $this->getBuilder(); + // $builder->select('*')->from('users')->where('id', '=', [12, 30]); + // $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); + // $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); + + // $builder = $this->getBuilder(); + // $builder->select('*')->from('users')->where('id', '!=', [12, 30]); + // $this->assertSame('select * from "users" where "id" != ?', $builder->toSql()); + // $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); + + // $builder = $this->getBuilder(); + // $builder->select('*')->from('users')->where('id', '<>', [12, 30]); + // $this->assertSame('select * from "users" where "id" <> ?', $builder->toSql()); + // $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); } public function testMySqlWrappingProtectsQuotationMarks() From 29c831df184f1dff7ee1444352472b037241d340 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 13 Jan 2021 07:36:19 -0600 Subject: [PATCH 057/443] version --- 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 ae6e70351474..97a41bb7711c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.10'; + const VERSION = '6.20.11'; /** * The base path for the Laravel installation. From 2cd4fd8110865c4ea98a26e273c8da4a61bdf17e Mon Sep 17 00:00:00 2001 From: Patrick O'Meara Date: Thu, 14 Jan 2021 01:18:20 +1100 Subject: [PATCH 058/443] [8.x] Allow a specific seeder to be used in tests (#35864) * Allow a specific seeder to be used in tests * if $seeder is set within a test use it instead of the default. * Update RefreshDatabase.php Co-authored-by: Taylor Otwell --- .../Foundation/Testing/RefreshDatabase.php | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/RefreshDatabase.php b/src/Illuminate/Foundation/Testing/RefreshDatabase.php index f62fad83c559..d66fd0f94911 100644 --- a/src/Illuminate/Foundation/Testing/RefreshDatabase.php +++ b/src/Illuminate/Foundation/Testing/RefreshDatabase.php @@ -79,11 +79,15 @@ protected function refreshTestDatabase() */ protected function migrateFreshUsing() { - return [ - '--drop-views' => $this->shouldDropViews(), - '--drop-types' => $this->shouldDropTypes(), - '--seed' => $this->shouldSeed(), - ]; + $seeder = $this->seeder(); + + return array_merge( + [ + '--drop-views' => $this->shouldDropViews(), + '--drop-types' => $this->shouldDropTypes(), + ], + $seeder ? ['--seeder' => $seeder] : ['--seed' => $this->shouldSeed()] + ); } /** @@ -157,4 +161,14 @@ protected function shouldSeed() { return property_exists($this, 'seed') ? $this->seed : false; } + + /** + * Determine the specific seeder class that should be used when refreshing the database. + * + * @return mixed + */ + protected function seeder() + { + return property_exists($this, 'seeder') ? $this->seeder : false; + } } From 8c6f18188a4d971312610315b7f1aa7b2261f170 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 13 Jan 2021 16:48:18 +0200 Subject: [PATCH 059/443] add sole to the query builder --- .../Database/Concerns/BuildsQueries.php | 26 ++++++++++++++++++ .../MultipleRecordsFoundException.php | 10 +++++++ .../Database/NoRecordsFoundException.php | 10 +++++++ .../Integration/Database/QueryBuilderTest.php | 27 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100755 src/Illuminate/Database/MultipleRecordsFoundException.php create mode 100755 src/Illuminate/Database/NoRecordsFoundException.php diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 6a39b4cb8fc4..f74782c16a4e 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -3,6 +3,8 @@ namespace Illuminate\Database\Concerns; use Illuminate\Container\Container; +use Illuminate\Database\MultipleRecordsFoundException; +use Illuminate\Database\NoRecordsFoundException; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; @@ -147,6 +149,30 @@ public function first($columns = ['*']) return $this->take(1)->get($columns)->first(); } + /** + * Execute the query and get the first result if it's the sole. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Model|object|static|null + * + * @throws \Illuminate\Database\NoRecordsFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + */ + public function sole($columns = ['*']) + { + $result = $this->get($columns); + + if ($result->isEmpty()) { + throw new NoRecordsFoundException(); + } + + if ($result->count() > 1) { + throw new MultipleRecordsFoundException(); + } + + return $result->first(); + } + /** * Apply the callback's query changes if the given "value" is true. * diff --git a/src/Illuminate/Database/MultipleRecordsFoundException.php b/src/Illuminate/Database/MultipleRecordsFoundException.php new file mode 100755 index 000000000000..390976d8db9a --- /dev/null +++ b/src/Illuminate/Database/MultipleRecordsFoundException.php @@ -0,0 +1,10 @@ + '1', 'title' => 'Foo Post']; + + $this->assertEquals(1, DB::table('posts')->where('title', 'Foo Post')->sole()->id); + } + + public function testSoleFailsForMultipleRecords() + { + DB::table('posts')->insert([ + ['title' => 'Foo Post', 'content' => 'Lorem Ipsum.', 'created_at' => new Carbon('2017-11-12 13:14:15')], + ]); + + $this->expectException(MultipleRecordsFoundException::class); + + DB::table('posts')->where('title', 'Foo Post')->sole(); + } + + public function testSoleFailsIfNoRecords() + { + $this->expectException(NoRecordsFoundException::class); + + DB::table('posts')->where('title', 'Baz Post')->sole(); + } + public function testSelect() { $expected = ['id' => '1', 'title' => 'Foo Post']; From bcf818fa71eba69cc75e1de003a30ac058d860fa Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 13 Jan 2021 16:58:00 +0200 Subject: [PATCH 060/443] fix style --- src/Illuminate/Database/MultipleRecordsFoundException.php | 2 +- src/Illuminate/Database/NoRecordsFoundException.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/MultipleRecordsFoundException.php b/src/Illuminate/Database/MultipleRecordsFoundException.php index 390976d8db9a..cccb7e4177bf 100755 --- a/src/Illuminate/Database/MultipleRecordsFoundException.php +++ b/src/Illuminate/Database/MultipleRecordsFoundException.php @@ -6,5 +6,5 @@ class MultipleRecordsFoundException extends RuntimeException { - + // } diff --git a/src/Illuminate/Database/NoRecordsFoundException.php b/src/Illuminate/Database/NoRecordsFoundException.php index 938d4c36293d..b45266c8e9bf 100755 --- a/src/Illuminate/Database/NoRecordsFoundException.php +++ b/src/Illuminate/Database/NoRecordsFoundException.php @@ -6,5 +6,5 @@ class NoRecordsFoundException extends RuntimeException { - + // } From b1fd05eaa3b7b59677fddd6b6caad407c6bbecce Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 13 Jan 2021 17:15:07 +0200 Subject: [PATCH 061/443] take 2 --- src/Illuminate/Database/Concerns/BuildsQueries.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index f74782c16a4e..9aa590654b83 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -160,7 +160,7 @@ public function first($columns = ['*']) */ public function sole($columns = ['*']) { - $result = $this->get($columns); + $result = $this->take(2)->get($columns); if ($result->isEmpty()) { throw new NoRecordsFoundException(); From 32ec62102e93a1d9bb9b8f4f2f83a633a9255fb8 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 13 Jan 2021 12:36:07 -0500 Subject: [PATCH 062/443] Add @JosephSilber as codeowner on Collections (#35872) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000000..c3d39f873292 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +/src/Illuminate/Collections/ @JosephSilber From bb957035dda413a22791609724b9ded26feee6ed Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 13 Jan 2021 15:29:22 -0500 Subject: [PATCH 063/443] Add @JosephSilber as codeowner on Collections tests (#35873) --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c3d39f873292..e89cb3511502 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,4 @@ /src/Illuminate/Collections/ @JosephSilber +/tests/Support/SupportCollectionTest/ @JosephSilber +/tests/Support/SupportLazyCollectionTest/ @JosephSilber +/tests/Support/SupportLazyCollectionIsLazyTest/ @JosephSilber From 290ca48b2d2ed1eca9cf078038706b9683e0d4f9 Mon Sep 17 00:00:00 2001 From: Harry Gulliford Date: Thu, 14 Jan 2021 10:59:36 +1100 Subject: [PATCH 064/443] Update supported versions --- .github/SECURITY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 444b8e623703..1ce441d0affb 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -6,6 +6,8 @@ Version | Security Fixes Until --- | --- +8 | September 8th, 2021 +7 | March 3rd, 2021 6 (LTS) | September 3rd, 2022 5.8 | February 26th, 2020 5.7 | September 4th, 2019 From 49ee16b9ee784d425205fa456b43581de7cf804a Mon Sep 17 00:00:00 2001 From: iamgergo Date: Thu, 14 Jan 2021 13:07:07 +0100 Subject: [PATCH 065/443] [8.x] Formatting some docblocks --- src/Illuminate/Collections/Collection.php | 2 +- src/Illuminate/Collections/LazyCollection.php | 2 +- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- src/Illuminate/Routing/Exceptions/UrlGenerationException.php | 2 +- src/Illuminate/Testing/AssertableJsonString.php | 3 +-- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 6a8ab88818aa..f708a3ee28bd 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -888,7 +888,7 @@ public function reduce(callable $callback, $initial = null) * Reduce an associative collection to a single value. * * @param callable $callback - * @param mixed $initial + * @param mixed $initial * @return mixed */ public function reduceWithKeys(callable $callback, $initial = null) diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index ca51626b071e..c7995fb27e1b 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -849,7 +849,7 @@ public function reduce(callable $callback, $initial = null) * Reduce an associative collection to a single value. * * @param callable $callback - * @param mixed $initial + * @param mixed $initial * @return mixed */ public function reduceWithKeys(callable $callback, $initial = null) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 3fcb75e67ab5..2185ec641ac6 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -223,7 +223,7 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, /** * Get a relationship join table hash. * - * @param bool $incrementJoinCount + * @param bool $incrementJoinCount * @return string */ public function getRelationCountHash($incrementJoinCount = true) diff --git a/src/Illuminate/Routing/Exceptions/UrlGenerationException.php b/src/Illuminate/Routing/Exceptions/UrlGenerationException.php index e0057c9d6bbf..eadda8010c0f 100644 --- a/src/Illuminate/Routing/Exceptions/UrlGenerationException.php +++ b/src/Illuminate/Routing/Exceptions/UrlGenerationException.php @@ -12,7 +12,7 @@ class UrlGenerationException extends Exception * Create a new exception for missing route parameters. * * @param \Illuminate\Routing\Route $route - * @param array $parameters + * @param array $parameters * @return static */ public static function forMissingParameters(Route $route, array $parameters = []) diff --git a/src/Illuminate/Testing/AssertableJsonString.php b/src/Illuminate/Testing/AssertableJsonString.php index 5a73afe50c7f..e36c84aa300d 100644 --- a/src/Illuminate/Testing/AssertableJsonString.php +++ b/src/Illuminate/Testing/AssertableJsonString.php @@ -276,8 +276,7 @@ public function assertSubset(array $data, $strict = false) /** * Reorder associative array keys to make it easy to compare arrays. * - * @param array $data - * + * @param array $data * @return array */ protected function reorderAssocKeys(array $data) From 83ec510eef7c4e40c6a4c776041e0a1d04ea1c9e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 14 Jan 2021 08:30:21 -0600 Subject: [PATCH 066/443] [8.x] Fix extra space on blade class components that are inline (#35874) This fixes extra spacing before and after Blade class components. --- .../View/Compilers/BladeCompiler.php | 5 +- .../View/Compilers/ComponentTagCompiler.php | 6 +- tests/Integration/View/BladeTest.php | 10 ++- .../View/templates/components/link.blade.php | 3 + .../View/templates/uses-link.blade.php | 1 + .../Blade/BladeComponentTagCompilerTest.php | 74 +++++++++---------- 6 files changed, 56 insertions(+), 43 deletions(-) create mode 100644 tests/Integration/View/templates/components/link.blade.php create mode 100644 tests/Integration/View/templates/uses-link.blade.php diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 4482036072fd..1d08d0c0821c 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -251,7 +251,10 @@ public function compileString($value) $result = $this->addFooters($result); } - return $result; + return str_replace( + ['##BEGIN-COMPONENT-CLASS##', '##END-COMPONENT-CLASS##'], + '', + $result); } /** diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index b7b5300535b6..9e079ac8a07c 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -193,7 +193,7 @@ protected function compileSelfClosingTags(string $value) $attributes = $this->getAttributesFromAttributeString($matches['attributes']); - return $this->componentString($matches[1], $attributes)."\n@endcomponentClass "; + return $this->componentString($matches[1], $attributes)."\n@endComponentClass##END-COMPONENT-CLASS##"; }, $value); } @@ -230,7 +230,7 @@ protected function componentString(string $component, array $attributes) $parameters = $data->all(); } - return " @component('{$class}', '{$component}', [".$this->attributesToString($parameters, $escapeBound = false).']) + return "##BEGIN-COMPONENT-CLASS##@component('{$class}', '{$component}', [".$this->attributesToString($parameters, $escapeBound = false).']) withAttributes(['.$this->attributesToString($attributes->all(), $escapeAttributes = $class !== DynamicComponent::class).']); ?>'; } @@ -384,7 +384,7 @@ public function partitionDataAndAttributes($class, array $attributes) */ protected function compileClosingTags(string $value) { - return preg_replace("/<\/\s*x[-\:][\w\-\:\.]*\s*>/", ' @endcomponentClass ', $value); + return preg_replace("/<\/\s*x[-\:][\w\-\:\.]*\s*>/", ' @endComponentClass##END-COMPONENT-CLASS##', $value); } /** diff --git a/tests/Integration/View/BladeTest.php b/tests/Integration/View/BladeTest.php index a26460ba90ec..864a041f5d21 100644 --- a/tests/Integration/View/BladeTest.php +++ b/tests/Integration/View/BladeTest.php @@ -42,12 +42,18 @@ public function test_rendering_the_same_dynamic_component_with_different_attribu $this->assertSame(' Hello Taylor - - + Hello Samuel ', trim($view)); } + public function test_inline_link_type_attributes_dont_add_extra_spacing_at_end() + { + $view = View::make('uses-link')->render(); + + $this->assertSame('This is a sentence with a link.', trim($view)); + } + public function test_appendable_attributes() { $view = View::make('uses-appendable-panel', ['name' => 'Taylor', 'withInjectedValue' => true])->render(); diff --git a/tests/Integration/View/templates/components/link.blade.php b/tests/Integration/View/templates/components/link.blade.php new file mode 100644 index 000000000000..74b8835393b6 --- /dev/null +++ b/tests/Integration/View/templates/components/link.blade.php @@ -0,0 +1,3 @@ +@props(['href']) + +{{ $slot }} \ No newline at end of file diff --git a/tests/Integration/View/templates/uses-link.blade.php b/tests/Integration/View/templates/uses-link.blade.php new file mode 100644 index 000000000000..53a67cf64e30 --- /dev/null +++ b/tests/Integration/View/templates/uses-link.blade.php @@ -0,0 +1 @@ +This is a sentence with a link. \ No newline at end of file diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index b84030c13d2b..c9b89df6096e 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -40,69 +40,69 @@ public function testBasicComponentParsing() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
'); - $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) + $this->assertSame("
##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes(['type' => 'foo','limit' => '5','@click' => 'foo','wire:click' => 'changePlan(\''.e(\$plan).'\')','required' => true]); ?>\n". -"@endcomponentClass @component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) +"@endComponentClass##END-COMPONENT-CLASS####BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes([]); ?>\n". -'@endcomponentClass
', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##
', trim($result)); } public function testBasicComponentWithEmptyAttributesParsing() { $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
'); - $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) + $this->assertSame("
##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes(['type' => '','limit' => '','@click' => '','required' => true]); ?>\n". -'@endcomponentClass
', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##
', trim($result)); } public function testDataCamelCasing() { $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => '1']) -withAttributes([]); ?> @endcomponentClass", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => '1']) +withAttributes([]); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testColonData() { $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => 1]) -withAttributes([]); ?> @endcomponentClass", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => 1]) +withAttributes([]); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testColonAttributesIsEscapedIfStrings() { $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) -withAttributes(['src' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('foo')]); ?> @endcomponentClass", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) +withAttributes(['src' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('foo')]); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testColonNestedComponentParsing() { $result = $this->compiler(['foo:alert' => TestAlertComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'foo:alert', []) -withAttributes([]); ?> @endcomponentClass", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'foo:alert', []) +withAttributes([]); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testColonStartingNestedComponentParsing() { $result = $this->compiler(['foo:alert' => TestAlertComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'foo:alert', []) -withAttributes([]); ?> @endcomponentClass", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'foo:alert', []) +withAttributes([]); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testSelfClosingComponentsCanBeCompiled() { $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
'); - $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) + $this->assertSame("
##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes([]); ?>\n". -'@endcomponentClass
', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##
', trim($result)); } public function testClassNamesCanBeGuessed() @@ -139,18 +139,18 @@ public function testComponentsCanBeCompiledWithHyphenAttributes() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes(['class' => 'bar','wire:model' => 'foo','x-on:click' => 'bar','@click' => 'baz']); ?>\n". -'@endcomponentClass', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##', trim($result)); } public function testSelfClosingComponentsCanBeCompiledWithDataAndAttributes() { $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => 'foo']) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => 'foo']) withAttributes(['class' => 'bar','wire:model' => 'foo']); ?>\n". -'@endcomponentClass', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##', trim($result)); } public function testComponentCanReceiveAttributeBag() @@ -158,8 +158,8 @@ public function testComponentCanReceiveAttributeBag() $this->mockViewFactory(); $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) -withAttributes(['class' => 'bar','attributes' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\$attributes),'wire:model' => 'foo']); ?> @endcomponentClass", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) +withAttributes(['class' => 'bar','attributes' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\$attributes),'wire:model' => 'foo']); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testSelfClosingComponentCanReceiveAttributeBag() @@ -168,35 +168,35 @@ public function testSelfClosingComponentCanReceiveAttributeBag() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('
merge([\'class\' => \'test\']) }} wire:model="foo" />
'); - $this->assertSame("
@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => 'foo']) + $this->assertSame("
##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => 'foo']) withAttributes(['class' => 'bar','attributes' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\$attributes->merge(['class' => 'test'])),'wire:model' => 'foo']); ?>\n". - '@endcomponentClass
', trim($result)); + '@endComponentClass##END-COMPONENT-CLASS##
', trim($result)); } public function testComponentsCanHaveAttachedWord() { $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags('Words'); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) -withAttributes([]); ?> @endcomponentClass Words", trim($result)); + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', []) +withAttributes([]); ?> @endComponentClass##END-COMPONENT-CLASS##Words", trim($result)); } public function testSelfClosingComponentsCanHaveAttachedWord() { $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags('Words'); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes([]); ?>\n". -'@endcomponentClass Words', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##Words', trim($result)); } public function testSelfClosingComponentsCanBeCompiledWithBoundData() { $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(''); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => \$title]) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', ['title' => \$title]) withAttributes(['class' => 'bar']); ?>\n". -'@endcomponentClass', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##', trim($result)); } public function testPairedComponentTags() @@ -204,9 +204,9 @@ public function testPairedComponentTags() $result = $this->compiler(['alert' => TestAlertComponent::class])->compileTags(' '); - $this->assertSame("@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestAlertComponent', 'alert', []) withAttributes([]); ?> - @endcomponentClass", trim($result)); + @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } public function testClasslessComponents() @@ -220,9 +220,9 @@ public function testClasslessComponents() $result = $this->compiler()->compileTags(''); - $this->assertSame("@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']]) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']]) withAttributes(['name' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('Taylor'),'age' => 31,'wire:model' => 'foo']); ?>\n". -'@endcomponentClass', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##', trim($result)); } public function testPackagesClasslessComponents() @@ -236,9 +236,9 @@ public function testPackagesClasslessComponents() $result = $this->compiler()->compileTags(''); - $this->assertSame("@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']]) + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']]) withAttributes(['name' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute('Taylor'),'age' => 31,'wire:model' => 'foo']); ?>\n". -'@endcomponentClass', trim($result)); +'@endComponentClass##END-COMPONENT-CLASS##', trim($result)); } public function testAttributeSanitization() From 7d56eff3136a1d22e3ed3a0bea0dd5ea2867812e Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Thu, 14 Jan 2021 15:47:18 +0100 Subject: [PATCH 067/443] add default parameter to throw_if / throw_unless (#35890) --- src/Illuminate/Support/helpers.php | 16 ++++++-- tests/Support/SupportHelpersTest.php | 56 +++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index f44371bb469e..bf110f8918b4 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -277,10 +277,14 @@ function tap($value, $callback = null) * * @throws \Throwable */ - function throw_if($condition, $exception, ...$parameters) + function throw_if($condition, $exception = 'RuntimeException', ...$parameters) { if ($condition) { - throw (is_string($exception) ? new $exception(...$parameters) : $exception); + if (is_string($exception) && class_exists($exception)) { + $exception = new $exception(...$parameters); + } + + throw is_string($exception) ? new RuntimeException($exception) : $exception; } return $condition; @@ -298,10 +302,14 @@ function throw_if($condition, $exception, ...$parameters) * * @throws \Throwable */ - function throw_unless($condition, $exception, ...$parameters) + function throw_unless($condition, $exception = 'RuntimeException', ...$parameters) { if (! $condition) { - throw (is_string($exception) ? new $exception(...$parameters) : $exception); + if (is_string($exception) && class_exists($exception)) { + $exception = new $exception(...$parameters); + } + + throw is_string($exception) ? new RuntimeException($exception) : $exception; } return $condition; diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index bb3e5ead59ce..af7de6b40f56 100755 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Env; use Illuminate\Support\Optional; +use LogicException; use Mockery as m; use PHPUnit\Framework\TestCase; use RuntimeException; @@ -362,10 +363,63 @@ public function testTap() } public function testThrow() + { + $this->expectException(LogicException::class); + + throw_if(true, new LogicException); + } + + public function testThrowDefaultException() + { + $this->expectException(RuntimeException::class); + + throw_if(true); + } + + public function testThrowExceptionWithMessage() { $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('test'); + + throw_if(true, 'test'); + } + + public function testThrowExceptionAsStringWithMessage() + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('test'); + + throw_if(true, LogicException::class, 'test'); + } + + public function testThrowUnless() + { + $this->expectException(LogicException::class); + + throw_unless(false, new LogicException); + } + + public function testThrowUnlessDefaultException() + { + $this->expectException(RuntimeException::class); + + throw_unless(false); + } + + public function testThrowUnlessExceptionWithMessage() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('test'); + + throw_unless(false, 'test'); + } + + public function testThrowUnlessExceptionAsStringWithMessage() + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('test'); - throw_if(true, new RuntimeException); + throw_unless(false, LogicException::class, 'test'); } public function testThrowReturnIfNotThrown() From 212d7f41c6f26fa842c45b78f775dbac4320788a Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 14 Jan 2021 17:08:36 +0100 Subject: [PATCH 068/443] Re-enable query builder tests (#35894) --- tests/Database/DatabaseQueryBuilderTest.php | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 407b312ee5bf..f7d20c532223 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -305,20 +305,20 @@ public function testWheresWithArrayValue() $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); $this->assertEquals([0 => 12], $builder->getBindings()); - // $builder = $this->getBuilder(); - // $builder->select('*')->from('users')->where('id', '=', [12, 30]); - // $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); - // $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); - - // $builder = $this->getBuilder(); - // $builder->select('*')->from('users')->where('id', '!=', [12, 30]); - // $this->assertSame('select * from "users" where "id" != ?', $builder->toSql()); - // $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); - - // $builder = $this->getBuilder(); - // $builder->select('*')->from('users')->where('id', '<>', [12, 30]); - // $this->assertSame('select * from "users" where "id" <> ?', $builder->toSql()); - // $this->assertEquals([0 => 12, 1 => 30], $builder->getBindings()); + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('id', '=', [12, 30]); + $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); + $this->assertEquals([0 => 12], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('id', '!=', [12, 30]); + $this->assertSame('select * from "users" where "id" != ?', $builder->toSql()); + $this->assertEquals([0 => 12], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('id', '<>', [12, 30]); + $this->assertSame('select * from "users" where "id" <> ?', $builder->toSql()); + $this->assertEquals([0 => 12], $builder->getBindings()); } public function testMySqlWrappingProtectsQuotationMarks() From 29c7dae9b32af2abffa7489f4758fd67905683c3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 14 Jan 2021 15:27:12 -0600 Subject: [PATCH 069/443] rename file --- src/Illuminate/Database/Concerns/BuildsQueries.php | 10 +++++----- ...FoundException.php => RecordsNotFoundException.php} | 2 +- tests/Integration/Database/QueryBuilderTest.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) rename src/Illuminate/Database/{NoRecordsFoundException.php => RecordsNotFoundException.php} (56%) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 9aa590654b83..38b04e8bcdcb 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -4,7 +4,7 @@ use Illuminate\Container\Container; use Illuminate\Database\MultipleRecordsFoundException; -use Illuminate\Database\NoRecordsFoundException; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; @@ -150,12 +150,12 @@ public function first($columns = ['*']) } /** - * Execute the query and get the first result if it's the sole. + * Execute the query and get the first result if it's the sole matching record. * * @param array|string $columns * @return \Illuminate\Database\Eloquent\Model|object|static|null * - * @throws \Illuminate\Database\NoRecordsFoundException + * @throws \Illuminate\Database\RecordsNotFoundException * @throws \Illuminate\Database\MultipleRecordsFoundException */ public function sole($columns = ['*']) @@ -163,11 +163,11 @@ public function sole($columns = ['*']) $result = $this->take(2)->get($columns); if ($result->isEmpty()) { - throw new NoRecordsFoundException(); + throw new RecordsNotFoundException; } if ($result->count() > 1) { - throw new MultipleRecordsFoundException(); + throw new MultipleRecordsFoundException; } return $result->first(); diff --git a/src/Illuminate/Database/NoRecordsFoundException.php b/src/Illuminate/Database/RecordsNotFoundException.php similarity index 56% rename from src/Illuminate/Database/NoRecordsFoundException.php rename to src/Illuminate/Database/RecordsNotFoundException.php index b45266c8e9bf..3e0d9557581d 100755 --- a/src/Illuminate/Database/NoRecordsFoundException.php +++ b/src/Illuminate/Database/RecordsNotFoundException.php @@ -4,7 +4,7 @@ use RuntimeException; -class NoRecordsFoundException extends RuntimeException +class RecordsNotFoundException extends RuntimeException { // } diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 0c7df7bbb124..675f30561fae 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -4,7 +4,7 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\MultipleRecordsFoundException; -use Illuminate\Database\NoRecordsFoundException; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; @@ -52,7 +52,7 @@ public function testSoleFailsForMultipleRecords() public function testSoleFailsIfNoRecords() { - $this->expectException(NoRecordsFoundException::class); + $this->expectException(RecordsNotFoundException::class); DB::table('posts')->where('title', 'Baz Post')->sole(); } From f3d4dcb21dc66824611fdde95c8075b694825bf5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 15 Jan 2021 07:23:12 -0600 Subject: [PATCH 070/443] fix serialization of rate limited middleware --- .../Queue/Middleware/RateLimited.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Illuminate/Queue/Middleware/RateLimited.php b/src/Illuminate/Queue/Middleware/RateLimited.php index efb0f60841f2..f7a8d6c08105 100644 --- a/src/Illuminate/Queue/Middleware/RateLimited.php +++ b/src/Illuminate/Queue/Middleware/RateLimited.php @@ -120,4 +120,31 @@ protected function getTimeUntilNextRetry($key) { return $this->limiter->availableIn($key) + 3; } + + /** + * Prepare the object for serialization. + * + * @return array + */ + public function __serialize() + { + return [ + 'limiterName' => $this->limiterName, + 'shouldRelease' => $this->shouldRelease, + ]; + } + + /** + * Prepare the object after unserialization. + * + * @param array $data + * @return void + */ + public function __unserialize(array $data) + { + $this->limiter = Container::getInstance()->make(RateLimiter::class); + + $this->limitedName = $data['limiterName']; + $this->shouldRelease = $data['shouldRelease']; + } } From ef7171e679497685131392cb1b200955092b053c Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 15 Jan 2021 21:31:43 +0800 Subject: [PATCH 071/443] Internally don't report exceptions from DB::where()->sole() (#35908) Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Foundation/Exceptions/Handler.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 924046b8b340..c73130cb137e 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -11,6 +11,8 @@ use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract; use Illuminate\Contracts\Support\Responsable; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Database\MultipleRecordsFoundException; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; @@ -89,6 +91,8 @@ class Handler implements ExceptionHandlerContract HttpException::class, HttpResponseException::class, ModelNotFoundException::class, + MultipleRecordsFoundException::class, + RecordsNotFoundException::class, SuspiciousOperationException::class, TokenMismatchException::class, ValidationException::class, From ab79d0cc600b44a2a6e89a7a0ca521732b749838 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Fri, 15 Jan 2021 10:33:06 -0300 Subject: [PATCH 072/443] [8.x] Throw ModelNotFoundException for sole in Eloquent (#35902) * throw ModelNotFoundException for sole in Eloquent * extend from RecordsNotFoundException --- src/Illuminate/Database/Eloquent/Builder.php | 24 +++++++++++- .../Eloquent/ModelNotFoundException.php | 4 +- .../Database/EloquentWhereTest.php | 39 +++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index d3f1f96a8c13..aa579259c1d5 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Query\Builder as QueryBuilder; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Pagination\Paginator; use Illuminate\Support\Arr; use Illuminate\Support\Str; @@ -25,7 +26,10 @@ */ class Builder { - use BuildsQueries, Concerns\QueriesRelationships, ExplainsQueries, ForwardsCalls; + use Concerns\QueriesRelationships, ExplainsQueries, ForwardsCalls; + use BuildsQueries { + sole as baseSole; + } /** * The base query builder instance. @@ -504,6 +508,24 @@ public function firstOr($columns = ['*'], Closure $callback = null) return $callback(); } + /** + * Execute the query and get the first result if it's the sole matching record. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Model + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + */ + public function sole($columns = ['*']) + { + try { + return $this->baseSole($columns); + } catch (RecordsNotFoundException $exception) { + throw new ModelNotFoundException($this->model); + } + } + /** * Get a single column's value from the first result of a query. * diff --git a/src/Illuminate/Database/Eloquent/ModelNotFoundException.php b/src/Illuminate/Database/Eloquent/ModelNotFoundException.php index 2795b934bb74..c35598bdbf46 100755 --- a/src/Illuminate/Database/Eloquent/ModelNotFoundException.php +++ b/src/Illuminate/Database/Eloquent/ModelNotFoundException.php @@ -2,10 +2,10 @@ namespace Illuminate\Database\Eloquent; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Support\Arr; -use RuntimeException; -class ModelNotFoundException extends RuntimeException +class ModelNotFoundException extends RecordsNotFoundException { /** * Name of the affected Eloquent model. diff --git a/tests/Integration/Database/EloquentWhereTest.php b/tests/Integration/Database/EloquentWhereTest.php index c7fcc470e6f4..a400d7f76305 100644 --- a/tests/Integration/Database/EloquentWhereTest.php +++ b/tests/Integration/Database/EloquentWhereTest.php @@ -3,6 +3,8 @@ namespace Illuminate\Tests\Integration\Database; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Database\MultipleRecordsFoundException; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; @@ -91,6 +93,43 @@ public function testFirstWhere() UserWhereTest::firstWhere(['name' => 'wrong-name', 'email' => 'test-email1'], null, null, 'or')) ); } + + public function testSole() + { + $expected = UserWhereTest::create([ + 'name' => 'test-name', + 'email' => 'test-email', + 'address' => 'test-address', + ]); + + $this->assertTrue($expected->is(UserWhereTest::where('name', 'test-name')->sole())); + } + + public function testSoleFailsForMultipleRecords() + { + UserWhereTest::create([ + 'name' => 'test-name', + 'email' => 'test-email', + 'address' => 'test-address', + ]); + + UserWhereTest::create([ + 'name' => 'test-name', + 'email' => 'other-email', + 'address' => 'other-address', + ]); + + $this->expectException(MultipleRecordsFoundException::class); + + UserWhereTest::where('name', 'test-name')->sole(); + } + + public function testSoleFailsIfNoRecords() + { + $this->expectException(ModelNotFoundException::class); + + UserWhereTest::where('name', 'test-name')->sole(); + } } class UserWhereTest extends Model From e1d3158d162c35d4b8e7b65840f9ac347199be63 Mon Sep 17 00:00:00 2001 From: Mo Khosh Date: Fri, 15 Jan 2021 17:21:46 +0330 Subject: [PATCH 073/443] [8.x] Pass $key to closure in Collection and LazyCollection's reduce method as well (#35878) * add reduce with keys to collections * add reduce with keys to lazy collections * add test for reduce with keys * fix style * merge reduceWithKeys into the existing reduce method * remove reduce and reduceWithKeys from Collection * remove reduce and reduceWithKeys from LazyCollection * add reduce and reduceWithKeys to EnumeratesValues * add test for reduce with keys and reduceWithKeys --- src/Illuminate/Collections/Collection.php | 30 ---------------- src/Illuminate/Collections/LazyCollection.php | 36 ------------------- .../Collections/Traits/EnumeratesValues.php | 36 +++++++++++++++++++ tests/Support/SupportCollectionTest.php | 8 +++++ 4 files changed, 44 insertions(+), 66 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index f708a3ee28bd..e4549d03ed11 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -872,36 +872,6 @@ public function random($number = null) return new static(Arr::random($this->items, $number)); } - /** - * Reduce the collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduce(callable $callback, $initial = null) - { - return array_reduce($this->items, $callback, $initial); - } - - /** - * Reduce an associative collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduceWithKeys(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this->items as $key => $value) { - $result = $callback($result, $value, $key); - } - - return $result; - } - /** * Replace the collection items with the given items. * diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index c7995fb27e1b..650213133ced 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -827,42 +827,6 @@ public function random($number = null) return is_null($number) ? $result : new static($result); } - /** - * Reduce the collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduce(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this as $value) { - $result = $callback($result, $value); - } - - return $result; - } - - /** - * Reduce an associative collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduceWithKeys(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this as $key => $value) { - $result = $callback($result, $value, $key); - } - - return $result; - } - /** * Replace the collection items with the given items. * diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 3355a9b2da29..0c0c7ce3c3ab 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -716,6 +716,42 @@ public function tap(callable $callback) return $this; } + /** + * Reduce the collection to a single value. + * + * @param callable $callback + * @param mixed $initial + * @return mixed + */ + public function reduce(callable $callback, $initial = null) + { + $result = $initial; + + foreach ($this as $key => $value) { + $result = $callback($result, $value, $key); + } + + return $result; + } + + /** + * Reduce an associative collection to a single value. + * + * @param callable $callback + * @param mixed $initial + * @return mixed + */ + public function reduceWithKeys(callable $callback, $initial = null) + { + $result = $initial; + + foreach ($this as $key => $value) { + $result = $callback($result, $value, $key); + } + + return $result; + } + /** * Create a collection of all elements that do not pass a given truth test. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index b622884fe6c1..1902589e181e 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3590,6 +3590,14 @@ public function testReduce($collection) $this->assertEquals(6, $data->reduce(function ($carry, $element) { return $carry += $element; })); + + $data = new $collection([ + 'foo' => 'bar', + 'baz' => 'qux', + ]); + $this->assertEquals('foobarbazqux', $data->reduce(function ($carry, $element, $key) { + return $carry .= $key.$element; + })); } /** From f646f8a8c594e83217079763b8ac20c260828da4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 15 Jan 2021 07:52:20 -0600 Subject: [PATCH 074/443] Apply fixes from StyleCI (#35909) --- tests/Support/SupportCollectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 1902589e181e..2dfd503656ca 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3590,7 +3590,7 @@ public function testReduce($collection) $this->assertEquals(6, $data->reduce(function ($carry, $element) { return $carry += $element; })); - + $data = new $collection([ 'foo' => 'bar', 'baz' => 'qux', From 49f9db00a754517f07d365ee5b0806df82e37029 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 15 Jan 2021 09:35:47 -0600 Subject: [PATCH 075/443] version --- 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 97a41bb7711c..f58255d51049 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.11'; + const VERSION = '6.20.12'; /** * The base path for the Laravel installation. From 28481951106e75cf8c5a8b24100059fa327df1ef Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 15 Jan 2021 09:38:30 -0600 Subject: [PATCH 076/443] version --- 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 34523e48057e..1dc26d3e3d16 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '7.30.2'; + const VERSION = '7.30.3'; /** * The base path for the Laravel installation. From 7132ff5d0307828173296b31953d195b517eb789 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Fri, 15 Jan 2021 18:55:55 -0300 Subject: [PATCH 077/443] [8.x] Handle `->sole()` exceptions (#35912) * handle sole exceptions * do not handle MultipleRecordsFoundException --- .../Foundation/Exceptions/Handler.php | 2 ++ .../FoundationExceptionsHandlerTest.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index c73130cb137e..33fbccc5e7e1 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -373,6 +373,8 @@ protected function prepareException(Throwable $e) $e = new HttpException(419, $e->getMessage(), $e); } elseif ($e instanceof SuspiciousOperationException) { $e = new NotFoundHttpException('Bad hostname provided.', $e); + } elseif ($e instanceof RecordsNotFoundException) { + $e = new NotFoundHttpException('Not found.', $e); } return $e; diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index 887de48f7ddd..f7175dc58db5 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -8,6 +8,7 @@ use Illuminate\Contracts\Routing\ResponseFactory as ResponseFactoryContract; use Illuminate\Contracts\Support\Responsable; use Illuminate\Contracts\View\Factory; +use Illuminate\Database\RecordsNotFoundException; use Illuminate\Foundation\Exceptions\Handler; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -235,6 +236,23 @@ public function testSuspiciousOperationReturns404WithoutReporting() $this->handler->report(new SuspiciousOperationException('Invalid method override "__CONSTRUCT"')); } + + public function testRecordsNotFoundReturns404WithoutReporting() + { + $this->config->shouldReceive('get')->with('app.debug', null)->once()->andReturn(true); + $this->request->shouldReceive('expectsJson')->once()->andReturn(true); + + $response = $this->handler->render($this->request, new RecordsNotFoundException()); + + $this->assertEquals(404, $response->getStatusCode()); + $this->assertStringContainsString('"message": "Not found."', $response->getContent()); + + $logger = m::mock(LoggerInterface::class); + $this->container->instance(LoggerInterface::class, $logger); + $logger->shouldNotReceive('error'); + + $this->handler->report(new RecordsNotFoundException()); + } } class CustomException extends Exception From 0076fc98a4aea00997764552bee17a86531cf605 Mon Sep 17 00:00:00 2001 From: Lupacescu Eduard Date: Fri, 15 Jan 2021 23:56:08 +0200 Subject: [PATCH 078/443] Adding PHPDoc 'afterCommit' on DB Facade. (#35911) --- src/Illuminate/Support/Facades/DB.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 7986e3cf863c..47c3ab543fa3 100755 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -22,6 +22,7 @@ * @method static string getDefaultConnection() * @method static void beginTransaction() * @method static void commit() + * @method static void afterCommit(\Closure $callback) * @method static void listen(\Closure $callback) * @method static void rollBack(int $toLevel = null) * @method static void setDefaultConnection(string $name) From 8465ecfc69ff72e4eb25fc9ff6f7a13746c0c060 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Sat, 16 Jan 2021 11:54:40 -0500 Subject: [PATCH 079/443] Use View contract rather than implementation (#35920) --- src/Illuminate/View/Concerns/ManagesComponents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/View/Concerns/ManagesComponents.php b/src/Illuminate/View/Concerns/ManagesComponents.php index 574e91d6213b..81b2bdf6cbaf 100644 --- a/src/Illuminate/View/Concerns/ManagesComponents.php +++ b/src/Illuminate/View/Concerns/ManagesComponents.php @@ -4,9 +4,9 @@ use Closure; use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Contracts\View\View; use Illuminate\Support\Arr; use Illuminate\Support\HtmlString; -use Illuminate\View\View; use InvalidArgumentException; trait ManagesComponents From c90605d610c57c3738b4aa49bf08da82c75eb7b9 Mon Sep 17 00:00:00 2001 From: Chuangbo Li Date: Sun, 17 Jan 2021 00:54:56 +0800 Subject: [PATCH 080/443] fix typo (#35916) --- src/Illuminate/Queue/Middleware/RateLimited.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Middleware/RateLimited.php b/src/Illuminate/Queue/Middleware/RateLimited.php index f7a8d6c08105..4d2d61c5e4e4 100644 --- a/src/Illuminate/Queue/Middleware/RateLimited.php +++ b/src/Illuminate/Queue/Middleware/RateLimited.php @@ -144,7 +144,7 @@ public function __unserialize(array $data) { $this->limiter = Container::getInstance()->make(RateLimiter::class); - $this->limitedName = $data['limiterName']; + $this->limiterName = $data['limiterName']; $this->shouldRelease = $data['shouldRelease']; } } From 5e40b0e87f08d40d7de2922374ea9dc2d96c0c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20N=C3=BCrnberger?= Date: Sun, 17 Jan 2021 21:14:47 +0100 Subject: [PATCH 081/443] use expected (#35926) --- tests/Integration/Database/QueryBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 675f30561fae..66a65cbdaa43 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -36,7 +36,7 @@ public function testSole() { $expected = ['id' => '1', 'title' => 'Foo Post']; - $this->assertEquals(1, DB::table('posts')->where('title', 'Foo Post')->sole()->id); + $this->assertSame($expected, (array) DB::table('posts')->where('title', 'Foo Post')->select('id', 'title')->sole()); } public function testSoleFailsForMultipleRecords() From 74159770942b7660488e8c213d9ad7ffd6bfba2c Mon Sep 17 00:00:00 2001 From: Mikey O'Toole Date: Mon, 18 Jan 2021 15:27:44 +0000 Subject: [PATCH 082/443] Add validation support for TeamSpeak3 URI scheme (#35933) This PR adds support for `ts3server` URI validation to the URL validator's list of protocols. https://gaming.stackexchange.com/questions/51926/how-can-i-directly-link-to-a-teamspeak-server-on-my-website --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index c0c5411c1391..4efd422cd711 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1776,7 +1776,7 @@ public function validateUrl($attribute, $value) * (c) Fabien Potencier http://symfony.com */ $pattern = '~^ - (aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|tg|things|thismessage|tip|tn3270|tool|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s):// # protocol + (aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|tg|things|thismessage|tip|tn3270|tool|ts3server|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s):// # protocol (((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+)@)? # basic auth ( ([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name From 1a146d2c170390def0b017146b21c9f8c21691ce Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 19 Jan 2021 14:24:34 +0100 Subject: [PATCH 083/443] Fix empty email with attachments (#35941) --- src/Illuminate/Mail/Mailer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index 2d310a3a00a0..7a11e58f68fc 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -325,7 +325,7 @@ protected function parseView($view) protected function addContent($message, $view, $plain, $raw, $data) { if (isset($view)) { - $message->setBody($this->renderView($view, $data), 'text/html'); + $message->setBody($this->renderView($view, $data) ?: ' ', 'text/html'); } if (isset($plain)) { From eeaf5f61446a62e93dff13d2c098d39bba8e6086 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 19 Jan 2021 07:40:52 -0600 Subject: [PATCH 084/443] version --- 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 ec1deae44b68..cb0724131fbc 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.22.1'; + const VERSION = '8.23.0'; /** * The base path for the Laravel installation. From 12ed06da14e3fe4257cb1ece91c2d3439cc2d34b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 19 Jan 2021 07:41:17 -0600 Subject: [PATCH 085/443] version --- 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 f58255d51049..30e8e7c358b1 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.12'; + const VERSION = '6.20.13'; /** * The base path for the Laravel installation. From cc526911b5dc830a39a4039828b871dbeca36ea4 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 19:46:10 +0200 Subject: [PATCH 086/443] [6.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 3ab00165cccc..570c2d5b9317 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.10...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.11...6.x) + + +## [v6.20.11 (2021-01-19)](https://github.com/laravel/framework/compare/v6.20.10...v6.20.11) + +### Fixed +- Limit expected bindings ([#35865](https://github.com/laravel/framework/pull/35865)) ## [v6.20.10 (2021-01-12)](https://github.com/laravel/framework/compare/v6.20.9...v6.20.10) From 19aeb79014b05b76f9e5e016a24f8bd78b59d209 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 19:49:41 +0200 Subject: [PATCH 087/443] [6.x] update changelog --- CHANGELOG-6.x.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 570c2d5b9317..ae2f901c392d 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -3,7 +3,7 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v6.20.11...6.x) -## [v6.20.11 (2021-01-19)](https://github.com/laravel/framework/compare/v6.20.10...v6.20.11) +## [v6.20.11 (2021-01-13)](https://github.com/laravel/framework/compare/v6.20.10...v6.20.11) ### Fixed - Limit expected bindings ([#35865](https://github.com/laravel/framework/pull/35865)) From 45c230e5db764c2cdfd3554131c3d3fc08fd4812 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:02:19 +0200 Subject: [PATCH 088/443] [7.x] update changelog --- CHANGELOG-7.x.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index 2a0534809019..bb6656470920 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,19 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.30.1...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.30.2...7.x) + + +## [v7.30.2 (2021-01-13)](https://github.com/laravel/framework/compare/v7.30.1...v7.30.2) + +### Added +- Added strings to `DetectsLostConnections` ([#35752](https://github.com/laravel/framework/pull/35752)) + +### Fixed +- Fixed error from missing null check on PHP 8 ([#35797](https://github.com/laravel/framework/pull/35797)) +- Limit expected bindings ([#35865](https://github.com/laravel/framework/pull/35865)) + +### Changed +- Retry connection if DNS lookup fails ([#35790](https://github.com/laravel/framework/pull/35790)) ## [v7.30.1 (2020-12-22)](https://github.com/laravel/framework/compare/v7.30.0...v7.30.1) From 80210553c1f88e7ca4b279364c003970b2824076 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:07:06 +0200 Subject: [PATCH 089/443] [8.x] update changelog --- CHANGELOG-8.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 6879551e0a1e..e049474c09b3 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,12 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.22.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.22.1...8.x) + + +## [v8.22.1 (2021-01-13)](https://github.com/laravel/framework/compare/v8.22.0...v8.22.1) + +### Fixed +- Limit expected bindings ([#35865](https://github.com/laravel/framework/pull/35865)) ## [v8.22.0 (2021-01-12)](https://github.com/laravel/framework/compare/v8.21.0...v8.22.0) From e4be180ad35a378b8e59e4c0236567995851a3f8 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:10:30 +0200 Subject: [PATCH 090/443] [6.x] update changelog --- CHANGELOG-6.x.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index ae2f901c392d..00a6d2154eea 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,9 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.11...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.12...6.x) + + +## [v6.20.12 (2021-01-13)](https://github.com/laravel/framework/compare/v6.20.11...v6.20.12) ## [v6.20.11 (2021-01-13)](https://github.com/laravel/framework/compare/v6.20.10...v6.20.11) From 57d148dc399ca192e59f0712875194f57ec768f5 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:13:17 +0200 Subject: [PATCH 091/443] [7.x] update changelog --- CHANGELOG-7.x.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index bb6656470920..36d7fe5e06fc 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,9 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.30.2...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.30.3...7.x) + + +## [v7.30.3 (2021-01-15)](https://github.com/laravel/framework/compare/v7.30.2...v7.30.3) ## [v7.30.2 (2021-01-13)](https://github.com/laravel/framework/compare/v7.30.1...v7.30.2) From f0dc53f3641b51373cc06e5ca3bcf8549c8186dd Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:16:32 +0200 Subject: [PATCH 092/443] [6.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 00a6d2154eea..42350000b97c 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.12...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.13...6.x) + + +## [v6.20.13 (2021-01-19)](https://github.com/laravel/framework/compare/v6.20.12...v6.20.13) + +### Fixed +- Fixed empty html mail ([#35941](https://github.com/laravel/framework/pull/35941)) ## [v6.20.12 (2021-01-13)](https://github.com/laravel/framework/compare/v6.20.11...v6.20.12) From e6b4974a323cfebe915324d192e5c296c1fa13a4 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:41:58 +0200 Subject: [PATCH 093/443] [8.x] update changelog --- CHANGELOG-8.x.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index e049474c09b3..bbacb405f40f 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,22 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.22.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.23.0...8.x) + + +## [v8.23.0 (2021-01-19)](https://github.com/laravel/framework/compare/v8.22.1...v8.23.0) + +### Added +- Added `Illuminate\Database\Concerns\BuildsQueries::sole()` ([#35869](https://github.com/laravel/framework/pull/35869), [29c7dae](https://github.com/laravel/framework/commit/29c7dae9b32af2abffa7489f4758fd67905683c3), [#35908](https://github.com/laravel/framework/pull/35908), [#35902](https://github.com/laravel/framework/pull/35902), [#35912](https://github.com/laravel/framework/pull/35912)) +- Added default parameter to throw_if / throw_unless ([#35890](https://github.com/laravel/framework/pull/35890)) +- Added validation support for TeamSpeak3 URI scheme ([#35933](https://github.com/laravel/framework/pull/35933)) + +### Fixed +- Fixed extra space on blade class components that are inline ([#35874](https://github.com/laravel/framework/pull/35874)) +- Fixed serialization of rate limited middleware ([f3d4dcb](https://github.com/laravel/framework/commit/f3d4dcb21dc66824611fdde95c8075b694825bf5), [#35916](https://github.com/laravel/framework/pull/35916)) + +### Changed +- Allow a specific seeder to be used in tests in `Illuminate\Foundation\Testing\RefreshDatabase::migrateFreshUsing()` ([#35864](https://github.com/laravel/framework/pull/35864)) +- Pass $key to closure in Collection and LazyCollection's reduce method as well ([#35878](https://github.com/laravel/framework/pull/35878)) ## [v8.22.1 (2021-01-13)](https://github.com/laravel/framework/compare/v8.22.0...v8.22.1) From 208c3976f186dcdfa0a434f4092bae7d32928465 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Jan 2021 20:44:27 +0200 Subject: [PATCH 094/443] [8.x] update changelog --- CHANGELOG-8.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index bbacb405f40f..f1e61cd5215f 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,12 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.23.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.23.1...8.x) + + +## [v8.23.1 (2021-01-19)](https://github.com/laravel/framework/compare/v8.23.0...v8.23.1) + +### Fixed +- Fixed empty html mail ([#35941](https://github.com/laravel/framework/pull/35941)) ## [v8.23.0 (2021-01-19)](https://github.com/laravel/framework/compare/v8.22.1...v8.23.0) From d08fd806337d991ea14e578a9c85b2f6d4ae990e Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 20 Jan 2021 13:50:36 +0000 Subject: [PATCH 095/443] Fixed type error (#35956) --- src/Illuminate/Http/Concerns/InteractsWithContentTypes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php b/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php index be760a2619d9..25d6ec1e9986 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php +++ b/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php @@ -31,7 +31,7 @@ public static function matchesType($actual, $type) */ public function isJson() { - return Str::contains($this->header('CONTENT_TYPE'), ['/json', '+json']); + return Str::contains($this->header('CONTENT_TYPE') ?? '', ['/json', '+json']); } /** From fa61b374655f465793feb29a49fbeec9c7878081 Mon Sep 17 00:00:00 2001 From: Andrew Nagy Date: Wed, 20 Jan 2021 06:16:15 -0800 Subject: [PATCH 096/443] Fixes #35947 (#35950) This fixes #35947. Since collections can deal with objects then the method sortByMany taken from Arr should be able to deal with objects as well --- 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 e4549d03ed11..beaac46fe280 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1168,7 +1168,7 @@ protected function sortByMany(array $comparisons = []) if (is_callable($prop)) { $result = $prop($a, $b); } else { - $values = [Arr::get($a, $prop), Arr::get($b, $prop)]; + $values = [data_get($a, $prop), data_get($b, $prop)]; if (! $ascending) { $values = array_reverse($values); From 9f0180f154fe14cc6d4a2a00b1fc25a684469152 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Wed, 20 Jan 2021 15:18:13 +0100 Subject: [PATCH 097/443] Change cache lock block method return to mixed (#35961) --- src/Illuminate/Cache/Lock.php | 2 +- src/Illuminate/Contracts/Cache/Lock.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 271cba50fc58..eb035161ba87 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -105,7 +105,7 @@ public function get($callback = null) * * @param int $seconds * @param callable|null $callback - * @return bool + * @return mixed * * @throws \Illuminate\Contracts\Cache\LockTimeoutException */ diff --git a/src/Illuminate/Contracts/Cache/Lock.php b/src/Illuminate/Contracts/Cache/Lock.php index 7f01b1be3f33..03f633a07a21 100644 --- a/src/Illuminate/Contracts/Cache/Lock.php +++ b/src/Illuminate/Contracts/Cache/Lock.php @@ -17,7 +17,7 @@ public function get($callback = null); * * @param int $seconds * @param callable|null $callback - * @return bool + * @return mixed */ public function block($seconds, $callback = null); From 8eaec037421aa9f3860da9d339986448b4c884eb Mon Sep 17 00:00:00 2001 From: vdauchy <26772554+vdauchy@users.noreply.github.com> Date: Tue, 19 Jan 2021 14:28:18 -0500 Subject: [PATCH 098/443] Add JobQueued event (Follows: https://github.com/laravel/framework/pull/32894) --- src/Illuminate/Queue/Events/JobQueued.php | 29 ++++++++ src/Illuminate/Queue/Queue.php | 25 ++++++- tests/Queue/QueueBeanstalkdQueueTest.php | 65 ++++++++++++------ tests/Queue/QueueDatabaseQueueUnitTest.php | 7 ++ tests/Queue/QueueRedisQueueTest.php | 11 +++ tests/Queue/QueueSqsQueueTest.php | 6 ++ tests/Queue/RedisQueueIntegrationTest.php | 78 +++++++++++++++++++--- 7 files changed, 191 insertions(+), 30 deletions(-) create mode 100644 src/Illuminate/Queue/Events/JobQueued.php diff --git a/src/Illuminate/Queue/Events/JobQueued.php b/src/Illuminate/Queue/Events/JobQueued.php new file mode 100644 index 000000000000..4568cd922fb0 --- /dev/null +++ b/src/Illuminate/Queue/Events/JobQueued.php @@ -0,0 +1,29 @@ +jobId = $jobId; + $this->job = $job; + } +} diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index b22ed51cd446..bfe8baec8507 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -7,6 +7,7 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Queue\ShouldBeEncrypted; +use Illuminate\Queue\Events\JobQueued; use Illuminate\Support\Arr; use Illuminate\Support\InteractsWithTime; use Illuminate\Support\Str; @@ -284,13 +285,17 @@ protected function enqueueUsing($job, $payload, $queue, $delay, $callback) if ($this->shouldDispatchAfterCommit($job) && $this->container->bound('db.transactions')) { return $this->container->make('db.transactions')->addCallback( - function () use ($payload, $queue, $delay, $callback) { - return $callback($payload, $queue, $delay); + function () use ($payload, $queue, $delay, $callback, $job) { + return tap($callback($payload, $queue, $delay), function ($jobId) use ($job) { + $this->raiseJobQueuedEvent($jobId, $job); + }); } ); } - return $callback($payload, $queue, $delay); + return tap($callback($payload, $queue, $delay), function ($jobId) use ($job) { + $this->raiseJobQueuedEvent($jobId, $job); + }); } /** @@ -345,4 +350,18 @@ public function setContainer(Container $container) { $this->container = $container; } + + /** + * Raise the job queued event. + * + * @param string|int|null $jobId + * @param \Closure|string|object $job + * @return void + */ + protected function raiseJobQueuedEvent($jobId, $job) + { + if ($this->container->bound('events')) { + $this->container['events']->dispatch(new JobQueued($jobId, $job)); + } + } } diff --git a/tests/Queue/QueueBeanstalkdQueueTest.php b/tests/Queue/QueueBeanstalkdQueueTest.php index 7134917a2369..534a16141381 100755 --- a/tests/Queue/QueueBeanstalkdQueueTest.php +++ b/tests/Queue/QueueBeanstalkdQueueTest.php @@ -13,6 +13,16 @@ class QueueBeanstalkdQueueTest extends TestCase { + /** + * @var BeanstalkdQueue + */ + private $queue; + + /** + * @var Container|m\LegacyMockInterface|m\MockInterface + */ + private $container; + protected function tearDown(): void { m::close(); @@ -26,14 +36,16 @@ public function testPushProperlyPushesJobOntoBeanstalkd() return $uuid; }); - $queue = new BeanstalkdQueue(m::mock(Pheanstalk::class), 'default', 60); - $pheanstalk = $queue->getPheanstalk(); + $this->setQueue('default', 60); + $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with('stack')->andReturn($pheanstalk); $pheanstalk->shouldReceive('useTube')->once()->with('default')->andReturn($pheanstalk); $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), 1024, 0, 60); - $queue->push('foo', ['data'], 'stack'); - $queue->push('foo', ['data']); + $this->queue->push('foo', ['data'], 'stack'); + $this->queue->push('foo', ['data']); + + $this->container->shouldHaveReceived('bound')->with('events')->times(2); Str::createUuidsNormally(); } @@ -46,53 +58,68 @@ public function testDelayedPushProperlyPushesJobOntoBeanstalkd() return $uuid; }); - $queue = new BeanstalkdQueue(m::mock(Pheanstalk::class), 'default', 60); - $pheanstalk = $queue->getPheanstalk(); + $this->setQueue('default', 60); + $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with('stack')->andReturn($pheanstalk); $pheanstalk->shouldReceive('useTube')->once()->with('default')->andReturn($pheanstalk); $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['uuid' => $uuid, 'displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'maxExceptions' => null, 'backoff' => null, 'timeout' => null, 'data' => ['data']]), Pheanstalk::DEFAULT_PRIORITY, 5, Pheanstalk::DEFAULT_TTR); - $queue->later(5, 'foo', ['data'], 'stack'); - $queue->later(5, 'foo', ['data']); + $this->queue->later(5, 'foo', ['data'], 'stack'); + $this->queue->later(5, 'foo', ['data']); + + $this->container->shouldHaveReceived('bound')->with('events')->times(2); Str::createUuidsNormally(); } public function testPopProperlyPopsJobOffOfBeanstalkd() { - $queue = new BeanstalkdQueue(m::mock(Pheanstalk::class), 'default', 60); - $queue->setContainer(m::mock(Container::class)); - $pheanstalk = $queue->getPheanstalk(); + $this->setQueue('default', 60); + + $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('watchOnly')->once()->with('default')->andReturn($pheanstalk); $job = m::mock(Job::class); $pheanstalk->shouldReceive('reserveWithTimeout')->once()->with(0)->andReturn($job); - $result = $queue->pop(); + $result = $this->queue->pop(); $this->assertInstanceOf(BeanstalkdJob::class, $result); } public function testBlockingPopProperlyPopsJobOffOfBeanstalkd() { - $queue = new BeanstalkdQueue(m::mock(Pheanstalk::class), 'default', 60, 60); - $queue->setContainer(m::mock(Container::class)); - $pheanstalk = $queue->getPheanstalk(); + $this->setQueue('default', 60, 60); + + $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('watchOnly')->once()->with('default')->andReturn($pheanstalk); $job = m::mock(Job::class); $pheanstalk->shouldReceive('reserveWithTimeout')->once()->with(60)->andReturn($job); - $result = $queue->pop(); + $result = $this->queue->pop(); $this->assertInstanceOf(BeanstalkdJob::class, $result); } public function testDeleteProperlyRemoveJobsOffBeanstalkd() { - $queue = new BeanstalkdQueue(m::mock(Pheanstalk::class), 'default', 60); - $pheanstalk = $queue->getPheanstalk(); + $this->setQueue('default', 60); + + $pheanstalk = $this->queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with('default')->andReturn($pheanstalk); $pheanstalk->shouldReceive('delete')->once()->with(m::type(Job::class)); - $queue->deleteMessage('default', 1); + $this->queue->deleteMessage('default', 1); + } + + /** + * @param string $default + * @param int $timeToRun + * @param int $blockFor + */ + private function setQueue($default, $timeToRun, $blockFor = 0) + { + $this->queue = new BeanstalkdQueue(m::mock(Pheanstalk::class), $default, $timeToRun, $blockFor); + $this->container = m::spy(Container::class); + $this->queue->setContainer($this->container); } } diff --git a/tests/Queue/QueueDatabaseQueueUnitTest.php b/tests/Queue/QueueDatabaseQueueUnitTest.php index 6fa35eca5708..c87dc754545b 100644 --- a/tests/Queue/QueueDatabaseQueueUnitTest.php +++ b/tests/Queue/QueueDatabaseQueueUnitTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Queue; +use Illuminate\Container\Container; use Illuminate\Database\Connection; use Illuminate\Queue\DatabaseQueue; use Illuminate\Queue\Queue; @@ -28,6 +29,7 @@ public function testPushProperlyPushesJobOntoDatabase() $queue = $this->getMockBuilder(DatabaseQueue::class)->onlyMethods(['currentTime'])->setConstructorArgs([$database = m::mock(Connection::class), 'table', 'default'])->getMock(); $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) { $this->assertSame('default', $array['queue']); @@ -39,6 +41,8 @@ public function testPushProperlyPushesJobOntoDatabase() $queue->push('foo', ['data']); + $container->shouldHaveReceived('bound')->with('events')->once(); + Str::createUuidsNormally(); } @@ -56,6 +60,7 @@ public function testDelayedPushProperlyPushesJobOntoDatabase() [$database = m::mock(Connection::class), 'table', 'default'] )->getMock(); $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) { $this->assertSame('default', $array['queue']); @@ -67,6 +72,8 @@ public function testDelayedPushProperlyPushesJobOntoDatabase() $queue->later(10, 'foo', ['data']); + $container->shouldHaveReceived('bound')->with('events')->once(); + Str::createUuidsNormally(); } diff --git a/tests/Queue/QueueRedisQueueTest.php b/tests/Queue/QueueRedisQueueTest.php index 2060772d78a8..952384b7f200 100644 --- a/tests/Queue/QueueRedisQueueTest.php +++ b/tests/Queue/QueueRedisQueueTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Queue; +use Illuminate\Container\Container; use Illuminate\Contracts\Redis\Factory; use Illuminate\Queue\LuaScripts; use Illuminate\Queue\Queue; @@ -28,11 +29,13 @@ public function testPushProperlyPushesJobOntoRedis() $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, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0])); $id = $queue->push('foo', ['data']); $this->assertSame('foo', $id); + $container->shouldHaveReceived('bound')->with('events')->once(); Str::createUuidsNormally(); } @@ -47,6 +50,7 @@ public function testPushProperlyPushesJobOntoRedisWithCustomPayloadHook() $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, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'id' => 'foo', 'attempts' => 0])); @@ -56,6 +60,7 @@ public function testPushProperlyPushesJobOntoRedisWithCustomPayloadHook() $id = $queue->push('foo', ['data']); $this->assertSame('foo', $id); + $container->shouldHaveReceived('bound')->with('events')->once(); Queue::createPayloadUsing(null); @@ -72,6 +77,7 @@ public function testPushProperlyPushesJobOntoRedisWithTwoCustomPayloadHook() $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, 'backoff' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'bar' => 'foo', 'id' => 'foo', 'attempts' => 0])); @@ -85,6 +91,7 @@ public function testPushProperlyPushesJobOntoRedisWithTwoCustomPayloadHook() $id = $queue->push('foo', ['data']); $this->assertSame('foo', $id); + $container->shouldHaveReceived('bound')->with('events')->once(); Queue::createPayloadUsing(null); @@ -100,6 +107,7 @@ public function testDelayedPushProperlyPushesJobOntoRedis() }); $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(1)->willReturn(2); @@ -112,6 +120,7 @@ public function testDelayedPushProperlyPushesJobOntoRedis() $id = $queue->later(1, 'foo', ['data']); $this->assertSame('foo', $id); + $container->shouldHaveReceived('bound')->with('events')->once(); Str::createUuidsNormally(); } @@ -126,6 +135,7 @@ public function testDelayedPushWithDateTimeProperlyPushesJobOntoRedis() $date = Carbon::now(); $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); @@ -137,6 +147,7 @@ public function testDelayedPushWithDateTimeProperlyPushesJobOntoRedis() ); $queue->later($date, 'foo', ['data']); + $container->shouldHaveReceived('bound')->with('events')->once(); Str::createUuidsNormally(); } diff --git a/tests/Queue/QueueSqsQueueTest.php b/tests/Queue/QueueSqsQueueTest.php index 789084515b0d..60e02b161ebb 100755 --- a/tests/Queue/QueueSqsQueueTest.php +++ b/tests/Queue/QueueSqsQueueTest.php @@ -92,33 +92,39 @@ public function testDelayedPushWithDateTimeProperlyPushesJobOntoSqs() { $now = Carbon::now(); $queue = $this->getMockBuilder(SqsQueue::class)->onlyMethods(['createPayload', 'secondsUntil', 'getQueue'])->setConstructorArgs([$this->sqs, $this->queueName, $this->account])->getMock(); + $queue->setContainer($container = m::spy(Container::class)); $queue->expects($this->once())->method('createPayload')->with($this->mockedJob, $this->queueName, $this->mockedData)->willReturn($this->mockedPayload); $queue->expects($this->once())->method('secondsUntil')->with($now)->willReturn(5); $queue->expects($this->once())->method('getQueue')->with($this->queueName)->willReturn($this->queueUrl); $this->sqs->shouldReceive('sendMessage')->once()->with(['QueueUrl' => $this->queueUrl, 'MessageBody' => $this->mockedPayload, 'DelaySeconds' => 5])->andReturn($this->mockedSendMessageResponseModel); $id = $queue->later($now->addSeconds(5), $this->mockedJob, $this->mockedData, $this->queueName); $this->assertEquals($this->mockedMessageId, $id); + $container->shouldHaveReceived('bound')->with('events')->once(); } public function testDelayedPushProperlyPushesJobOntoSqs() { $queue = $this->getMockBuilder(SqsQueue::class)->onlyMethods(['createPayload', 'secondsUntil', 'getQueue'])->setConstructorArgs([$this->sqs, $this->queueName, $this->account])->getMock(); + $queue->setContainer($container = m::spy(Container::class)); $queue->expects($this->once())->method('createPayload')->with($this->mockedJob, $this->queueName, $this->mockedData)->willReturn($this->mockedPayload); $queue->expects($this->once())->method('secondsUntil')->with($this->mockedDelay)->willReturn($this->mockedDelay); $queue->expects($this->once())->method('getQueue')->with($this->queueName)->willReturn($this->queueUrl); $this->sqs->shouldReceive('sendMessage')->once()->with(['QueueUrl' => $this->queueUrl, 'MessageBody' => $this->mockedPayload, 'DelaySeconds' => $this->mockedDelay])->andReturn($this->mockedSendMessageResponseModel); $id = $queue->later($this->mockedDelay, $this->mockedJob, $this->mockedData, $this->queueName); $this->assertEquals($this->mockedMessageId, $id); + $container->shouldHaveReceived('bound')->with('events')->once(); } public function testPushProperlyPushesJobOntoSqs() { $queue = $this->getMockBuilder(SqsQueue::class)->onlyMethods(['createPayload', 'getQueue'])->setConstructorArgs([$this->sqs, $this->queueName, $this->account])->getMock(); + $queue->setContainer($container = m::spy(Container::class)); $queue->expects($this->once())->method('createPayload')->with($this->mockedJob, $this->queueName, $this->mockedData)->willReturn($this->mockedPayload); $queue->expects($this->once())->method('getQueue')->with($this->queueName)->willReturn($this->queueUrl); $this->sqs->shouldReceive('sendMessage')->once()->with(['QueueUrl' => $this->queueUrl, 'MessageBody' => $this->mockedPayload])->andReturn($this->mockedSendMessageResponseModel); $id = $queue->push($this->mockedJob, $this->mockedData, $this->queueName); $this->assertEquals($this->mockedMessageId, $id); + $container->shouldHaveReceived('bound')->with('events')->once(); } public function testSizeProperlyReadsSqsQueueSize() diff --git a/tests/Queue/RedisQueueIntegrationTest.php b/tests/Queue/RedisQueueIntegrationTest.php index 0380988bd4e1..b0a6a498f99c 100644 --- a/tests/Queue/RedisQueueIntegrationTest.php +++ b/tests/Queue/RedisQueueIntegrationTest.php @@ -3,7 +3,9 @@ namespace Illuminate\Tests\Queue; use Illuminate\Container\Container; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; +use Illuminate\Queue\Events\JobQueued; use Illuminate\Queue\Jobs\RedisJob; use Illuminate\Queue\RedisQueue; use Illuminate\Support\Carbon; @@ -21,6 +23,11 @@ class RedisQueueIntegrationTest extends TestCase */ private $queue; + /** + * @var \Mockery\MockInterface|\Mockery\LegacyMockInterface + */ + private $container; + protected function setUp(): void { Carbon::setTestNow(Carbon::now()); @@ -57,6 +64,8 @@ public function testExpiredJobsArePopped($driver) $this->queue->later(-300, $jobs[2]); $this->queue->later(-100, $jobs[3]); + $this->container->shouldHaveReceived('bound')->with('events')->times(4); + $this->assertEquals($jobs[2], unserialize(json_decode($this->queue->pop()->getRawBody())->data->command)); $this->assertEquals($jobs[1], unserialize(json_decode($this->queue->pop()->getRawBody())->data->command)); $this->assertEquals($jobs[3], unserialize(json_decode($this->queue->pop()->getRawBody())->data->command)); @@ -183,13 +192,14 @@ public function testPopProperlyPopsDelayedJobOffOfRedis($driver) */ public function testPopPopsDelayedJobOffOfRedisWhenExpireNull($driver) { - $this->queue = new RedisQueue($this->redis[$driver], 'default', null, null); - $this->queue->setContainer(m::mock(Container::class)); + $this->setQueue($driver, 'default', null, null); // Push an item into queue $job = new RedisQueueIntegrationTestJob(10); $this->queue->later(-10, $job); + $this->container->shouldHaveReceived('bound')->with('events')->once(); + // Pop and check it is popped correctly $before = $this->currentTime(); $this->assertEquals($job, unserialize(json_decode($this->queue->pop()->getRawBody())->data->command)); @@ -264,12 +274,13 @@ public function testBlockingPopProperlyPopsExpiredJobs($driver) */ public function testNotExpireJobsWhenExpireNull($driver) { - $this->queue = new RedisQueue($this->redis[$driver], 'default', null, null); - $this->queue->setContainer(m::mock(Container::class)); + $this->setQueue($driver, 'default', null, null); // Make an expired reserved job $failed = new RedisQueueIntegrationTestJob(-20); $this->queue->push($failed); + $this->container->shouldHaveReceived('bound')->with('events')->once(); + $beforeFailPop = $this->currentTime(); $this->queue->pop(); $afterFailPop = $this->currentTime(); @@ -277,6 +288,7 @@ public function testNotExpireJobsWhenExpireNull($driver) // Push an item into queue $job = new RedisQueueIntegrationTestJob(10); $this->queue->push($job); + $this->container->shouldHaveReceived('bound')->with('events')->times(2); // Pop and check it is popped correctly $before = $this->currentTime(); @@ -309,12 +321,12 @@ public function testNotExpireJobsWhenExpireNull($driver) */ public function testExpireJobsWhenExpireSet($driver) { - $this->queue = new RedisQueue($this->redis[$driver], 'default', null, 30); - $this->queue->setContainer(m::mock(Container::class)); + $this->setQueue($driver, 'default', null, 30); // Push an item into queue $job = new RedisQueueIntegrationTestJob(10); $this->queue->push($job); + $this->container->shouldHaveReceived('bound')->with('events')->once(); // Pop and check it is popped correctly $before = $this->currentTime(); @@ -455,17 +467,67 @@ public function testSize($driver) $this->assertEquals(2, $this->queue->size()); } + /** + * @dataProvider redisDriverProvider + * + * @param string $driver + */ + public function testPushJobQueuedEvent($driver) + { + $events = m::mock(Dispatcher::class); + $events->shouldReceive('dispatch')->withArgs(function (JobQueued $jobQueued) { + $this->assertInstanceOf(RedisQueueIntegrationTestJob::class, $jobQueued->job); + $this->assertIsString(RedisQueueIntegrationTestJob::class, $jobQueued->jobId); + + return true; + })->andReturnNull()->once(); + + $container = m::mock(Container::class); + $container->shouldReceive('bound')->with('events')->andReturn(true)->once(); + $container->shouldReceive('offsetGet')->with('events')->andReturn($events)->once(); + + $queue = new RedisQueue($this->redis[$driver]); + $queue->setContainer($container); + + $queue->push(new RedisQueueIntegrationTestJob(5)); + } + + /** + * @dataProvider redisDriverProvider + * + * @param string $driver + */ + public function testBulkJobQueuedEvent($driver) + { + $events = m::mock(Dispatcher::class); + $events->shouldReceive('dispatch')->with(m::type(JobQueued::class))->andReturnNull()->times(3); + + $container = m::mock(Container::class); + $container->shouldReceive('bound')->with('events')->andReturn(true)->times(3); + $container->shouldReceive('offsetGet')->with('events')->andReturn($events)->times(3); + + $queue = new RedisQueue($this->redis[$driver]); + $queue->setContainer($container); + + $queue->bulk([ + new RedisQueueIntegrationTestJob(5), + new RedisQueueIntegrationTestJob(10), + new RedisQueueIntegrationTestJob(15), + ]); + } + /** * @param string $driver * @param string $default - * @param string $connection + * @param string|null $connection * @param int $retryAfter * @param int|null $blockFor */ private function setQueue($driver, $default = 'default', $connection = null, $retryAfter = 60, $blockFor = null) { $this->queue = new RedisQueue($this->redis[$driver], $default, $connection, $retryAfter, $blockFor); - $this->queue->setContainer(m::mock(Container::class)); + $this->container = m::spy(Container::class); + $this->queue->setContainer($this->container); } } From 5d572e7a6d479ef68ee92c9d67e2e9465174fb4c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 20 Jan 2021 14:18:04 -0600 Subject: [PATCH 099/443] formatting --- src/Illuminate/Queue/Events/JobQueued.php | 25 +++++++++++++++----- src/Illuminate/Queue/Queue.php | 28 +++++++++++------------ tests/Queue/RedisQueueIntegrationTest.php | 2 +- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/Illuminate/Queue/Events/JobQueued.php b/src/Illuminate/Queue/Events/JobQueued.php index 4568cd922fb0..c91d14095963 100644 --- a/src/Illuminate/Queue/Events/JobQueued.php +++ b/src/Illuminate/Queue/Events/JobQueued.php @@ -5,25 +5,38 @@ class JobQueued { /** + * The connection name. + * + * @var string + */ + public $connectionName; + + /** + * The job ID. + * * @var string|int|null */ - public $jobId; + public $id; /** - * @var string|object + * The job instance. + * + * @var \Closure|string|object */ public $job; /** - * JobQueued constructor. + * Create a new event instance. * - * @param string|int|null $jobId + * @param string $connectionName + * @param string|int|null $id * @param \Closure|string|object $job * @return void */ - public function __construct($jobId, $job) + public function __construct($connectionName, $id, $job) { - $this->jobId = $jobId; + $this->connectionName = $connectionName; + $this->id = $id; $this->job = $job; } } diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index bfe8baec8507..f036f2a871c5 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -317,6 +317,20 @@ protected function shouldDispatchAfterCommit($job) return false; } + /** + * Raise the job queued event. + * + * @param string|int|null $jobId + * @param \Closure|string|object $job + * @return void + */ + protected function raiseJobQueuedEvent($jobId, $job) + { + if ($this->container->bound('events')) { + $this->container['events']->dispatch(new JobQueued($this->connectionName, $jobId, $job)); + } + } + /** * Get the connection name for the queue. * @@ -350,18 +364,4 @@ public function setContainer(Container $container) { $this->container = $container; } - - /** - * Raise the job queued event. - * - * @param string|int|null $jobId - * @param \Closure|string|object $job - * @return void - */ - protected function raiseJobQueuedEvent($jobId, $job) - { - if ($this->container->bound('events')) { - $this->container['events']->dispatch(new JobQueued($jobId, $job)); - } - } } diff --git a/tests/Queue/RedisQueueIntegrationTest.php b/tests/Queue/RedisQueueIntegrationTest.php index b0a6a498f99c..5fbad9311dd4 100644 --- a/tests/Queue/RedisQueueIntegrationTest.php +++ b/tests/Queue/RedisQueueIntegrationTest.php @@ -477,7 +477,7 @@ public function testPushJobQueuedEvent($driver) $events = m::mock(Dispatcher::class); $events->shouldReceive('dispatch')->withArgs(function (JobQueued $jobQueued) { $this->assertInstanceOf(RedisQueueIntegrationTestJob::class, $jobQueued->job); - $this->assertIsString(RedisQueueIntegrationTestJob::class, $jobQueued->jobId); + $this->assertIsString(RedisQueueIntegrationTestJob::class, $jobQueued->id); return true; })->andReturnNull()->once(); From e5e1ea85a5fd2d134d4f249e5a6a7cf491cc5803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C3=ADlio=20B=2E=20Pedrollo?= Date: Wed, 20 Jan 2021 18:02:53 -0300 Subject: [PATCH 100/443] Add proper handling for non-default postgresql schema when performing a dump --- src/Illuminate/Database/Schema/PostgresSchemaState.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index 179db6189c55..18cbedf64304 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -16,12 +16,15 @@ class PostgresSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { + $schemaBuilder = $connection->getSchemaBuilder(); + $schema = $schemaBuilder->getConnection()->getConfig('schema'); + $excludedTables = collect($connection->getSchemaBuilder()->getAllTables()) ->map->tablename ->reject(function ($table) { return $table === $this->migrationTable; - })->map(function ($table) { - return '--exclude-table-data='.$table; + })->map(function ($table) use ($schema) { + return '--exclude-table-data='.$schema.'.'.$table; })->implode(' '); $this->makeProcess( From 502e75b2c8a4469363ed03adc974a5194e820ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C3=ADlio=20B=2E=20Pedrollo?= Date: Wed, 20 Jan 2021 18:05:20 -0300 Subject: [PATCH 101/443] Suppress harmless errors messages when restoring a db dump with non default schema --- src/Illuminate/Database/Schema/PostgresSchemaState.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index 18cbedf64304..9ce92a82eace 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -42,7 +42,7 @@ public function dump(Connection $connection, $path) */ public function load($path) { - $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --no-owner --no-acl --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE $LARAVEL_LOAD_PATH'; + $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --no-owner --no-acl --clean --if-exists --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE $LARAVEL_LOAD_PATH'; if (Str::endsWith($path, '.sql')) { $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD psql --file=$LARAVEL_LOAD_PATH --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE'; From 97f6f21a323cbdf5ced6a90b62e7199877c67785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C3=ADlio=20B=2E=20Pedrollo?= Date: Wed, 20 Jan 2021 18:42:57 -0300 Subject: [PATCH 102/443] Use provided $connection to get schema --- src/Illuminate/Database/Schema/PostgresSchemaState.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index 9ce92a82eace..bca0958c3b26 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -16,9 +16,7 @@ class PostgresSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { - $schemaBuilder = $connection->getSchemaBuilder(); - $schema = $schemaBuilder->getConnection()->getConfig('schema'); - + $schema = $connection->getConfig('schema'); $excludedTables = collect($connection->getSchemaBuilder()->getAllTables()) ->map->tablename ->reject(function ($table) { From 9d3752ca5f29c4cb1c0384fb01847820b6ac492c Mon Sep 17 00:00:00 2001 From: Kane Cohen Date: Thu, 21 Jan 2021 08:44:52 +0000 Subject: [PATCH 103/443] Limit expected bindingx v2. --- src/Illuminate/Database/Query/Builder.php | 25 +++++++++++++++------ tests/Database/DatabaseQueryBuilderTest.php | 5 +++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 83416d83be02..c8d47e621495 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -307,6 +307,17 @@ public function fromRaw($expression, $bindings = []) return $this; } + /** + * Returns scalar type value from an unknown type of input. + * + * @param mixed $value + * @return mixed + */ + protected function scalarValue($value) + { + return is_array($value) ? head(Arr::flatten($value)) : $value; + } + /** * Creates a subquery and parse it. * @@ -698,7 +709,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' ); if (! $value instanceof Expression) { - $this->addBinding(is_array($value) ? head($value) : $value, 'where'); + $this->addBinding($this->scalarValue($value), 'where'); } return $this; @@ -1043,7 +1054,7 @@ public function whereBetween($column, array $values, $boolean = 'and', $not = fa $this->wheres[] = compact('type', 'column', 'values', 'boolean', 'not'); - $this->addBinding(array_slice($this->cleanBindings($values), 0, 2), 'where'); + $this->addBinding(array_slice($this->cleanBindings(Arr::flatten($values)), 0, 2), 'where'); return $this; } @@ -1111,7 +1122,7 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = is_array($value) ? head($value) : $value; + $value = $this->scalarValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('Y-m-d'); @@ -1152,7 +1163,7 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = is_array($value) ? head($value) : $value; + $value = $this->scalarValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('H:i:s'); @@ -1238,7 +1249,7 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = is_array($value) ? head($value) : $value; + $value = $this->scalarValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('m'); @@ -1593,7 +1604,7 @@ public function whereJsonLength($column, $operator, $value = null, $boolean = 'a $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { - $this->addBinding((int) $value); + $this->addBinding((int) $this->scalarValue($value)); } return $this; @@ -1742,7 +1753,7 @@ public function having($column, $operator = null, $value = null, $boolean = 'and $this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { - $this->addBinding(is_array($value) ? head($value) : $value, 'having'); + $this->addBinding($this->scalarValue($value), 'having'); } return $this; diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index f7d20c532223..781bc637b2a4 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -319,6 +319,11 @@ public function testWheresWithArrayValue() $builder->select('*')->from('users')->where('id', '<>', [12, 30]); $this->assertSame('select * from "users" where "id" <> ?', $builder->toSql()); $this->assertEquals([0 => 12], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('id', '=', [[12, 30]]); + $this->assertSame('select * from "users" where "id" = ?', $builder->toSql()); + $this->assertEquals([0 => 12], $builder->getBindings()); } public function testMySqlWrappingProtectsQuotationMarks() From dbbb1c1c8a1fa0a51677b5a74fcfe0e2561ced91 Mon Sep 17 00:00:00 2001 From: Kane Cohen Date: Thu, 21 Jan 2021 10:48:50 +0000 Subject: [PATCH 104/443] Update whereDay and whereYear to clean value. --- src/Illuminate/Database/Query/Builder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index c8d47e621495..85679e9472c0 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1204,7 +1204,7 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = is_array($value) ? head($value) : $value; + $value = $this->scalarValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('d'); @@ -1294,7 +1294,7 @@ public function whereYear($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = is_array($value) ? head($value) : $value; + $value = $this->scalarValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('Y'); From c6b8168e6cbbe339fdc3af5ccdded545779965df Mon Sep 17 00:00:00 2001 From: Kane Cohen Date: Thu, 21 Jan 2021 12:08:38 +0000 Subject: [PATCH 105/443] Add limit bindings for having between + tests. --- src/Illuminate/Database/Query/Builder.php | 2 +- tests/Database/DatabaseQueryBuilderTest.php | 23 +++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 85679e9472c0..8ab17d32b960 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1791,7 +1791,7 @@ public function havingBetween($column, array $values, $boolean = 'and', $not = f $this->havings[] = compact('type', 'column', 'values', 'boolean', 'not'); - $this->addBinding($this->cleanBindings($values), 'having'); + $this->addBinding(array_slice($this->cleanBindings(Arr::flatten($values)), 0, 2), 'having'); return $this; } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 781bc637b2a4..8607434fea1a 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -654,6 +654,16 @@ public function testWhereBetweens() $this->assertSame('select * from "users" where "id" between ? and ?', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereBetween('id', [[1, 2, 3]]); + $this->assertSame('select * from "users" where "id" between ? and ?', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereBetween('id', [[1], [2, 3]]); + $this->assertSame('select * from "users" where "id" between ? and ?', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereNotBetween('id', [1, 2]); $this->assertSame('select * from "users" where "id" not between ? and ?', $builder->toSql()); @@ -1172,10 +1182,19 @@ public function testHavings() $builder = $this->getBuilder(); $builder->select(['category', new Raw('count(*) as "total"')])->from('item')->where('department', '=', 'popular')->groupBy('category')->having('total', '>', 3); $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > ?', $builder->toSql()); + } + public function testHavingBetweens() + { $builder = $this->getBuilder(); - $builder->select('*')->from('users')->havingBetween('last_login_date', ['2018-11-16', '2018-12-16']); - $this->assertSame('select * from "users" having "last_login_date" between ? and ?', $builder->toSql()); + $builder->select('*')->from('users')->havingBetween('id', [1, 2, 3]); + $this->assertSame('select * from "users" having "id" between ? and ?', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->havingBetween('id', [[1, 2], [3, 4]]); + $this->assertSame('select * from "users" having "id" between ? and ?', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); } public function testHavingShortcut() From 006873df411d28bfd03fea5e7f91a2afe3918498 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Jan 2021 08:07:23 -0600 Subject: [PATCH 106/443] formatting --- src/Illuminate/Database/Query/Builder.php | 38 +++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 8ab17d32b960..c762e8525605 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -307,17 +307,6 @@ public function fromRaw($expression, $bindings = []) return $this; } - /** - * Returns scalar type value from an unknown type of input. - * - * @param mixed $value - * @return mixed - */ - protected function scalarValue($value) - { - return is_array($value) ? head(Arr::flatten($value)) : $value; - } - /** * Creates a subquery and parse it. * @@ -709,7 +698,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' ); if (! $value instanceof Expression) { - $this->addBinding($this->scalarValue($value), 'where'); + $this->addBinding($this->flattenValue($value), 'where'); } return $this; @@ -1122,7 +1111,7 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = $this->scalarValue($value); + $value = $this->flattenValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('Y-m-d'); @@ -1163,7 +1152,7 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = $this->scalarValue($value); + $value = $this->flattenValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('H:i:s'); @@ -1204,7 +1193,7 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = $this->scalarValue($value); + $value = $this->flattenValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('d'); @@ -1249,7 +1238,7 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = $this->scalarValue($value); + $value = $this->flattenValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('m'); @@ -1294,7 +1283,7 @@ public function whereYear($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); - $value = $this->scalarValue($value); + $value = $this->flattenValue($value); if ($value instanceof DateTimeInterface) { $value = $value->format('Y'); @@ -1604,7 +1593,7 @@ public function whereJsonLength($column, $operator, $value = null, $boolean = 'a $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { - $this->addBinding((int) $this->scalarValue($value)); + $this->addBinding((int) $this->flattenValue($value)); } return $this; @@ -1753,7 +1742,7 @@ public function having($column, $operator = null, $value = null, $boolean = 'and $this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean'); if (! $value instanceof Expression) { - $this->addBinding($this->scalarValue($value), 'having'); + $this->addBinding($this->flattenValue($value), 'having'); } return $this; @@ -2969,6 +2958,17 @@ protected function cleanBindings(array $bindings) })); } + /** + * Get a scalar type value from an unknown type of input. + * + * @param mixed $value + * @return mixed + */ + protected function flattenValue($value) + { + return is_array($value) ? head(Arr::flatten($value)) : $value; + } + /** * Get the default key name of the table. * From 3464d0232cb75aeadb7b4483f788c1d1a30221d4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Jan 2021 08:10:27 -0600 Subject: [PATCH 107/443] version --- 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 30e8e7c358b1..35348d53f62b 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.13'; + const VERSION = '6.20.14'; /** * The base path for the Laravel installation. From 9dd38140dc2924daa1a020a3d7a45f9ceff03df3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Jan 2021 08:10:48 -0600 Subject: [PATCH 108/443] version --- 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 1dc26d3e3d16..142bc4b2d4bd 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '7.30.3'; + const VERSION = '7.30.4'; /** * The base path for the Laravel installation. From d627ce29122404abaa5bd9221d4b14e08fd4fcd2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Jan 2021 08:11:10 -0600 Subject: [PATCH 109/443] version --- 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 0dab37cd18dc..63637a1c60b8 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.23.1'; + const VERSION = '8.23.2'; /** * The base path for the Laravel installation. From 7689b36264eca2b2a9b5b099fa9735277feacb73 Mon Sep 17 00:00:00 2001 From: Chuangbo Li Date: Thu, 21 Jan 2021 22:18:59 +0800 Subject: [PATCH 110/443] fix serialization of rate limited with redis middleware (#35971) Same as f3d4dcb but for RateLimitedWithRedis --- .../Queue/Middleware/RateLimitedWithRedis.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php b/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php index 7000e9d55307..af1eac1aa7ff 100644 --- a/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php +++ b/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php @@ -88,4 +88,17 @@ protected function getTimeUntilNextRetry($key) { return ($this->decaysAt[$key] - $this->currentTime()) + 3; } + + /** + * Prepare the object after unserialization. + * + * @param array $data + * @return void + */ + public function __unserialize(array $data) + { + parent::__unserialize($data); + + $this->redis = Container::getInstance()->make(Redis::class); + } } From d16e9f875e4d7609a05d5007393e22ba95efd1fc Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Jan 2021 08:19:21 -0600 Subject: [PATCH 111/443] version --- 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 63637a1c60b8..4fdb7059931c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.23.2'; + const VERSION = '8.24.0'; /** * The base path for the Laravel installation. From 6e6d699b05c2fe9447e26adaf26e154c8063a34d Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 21 Jan 2021 17:27:27 +0100 Subject: [PATCH 112/443] Fix Filesystem type (#35979) --- src/Illuminate/Database/PostgresConnection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index 009a02b37def..5d68d1d665a7 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -10,6 +10,7 @@ use Illuminate\Database\Schema\Grammars\PostgresGrammar as SchemaGrammar; use Illuminate\Database\Schema\PostgresBuilder; use Illuminate\Database\Schema\PostgresSchemaState; +use Illuminate\Filesystem\Filesystem; use PDO; class PostgresConnection extends Connection @@ -77,7 +78,7 @@ protected function getDefaultSchemaGrammar() /** * Get the schema state for the connection. * - * @param \Illuminate\Database\Filesystem|null $files + * @param \Illuminate\Filesystem\Filesystem|null $files * @param callable|null $processFactory * @return \Illuminate\Database\Schema\PostgresSchemaState */ From 6b01aea060634cf64fdee8b669c18b2c4b2d33ae Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 22 Jan 2021 15:51:44 +0200 Subject: [PATCH 113/443] fix worker --delay option (#35991) --- src/Illuminate/Queue/Console/WorkCommand.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index c8c815eefe24..ff092197f53a 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -124,13 +124,9 @@ protected function runWorker($connection, $queue) */ protected function gatherWorkerOptions() { - $backoff = $this->hasOption('backoff') - ? $this->option('backoff') - : $this->option('delay'); - return new WorkerOptions( $this->option('name'), - $backoff, + max($this->option('backoff'), $this->option('delay')), $this->option('memory'), $this->option('timeout'), $this->option('sleep'), From f53b3bc7967e182bfe1b7cb7f86ad0649bb16faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Fri, 22 Jan 2021 14:56:05 +0100 Subject: [PATCH 114/443] [8.x] Support Eloquent Builder for static analyses (#35993) * Support Eloquent Builder for static analyses * Update Builder.php --- src/Illuminate/Database/Query/Builder.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 175a9062f45b..7a7df49a28c5 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -491,7 +491,7 @@ public function joinWhere($table, $first, $operator, $second, $type = 'inner') /** * Add a subquery join clause to the query. * - * @param \Closure|\Illuminate\Database\Query\Builder|string $query + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query * @param string $as * @param \Closure|string $first * @param string|null $operator @@ -544,7 +544,7 @@ public function leftJoinWhere($table, $first, $operator, $second) /** * Add a subquery left join to the query. * - * @param \Closure|\Illuminate\Database\Query\Builder|string $query + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query * @param string $as * @param \Closure|string $first * @param string|null $operator @@ -587,7 +587,7 @@ public function rightJoinWhere($table, $first, $operator, $second) /** * Add a subquery right join to the query. * - * @param \Closure|\Illuminate\Database\Query\Builder|string $query + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query * @param string $as * @param \Closure|string $first * @param string|null $operator From fc1c2dd9caf6ddc66812dcc9138112222585d524 Mon Sep 17 00:00:00 2001 From: Daniel Madureira Date: Fri, 22 Jan 2021 11:03:14 -0300 Subject: [PATCH 115/443] Added reference to resourceVerbs method in docblock (#35989) --- src/Illuminate/Support/Facades/Route.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Route.php b/src/Illuminate/Support/Facades/Route.php index f21ba4c23a20..7f36be9910bc 100755 --- a/src/Illuminate/Support/Facades/Route.php +++ b/src/Illuminate/Support/Facades/Route.php @@ -29,6 +29,7 @@ * @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix) * @method static \Illuminate\Routing\RouteRegistrar where(array $where) * @method static \Illuminate\Routing\Router|\Illuminate\Routing\RouteRegistrar group(\Closure|string|array $attributes, \Closure|string $routes) + * @method static \Illuminate\Routing\ResourceRegistrar resourceVerbs(array $verbs = []) * @method static string|null currentRouteAction() * @method static string|null currentRouteName() * @method static void apiResources(array $resources, array $options = []) From 4ad4f199f77392e176f0ee56371e116b057270cd Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Fri, 22 Jan 2021 16:05:23 +0200 Subject: [PATCH 116/443] Added tests. Added support of PHP 7.3 (#35986) --- .../Queue/Middleware/RateLimited.php | 12 ++++-------- .../Queue/Middleware/RateLimitedWithRedis.php | 5 ++--- tests/Integration/Queue/RateLimitedTest.php | 16 ++++++++++++++++ .../Queue/RateLimitedWithRedisTest.php | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Queue/Middleware/RateLimited.php b/src/Illuminate/Queue/Middleware/RateLimited.php index 4d2d61c5e4e4..129741f7a6c7 100644 --- a/src/Illuminate/Queue/Middleware/RateLimited.php +++ b/src/Illuminate/Queue/Middleware/RateLimited.php @@ -126,25 +126,21 @@ protected function getTimeUntilNextRetry($key) * * @return array */ - public function __serialize() + public function __sleep() { return [ - 'limiterName' => $this->limiterName, - 'shouldRelease' => $this->shouldRelease, + 'limiterName', + 'shouldRelease', ]; } /** * Prepare the object after unserialization. * - * @param array $data * @return void */ - public function __unserialize(array $data) + public function __wakeup() { $this->limiter = Container::getInstance()->make(RateLimiter::class); - - $this->limiterName = $data['limiterName']; - $this->shouldRelease = $data['shouldRelease']; } } diff --git a/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php b/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php index af1eac1aa7ff..e919786f27c6 100644 --- a/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php +++ b/src/Illuminate/Queue/Middleware/RateLimitedWithRedis.php @@ -92,12 +92,11 @@ protected function getTimeUntilNextRetry($key) /** * Prepare the object after unserialization. * - * @param array $data * @return void */ - public function __unserialize(array $data) + public function __wakeup() { - parent::__unserialize($data); + parent::__wakeup(); $this->redis = Container::getInstance()->make(Redis::class); } diff --git a/tests/Integration/Queue/RateLimitedTest.php b/tests/Integration/Queue/RateLimitedTest.php index d73dd58a2c29..c3a74027cc7e 100644 --- a/tests/Integration/Queue/RateLimitedTest.php +++ b/tests/Integration/Queue/RateLimitedTest.php @@ -80,6 +80,22 @@ public function testJobsCanHaveConditionalRateLimits() $this->assertJobWasReleased(NonAdminTestJob::class); } + public function testMiddlewareSerialization() + { + $rateLimited = new RateLimited('limiterName'); + $rateLimited->shouldRelease = false; + + $restoredRateLimited = unserialize(serialize($rateLimited)); + + $fetch = (function (string $name) { + return $this->{$name}; + })->bindTo($restoredRateLimited, RateLimited::class); + + $this->assertFalse($restoredRateLimited->shouldRelease); + $this->assertEquals('limiterName', $fetch('limiterName')); + $this->assertInstanceOf(RateLimiter::class, $fetch('limiter')); + } + protected function assertJobRanSuccessfully($class) { $class::$handled = false; diff --git a/tests/Integration/Queue/RateLimitedWithRedisTest.php b/tests/Integration/Queue/RateLimitedWithRedisTest.php index 175f531bbfa0..f08f3146a108 100644 --- a/tests/Integration/Queue/RateLimitedWithRedisTest.php +++ b/tests/Integration/Queue/RateLimitedWithRedisTest.php @@ -7,6 +7,7 @@ use Illuminate\Cache\RateLimiter; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Contracts\Queue\Job; +use Illuminate\Contracts\Redis\Factory as Redis; use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; use Illuminate\Queue\CallQueuedHandler; use Illuminate\Queue\InteractsWithQueue; @@ -111,6 +112,23 @@ public function testJobsCanHaveConditionalRateLimits() $this->assertJobWasReleased($nonAdminJob); } + public function testMiddlewareSerialization() + { + $rateLimited = new RateLimitedWithRedis('limiterName'); + $rateLimited->shouldRelease = false; + + $restoredRateLimited = unserialize(serialize($rateLimited)); + + $fetch = (function (string $name) { + return $this->{$name}; + })->bindTo($restoredRateLimited, RateLimitedWithRedis::class); + + $this->assertFalse($restoredRateLimited->shouldRelease); + $this->assertEquals('limiterName', $fetch('limiterName')); + $this->assertInstanceOf(RateLimiter::class, $fetch('limiter')); + $this->assertInstanceOf(Redis::class, $fetch('redis')); + } + protected function assertJobRanSuccessfully($testJob) { $testJob::$handled = false; From 7be50a511955dea2bf4d6e30208b6fbf07eaa36e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 22 Jan 2021 08:58:06 -0600 Subject: [PATCH 117/443] formatting and schema handling --- src/Illuminate/Database/Schema/PostgresSchemaState.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index bca0958c3b26..7231118f1899 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -16,13 +16,16 @@ class PostgresSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { - $schema = $connection->getConfig('schema'); + $schema = $connection->getConfig('schema', 'public'); + + $schema = $schema === 'public' ? '' : $schema.'.'; + $excludedTables = collect($connection->getSchemaBuilder()->getAllTables()) ->map->tablename ->reject(function ($table) { return $table === $this->migrationTable; })->map(function ($table) use ($schema) { - return '--exclude-table-data='.$schema.'.'.$table; + return '--exclude-table-data='.$schema.$table; })->implode(' '); $this->makeProcess( @@ -40,7 +43,7 @@ public function dump(Connection $connection, $path) */ public function load($path) { - $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --no-owner --no-acl --clean --if-exists --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE $LARAVEL_LOAD_PATH'; + $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --no-owner --no-acl --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE $LARAVEL_LOAD_PATH'; if (Str::endsWith($path, '.sql')) { $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD psql --file=$LARAVEL_LOAD_PATH --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE'; From 49b0d524db882e84f977bba000ff9ac9da12b506 Mon Sep 17 00:00:00 2001 From: Bogdan Kharchenko Date: Fri, 22 Jan 2021 10:34:09 -0500 Subject: [PATCH 118/443] Logout Current Device hint (#35997) --- src/Illuminate/Support/Facades/Auth.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Auth.php b/src/Illuminate/Support/Facades/Auth.php index 02ce2cd76b4c..eb9a05d2ed93 100755 --- a/src/Illuminate/Support/Facades/Auth.php +++ b/src/Illuminate/Support/Facades/Auth.php @@ -24,6 +24,7 @@ * @method static int|string|null id() * @method static void login(\Illuminate\Contracts\Auth\Authenticatable $user, bool $remember = false) * @method static void logout() + * @method static void logoutCurrentDevice() * @method static void setUser(\Illuminate\Contracts\Auth\Authenticatable $user) * @method static void shouldUse(string $name); * From cc03df353661a4b7364a5a0c11fa858c7d33c5c3 Mon Sep 17 00:00:00 2001 From: ozgurkadarozgur Date: Fri, 22 Jan 2021 19:54:02 +0300 Subject: [PATCH 119/443] TransformsRequest.php cleanArray function fix. (#36002) When I send a request which has nested json body fields this function does recursive operation and it throws 'maximum function nested level of 256 reached.'. Size of my data is less than 256. If I use foreach loop it does not make recursive operation. My request: {"sample1":"sample","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[{"title":"aa","children":[]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}],"sample2":[{"sample3":"sample","name":"sample"}]} --- .../Foundation/Http/Middleware/TransformsRequest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php index a61a1bd72013..fca34f837b0b 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php +++ b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php @@ -58,9 +58,11 @@ protected function cleanParameterBag(ParameterBag $bag) */ protected function cleanArray(array $data, $keyPrefix = '') { - return collect($data)->map(function ($value, $key) use ($keyPrefix) { - return $this->cleanValue($keyPrefix.$key, $value); - })->all(); + foreach ($data as $key => $value) { + $data[$key] = $this->cleanValue($keyPrefix.$key, $value); + } + + return collect($data)->all(); } /** From 72a44d33a534aca63e37ee5dceecd3c0eb912656 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sat, 23 Jan 2021 19:20:10 +0100 Subject: [PATCH 120/443] Ensure that the model class name is properly set. (#36011) --- src/Illuminate/Database/Eloquent/Builder.php | 2 +- tests/Integration/Database/EloquentWhereTest.php | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index aa579259c1d5..f9b3f4c6219d 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -522,7 +522,7 @@ public function sole($columns = ['*']) try { return $this->baseSole($columns); } catch (RecordsNotFoundException $exception) { - throw new ModelNotFoundException($this->model); + throw (new ModelNotFoundException)->setModel(get_class($this->model)); } } diff --git a/tests/Integration/Database/EloquentWhereTest.php b/tests/Integration/Database/EloquentWhereTest.php index a400d7f76305..1d7d5f337328 100644 --- a/tests/Integration/Database/EloquentWhereTest.php +++ b/tests/Integration/Database/EloquentWhereTest.php @@ -126,9 +126,13 @@ public function testSoleFailsForMultipleRecords() public function testSoleFailsIfNoRecords() { - $this->expectException(ModelNotFoundException::class); + try { + UserWhereTest::where('name', 'test-name')->sole(); + } catch (ModelNotFoundException $exception) { + // + } - UserWhereTest::where('name', 'test-name')->sole(); + $this->assertSame(UserWhereTest::class, $exception->getModel()); } } From f4c7912753cbcc80104ea844593f7fdd1ca0fed7 Mon Sep 17 00:00:00 2001 From: BinotaLIU Date: Sun, 24 Jan 2021 16:00:40 +0800 Subject: [PATCH 121/443] add Str::pipe --- src/Illuminate/Support/Stringable.php | 11 +++++++++++ tests/Support/SupportStringableTest.php | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index c24d19e6a923..1b9e1a0b6933 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -399,6 +399,17 @@ public function parseCallback($default = null) return Str::parseCallback($this->value, $default); } + /** + * Call the given callback and return a new string. + * + * @param callable $callback + * @return static + */ + public function pipe(callable $callback) + { + return new static(call_user_func($callback, $this)); + } + /** * Get the plural form of an English word. * diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 1986d050de9c..851b2c0617ac 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -545,4 +545,28 @@ public function testChunk() $this->assertInstanceOf(Collection::class, $chunks); $this->assertSame(['foo', 'bar', 'baz'], $chunks->all()); } + + public function testTap() + { + $stringable = $this->stringable('foobarbaz'); + + $fromTheTap = ''; + + $stringable = $stringable->tap(function (Stringable $string) use (&$fromTheTap) { + $fromTheTap = $string->substr(0, 3); + }); + + $this->assertSame('foo', (string) $fromTheTap); + $this->assertSame('foobarbaz', (string) $stringable); + } + + public function testPipe() + { + $callback = function ($stringable) { + return 'bar'; + }; + + $this->assertInstanceOf(Stringable::class, $this->stringable('foo')->pipe($callback)); + $this->assertSame('bar', (string) $this->stringable('foo')->pipe($callback)); + } } From 7f1138e362c6e124f4e1b327fc14d83eb80fffee Mon Sep 17 00:00:00 2001 From: BinotaLIU Date: Sun, 24 Jan 2021 16:01:02 +0800 Subject: [PATCH 122/443] make Stringable Tappable --- src/Illuminate/Support/Stringable.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 1b9e1a0b6933..b718f98a090c 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -4,11 +4,12 @@ use Closure; use Illuminate\Support\Traits\Macroable; +use Illuminate\Support\Traits\Tappable; use Symfony\Component\VarDumper\VarDumper; class Stringable { - use Macroable; + use Tappable, Macroable; /** * The underlying string value. From 8a7ea7135ca6019b5e4b87969cfde4a75ab59af2 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Sun, 24 Jan 2021 02:49:02 -0700 Subject: [PATCH 123/443] Typo fixes --- src/Illuminate/Cache/Lock.php | 2 +- src/Illuminate/Database/DatabaseTransactionRecord.php | 2 +- .../Foundation/Testing/Concerns/InteractsWithConsole.php | 2 +- tests/Foundation/FoundationFormRequestTest.php | 6 +++--- tests/Http/HttpRequestTest.php | 4 ++-- .../Notifications/SendingMailNotificationsTest.php | 6 +++--- tests/Log/LogManagerTest.php | 2 +- tests/Mail/MailableQueuedTest.php | 8 ++++---- tests/Redis/RedisManagerExtensionTest.php | 4 ++-- tests/Support/SupportCollectionTest.php | 4 ++-- tests/Validation/ValidationValidatorTest.php | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index eb035161ba87..bed170507a9a 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -153,7 +153,7 @@ protected function isOwnedByCurrentProcess() } /** - * Specify the number of milliseconds to sleep in between blocked lock aquisition attempts. + * Specify the number of milliseconds to sleep in between blocked lock acquisition attempts. * * @param int $milliseconds * @return $this diff --git a/src/Illuminate/Database/DatabaseTransactionRecord.php b/src/Illuminate/Database/DatabaseTransactionRecord.php index b4556d8fc305..3259552dcfbb 100755 --- a/src/Illuminate/Database/DatabaseTransactionRecord.php +++ b/src/Illuminate/Database/DatabaseTransactionRecord.php @@ -30,7 +30,7 @@ class DatabaseTransactionRecord * * @param string $connection * @param int $level - * @retunr void + * @return void */ public function __construct($connection, $level) { diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index dad0f65f6464..38409d3d697f 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -30,7 +30,7 @@ trait InteractsWithConsole public $unexpectedOutput = []; /** - * All of the expected ouput tables. + * All of the expected output tables. * * @var array */ diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index fb535897f5ca..d394566ce6cb 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -119,15 +119,15 @@ public function test_after_validation_runs_after_validation() * Catch the given exception thrown from the executor, and return it. * * @param string $class - * @param \Closure $excecutor + * @param \Closure $executor * @return \Exception * * @throws \Exception */ - protected function catchException($class, $excecutor) + protected function catchException($class, $executor) { try { - $excecutor(); + $executor(); } catch (Exception $e) { if (is_a($e, $class)) { return $e; diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index a381c4871192..65272b796302 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -501,8 +501,8 @@ public function testArrayAccess() return $route; }); - $this->assertFalse(isset($request['non-existant'])); - $this->assertNull($request['non-existant']); + $this->assertFalse(isset($request['non-existent'])); + $this->assertNull($request['non-existent']); $this->assertTrue(isset($request['name'])); $this->assertNull($request['name']); diff --git a/tests/Integration/Notifications/SendingMailNotificationsTest.php b/tests/Integration/Notifications/SendingMailNotificationsTest.php index cd46217c373a..0f5d595e859c 100644 --- a/tests/Integration/Notifications/SendingMailNotificationsTest.php +++ b/tests/Integration/Notifications/SendingMailNotificationsTest.php @@ -203,12 +203,12 @@ public function testMailIsSentWithSubject() $user->notify($notification); } - public function testMailIsSentToMultipleAdresses() + public function testMailIsSentToMultipleAddresses() { $notification = new TestMailNotificationWithSubject; $notification->id = Str::uuid()->toString(); - $user = NotifiableUserWithMultipleAddreses::forceCreate([ + $user = NotifiableUserWithMultipleAddresses::forceCreate([ 'email' => 'taylor@laravel.com', ]); @@ -365,7 +365,7 @@ public function routeNotificationForMail($notification) } } -class NotifiableUserWithMultipleAddreses extends NotifiableUser +class NotifiableUserWithMultipleAddresses extends NotifiableUser { public function routeNotificationForMail($notification) { diff --git a/tests/Log/LogManagerTest.php b/tests/Log/LogManagerTest.php index f365c9f701c0..65cd162d76ad 100755 --- a/tests/Log/LogManagerTest.php +++ b/tests/Log/LogManagerTest.php @@ -327,7 +327,7 @@ public function testLogManagerCreateSyslogDriverWithConfiguredFormatter() $this->assertSame('Y/m/d--test', $dateFormat->getValue($formatter)); } - public function testLogMnagerPurgeResolvedChannels() + public function testLogManagerPurgeResolvedChannels() { $manager = new LogManager($this->app); diff --git a/tests/Mail/MailableQueuedTest.php b/tests/Mail/MailableQueuedTest.php index 99854f82ce81..47b93429e62e 100644 --- a/tests/Mail/MailableQueuedTest.php +++ b/tests/Mail/MailableQueuedTest.php @@ -32,7 +32,7 @@ public function testQueuedMailableSent() ->onlyMethods(['createMessage', 'to']) ->getMock(); $mailer->setQueue($queueFake); - $mailable = new MailableQueableStub; + $mailable = new MailableQueueableStub; $queueFake->assertNothingPushed(); $mailer->send($mailable); $queueFake->assertPushedOn(null, SendQueuedMailable::class); @@ -46,7 +46,7 @@ public function testQueuedMailableWithAttachmentSent() ->onlyMethods(['createMessage']) ->getMock(); $mailer->setQueue($queueFake); - $mailable = new MailableQueableStub; + $mailable = new MailableQueueableStub; $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; $mailable->attach('foo.jpg', $attachmentOption); $this->assertIsArray($mailable->attachments); @@ -75,7 +75,7 @@ public function testQueuedMailableWithAttachmentFromDiskSent() ->onlyMethods(['createMessage']) ->getMock(); $mailer->setQueue($queueFake); - $mailable = new MailableQueableStub; + $mailable = new MailableQueueableStub; $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; $mailable->attachFromStorage('/', 'foo.jpg', $attachmentOption); @@ -95,7 +95,7 @@ protected function getMocks() } } -class MailableQueableStub extends Mailable implements ShouldQueue +class MailableQueueableStub extends Mailable implements ShouldQueue { use Queueable; diff --git a/tests/Redis/RedisManagerExtensionTest.php b/tests/Redis/RedisManagerExtensionTest.php index 04b7eb63d7d9..650b118ec646 100644 --- a/tests/Redis/RedisManagerExtensionTest.php +++ b/tests/Redis/RedisManagerExtensionTest.php @@ -39,7 +39,7 @@ protected function setUp(): void ]); $this->redis->extend('my_custom_driver', function () { - return new FakeRedisConnnector(); + return new FakeRedisConnector(); }); } @@ -91,7 +91,7 @@ public function test_parse_connection_configuration_for_cluster() } } -class FakeRedisConnnector implements Connector +class FakeRedisConnector implements Connector { /** * Create a new clustered Predis connection. diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 2dfd503656ca..a72fc66949aa 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -78,8 +78,8 @@ public function testFirstWhere($collection) $this->assertSame('book', $data->firstWhere('material', 'paper')['type']); $this->assertSame('gasket', $data->firstWhere('material', 'rubber')['type']); - $this->assertNull($data->firstWhere('material', 'nonexistant')); - $this->assertNull($data->firstWhere('nonexistant', 'key')); + $this->assertNull($data->firstWhere('material', 'nonexistent')); + $this->assertNull($data->firstWhere('nonexistent', 'key')); } /** diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 3a97c0c962d1..48f9edcef0f8 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -2982,7 +2982,7 @@ public function testValidateImageDimensions() $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=2/3']); $this->assertTrue($v->passes()); - // Ensure svg images always pass as size is irreleveant (image/svg+xml) + // Ensure svg images always pass as size is irrelevant (image/svg+xml) $svgXmlUploadedFile = new UploadedFile(__DIR__.'/fixtures/image.svg', '', 'image/svg+xml', null, true); $trans = $this->getIlluminateArrayTranslator(); @@ -2995,7 +2995,7 @@ public function testValidateImageDimensions() $v = new Validator($trans, ['x' => $svgXmlFile], ['x' => 'dimensions:max_width=1,max_height=1']); $this->assertTrue($v->passes()); - // Ensure svg images always pass as size is irreleveant (image/svg) + // Ensure svg images always pass as size is irrelevant (image/svg) $svgUploadedFile = new UploadedFile(__DIR__.'/fixtures/image2.svg', '', 'image/svg', null, true); $trans = $this->getIlluminateArrayTranslator(); From dd0d096499349a88dd6b99cb6b985350c15833a3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 24 Jan 2021 19:06:30 -0600 Subject: [PATCH 124/443] formatting --- src/Illuminate/Support/Stringable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index b718f98a090c..e945beaf7614 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -9,7 +9,7 @@ class Stringable { - use Tappable, Macroable; + use Macroable, Tappable; /** * The underlying string value. From 387281ffe386b41b4060c1dd1610911a772771d7 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Mon, 25 Jan 2021 14:02:28 +0200 Subject: [PATCH 125/443] Allow to encrypt json with fillJsonAttribute --- .../Eloquent/Concerns/HasAttributes.php | 8 +++++++- .../EloquentModelEncryptedCastingTest.php | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 0bde3e119227..e62f8b52148d 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -779,10 +779,16 @@ public function fillJsonAttribute($key, $value) { [$key, $path] = explode('->', $key, 2); - $this->attributes[$key] = $this->asJson($this->getArrayAttributeWithValue( + $value = $this->asJson($this->getArrayAttributeWithValue( $path, $key, $value )); + if ($this->isEncryptedCastable($key)) { + $value = $this->castAttributeAsEncryptedString($key, $value); + } + + $this->attributes[$key] = $value; + return $this; } diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index 6eca8078028c..5b7029f19725 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -98,6 +98,26 @@ public function testJsonIsCastable() ]); } + public function testJsonAttributeIsCastable() + { + $this->encrypter->expects('encrypt') + ->with('{"key1":"value1"}', false) + ->andReturn('encrypted-secret-json-string'); + $this->encrypter->expects('decrypt') + ->with('encrypted-secret-json-string', false) + ->andReturn('{"key1":"value1"}'); + + $subject = new EncryptedCast; + $subject->setAttribute('secret_json->key1','value1'); + $subject->save(); + + $this->assertSame(['key1' => 'value1'], $subject->secret_json); + $this->assertDatabaseHas('encrypted_casts', [ + 'id' => $subject->id, + 'secret_json' => 'encrypted-secret-json-string', + ]); + } + public function testObjectIsCastable() { $object = new \stdClass(); From bbe6aebce246add080fa687031ba1afd0ae01242 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Mon, 25 Jan 2021 14:08:48 +0200 Subject: [PATCH 126/443] CS --- .../Integration/Database/EloquentModelEncryptedCastingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index 5b7029f19725..844a82ef3fac 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -108,7 +108,7 @@ public function testJsonAttributeIsCastable() ->andReturn('{"key1":"value1"}'); $subject = new EncryptedCast; - $subject->setAttribute('secret_json->key1','value1'); + $subject->setAttribute('secret_json->key1', 'value1'); $subject->save(); $this->assertSame(['key1' => 'value1'], $subject->secret_json); From 6e630ea3931b6fb1f233a59fd614def867ee9014 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Mon, 25 Jan 2021 16:36:28 +0200 Subject: [PATCH 127/443] Fix retrieving encrypted JSON in getArrayAttributeByKey --- .../Database/Eloquent/Concerns/HasAttributes.php | 13 +++++++++++-- .../EloquentModelEncryptedCastingTest.php | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index e62f8b52148d..e60e09574f94 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -850,8 +850,17 @@ protected function getArrayAttributeWithValue($path, $key, $value) */ protected function getArrayAttributeByKey($key) { - return isset($this->attributes[$key]) ? - $this->fromJson($this->attributes[$key]) : []; + if(!isset($this->attributes[$key])){ + return []; + } + + $value = $this->attributes[$key]; + + if ($this->isEncryptedCastable($key)) { + $value = $this->fromEncryptedString($value); + } + + return $this->fromJson($value); } /** diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index 844a82ef3fac..7aad90a686fc 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -106,15 +106,23 @@ public function testJsonAttributeIsCastable() $this->encrypter->expects('decrypt') ->with('encrypted-secret-json-string', false) ->andReturn('{"key1":"value1"}'); + $this->encrypter->expects('encrypt') + ->with('{"key1":"value1","key2":"value2"}', false) + ->andReturn('encrypted-secret-json-string2'); + $this->encrypter->expects('decrypt') + ->with('encrypted-secret-json-string2', false) + ->andReturn('{"key1":"value1","key2":"value2"}'); - $subject = new EncryptedCast; - $subject->setAttribute('secret_json->key1', 'value1'); + $subject = new EncryptedCast([ + 'secret_json' => ['key1' => 'value1'], + ]); + $subject->setAttribute('secret_json->key2', 'value2'); $subject->save(); - $this->assertSame(['key1' => 'value1'], $subject->secret_json); + $this->assertSame(['key1' => 'value1', 'key2' => 'value2'], $subject->secret_json); $this->assertDatabaseHas('encrypted_casts', [ 'id' => $subject->id, - 'secret_json' => 'encrypted-secret-json-string', + 'secret_json' => 'encrypted-secret-json-string2', ]); } From 556fdb4a25872f02f5bcb58e77249bdca41224b5 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 09:12:14 -0600 Subject: [PATCH 128/443] First pass at else --- src/Illuminate/Routing/Route.php | 23 +++++++++++++++++++++++ src/Illuminate/Routing/Router.php | 15 ++++++++++++--- tests/Routing/RoutingRouteTest.php | 22 ++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 37ba1aaa4236..bfa7a549d1d4 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -933,6 +933,29 @@ public function setAction(array $action) return $this; } + /** + * Get the value of the else redirect. + * + * @return \Illuminate\Http\RedirectResponse|null + */ + public function getElse() + { + return $this->action['else'] ?? null; + } + + /** + * Add or change the else redirect. + * + * @param \Illuminate\Http\RedirectResponse $else + * @return $this + */ + public function else($else) + { + $this->action['else'] = $else; + + return $this; + } + /** * Get all middleware, including the ones from the controller. * diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index f1b61dc74dcf..376bb35e6801 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -12,6 +12,7 @@ use Illuminate\Contracts\Support\Jsonable; use Illuminate\Contracts\Support\Responsable; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; @@ -665,9 +666,17 @@ protected function runRoute(Request $request, Route $route) $this->events->dispatch(new RouteMatched($route, $request)); - return $this->prepareResponse($request, - $this->runRouteWithinStack($route, $request) - ); + try { + return $this->prepareResponse($request, + $this->runRouteWithinStack($route, $request) + ); + } catch (ModelNotFoundException $exception) { + if($route->getElse()) { + return $route->getElse(); + } + + throw $exception; + } } /** diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index 9a9f76e8123f..dd7c4c92fe36 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -15,6 +15,7 @@ use Illuminate\Events\Dispatcher; use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Http\JsonResponse; +use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Routing\Controller; @@ -1671,6 +1672,27 @@ public function testImplicitBindingsWithOptionalParameterWithExistingKeyInUri() $this->assertSame('taylor', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent()); } + public function testImplicitBindingsWithMissingModelHandledByElse() + { + $redirect = new RedirectResponse('/', 302); + + $router = $this->getRouter(); + $router->get('foo/{bar}', [ + 'middleware' => SubstituteBindings::class, + 'uses' => function (RouteModelBindingNullStub $bar = null) { + $this->assertInstanceOf(RouteModelBindingNullStub::class, $bar); + + return $bar->first(); + }, + ])->else($redirect); + + $request = Request::create('foo/taylor', 'GET'); + + $response = $router->dispatch($request); + $this->assertTrue($response->isRedirect('/')); + $this->assertEquals(302, $response->getStatusCode()); + } + public function testImplicitBindingsWithOptionalParameterWithNoKeyInUri() { $router = $this->getRouter(); From b7c60553e749d2850832388ef2e23020083972b4 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 25 Jan 2021 16:29:09 +0100 Subject: [PATCH 129/443] Pipe through render and report exception methods (#36032) --- .../Foundation/Exceptions/Handler.php | 1 - .../View/Engines/CompilerEngine.php | 4 +- src/Illuminate/View/ViewException.php | 37 +++++++++++++++++++ .../View/RenderableViewExceptionTest.php | 36 ++++++++++++++++++ .../templates/renderable-exception.blade.php | 3 ++ tests/View/fixtures/nested/basic.php | 1 - 6 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/Illuminate/View/ViewException.php create mode 100644 tests/Integration/View/RenderableViewExceptionTest.php create mode 100644 tests/Integration/View/templates/renderable-exception.blade.php diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 33fbccc5e7e1..61a775a92a2d 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -21,7 +21,6 @@ use Illuminate\Session\TokenMismatchException; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\View; use Illuminate\Support\Reflector; use Illuminate\Support\Traits\ReflectsClosures; use Illuminate\Support\ViewErrorBag; diff --git a/src/Illuminate/View/Engines/CompilerEngine.php b/src/Illuminate/View/Engines/CompilerEngine.php index d711fc670336..dca6a8710560 100755 --- a/src/Illuminate/View/Engines/CompilerEngine.php +++ b/src/Illuminate/View/Engines/CompilerEngine.php @@ -2,9 +2,9 @@ namespace Illuminate\View\Engines; -use ErrorException; use Illuminate\Filesystem\Filesystem; use Illuminate\View\Compilers\CompilerInterface; +use Illuminate\View\ViewException; use Throwable; class CompilerEngine extends PhpEngine @@ -76,7 +76,7 @@ public function get($path, array $data = []) */ protected function handleViewException(Throwable $e, $obLevel) { - $e = new ErrorException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e); + $e = new ViewException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e); parent::handleViewException($e, $obLevel); } diff --git a/src/Illuminate/View/ViewException.php b/src/Illuminate/View/ViewException.php new file mode 100644 index 000000000000..447c89bc7de5 --- /dev/null +++ b/src/Illuminate/View/ViewException.php @@ -0,0 +1,37 @@ +getPrevious(); + + if ($exception && method_exists('report', $exception)) { + $exception->report(); + } + } + + /** + * Render the exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function render($request) + { + $exception = $this->getPrevious(); + + if ($exception && method_exists($exception, 'render')) { + return $exception->render($request); + } + } +} diff --git a/tests/Integration/View/RenderableViewExceptionTest.php b/tests/Integration/View/RenderableViewExceptionTest.php new file mode 100644 index 000000000000..93c91cb31387 --- /dev/null +++ b/tests/Integration/View/RenderableViewExceptionTest.php @@ -0,0 +1,36 @@ +get('/'); + + $response->assertSee('This is a renderable exception.'); + } + + protected function getEnvironmentSetUp($app) + { + $app['config']->set('view.paths', [__DIR__.'/templates']); + } +} + +class RenderableException extends Exception +{ + public function render($request) + { + return new Response('This is a renderable exception.'); + } +} diff --git a/tests/Integration/View/templates/renderable-exception.blade.php b/tests/Integration/View/templates/renderable-exception.blade.php new file mode 100644 index 000000000000..28649eefa7f9 --- /dev/null +++ b/tests/Integration/View/templates/renderable-exception.blade.php @@ -0,0 +1,3 @@ +@php + throw new Illuminate\Tests\Integration\View\RenderableException; +@endphp diff --git a/tests/View/fixtures/nested/basic.php b/tests/View/fixtures/nested/basic.php index 557db03de997..e69de29bb2d1 100755 --- a/tests/View/fixtures/nested/basic.php +++ b/tests/View/fixtures/nested/basic.php @@ -1 +0,0 @@ -Hello World From e5f217135464a7de2b11d6e11ca7e5940678ecf9 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 09:32:30 -0600 Subject: [PATCH 130/443] Fix styling issue --- src/Illuminate/Routing/Router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 376bb35e6801..c46f2c9e5e05 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -671,7 +671,7 @@ protected function runRoute(Request $request, Route $route) $this->runRouteWithinStack($route, $request) ); } catch (ModelNotFoundException $exception) { - if($route->getElse()) { + if ($route->getElse()) { return $route->getElse(); } From 0ea96b4394a8a5a1da2556197186a450c9ba6314 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 25 Jan 2021 17:42:59 +0200 Subject: [PATCH 131/443] accept a command in object form in Bus::assertChained (#36031) --- src/Illuminate/Support/Testing/Fakes/BusFake.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index 31a08d3548b0..21db27517619 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -200,6 +200,8 @@ public function assertChained(array $expectedChain) if ($command instanceof Closure) { [$command, $callback] = [$this->firstClosureParameterType($command), $command]; + } elseif (! is_string($command)) { + $command = get_class($command); } PHPUnit::assertTrue( From e72027960fd4d8ff281938edb4632e13e391b8fd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 25 Jan 2021 10:14:08 -0600 Subject: [PATCH 132/443] fix bus fake --- .../Support/Testing/Fakes/BusFake.php | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index 21db27517619..f9ef5d4cd68c 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -201,7 +201,13 @@ public function assertChained(array $expectedChain) if ($command instanceof Closure) { [$command, $callback] = [$this->firstClosureParameterType($command), $command]; } elseif (! is_string($command)) { - $command = get_class($command); + $instance = $command; + + $command = get_class($instance); + + $callback = function ($job) use ($instance) { + return serialize($this->resetChainPropertiesToDefaults($job)) === serialize($instance); + }; } PHPUnit::assertTrue( @@ -219,6 +225,22 @@ public function assertChained(array $expectedChain) : $this->assertDispatchedWithChainOfClasses($command, $expectedChain, $callback); } + /** + * Reset the chain properties to their default values on the job. + * + * @param mixed $job + * @return mixed + */ + protected function resetChainPropertiesToDefaults($job) + { + return tap(clone $job, function ($job) { + $job->chainConnection = null; + $job->chainQueue = null; + $job->chainCatchCallbacks = null; + $job->chained = []; + }); + } + /** * Assert if a job was dispatched with an empty chain based on a truth-test callback. * From 958386afda9f62e3a66f8f8c2569d0dc651a8e24 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Mon, 25 Jan 2021 16:19:43 +0000 Subject: [PATCH 133/443] [8.x] Adds parallel testing (#36034) * Adds parallel testing * Adds paratest to testing component's "suggest" section --- composer.json | 1 + src/Illuminate/Database/Schema/Builder.php | 22 ++ .../Database/Schema/Grammars/Grammar.php | 24 ++ .../Database/Schema/Grammars/MySqlGrammar.php | 31 +++ .../Schema/Grammars/PostgresGrammar.php | 30 +++ .../Schema/Grammars/SqlServerGrammar.php | 29 ++ .../Database/Schema/MySqlBuilder.php | 26 ++ .../Database/Schema/PostgresBuilder.php | 26 ++ .../Database/Schema/SQLiteBuilder.php | 26 ++ .../Database/Schema/SqlServerBuilder.php | 26 ++ .../Providers/FoundationServiceProvider.php | 2 + .../Foundation/Testing/TestCase.php | 5 + .../Support/Facades/ParallelTesting.php | 25 ++ src/Illuminate/Support/Facades/Schema.php | 2 + src/Illuminate/Support/Facades/Storage.php | 10 +- .../Testing/Concerns/TestDatabases.php | 162 +++++++++++ .../Testing/ParallelConsoleOutput.php | 60 +++++ src/Illuminate/Testing/ParallelRunner.php | 140 ++++++++++ src/Illuminate/Testing/ParallelTesting.php | 255 ++++++++++++++++++ .../ParallelTestingServiceProvider.php | 38 +++ src/Illuminate/Testing/composer.json | 1 + .../DatabaseAbstractSchemaGrammarTest.php | 37 +++ tests/Database/DatabaseMySqlBuilderTest.php | 48 ++++ .../DatabaseMySqlSchemaGrammarTest.php | 42 +++ .../Database/DatabasePostgresBuilderTest.php | 52 ++++ .../DatabasePostgresSchemaGrammarTest.php | 38 +++ tests/Database/DatabaseSQLiteBuilderTest.php | 91 +++++++ tests/Database/DatabaseSchemaBuilderTest.php | 27 ++ .../DatabaseSqlServerSchemaGrammarTest.php | 36 +++ tests/Database/SqlServerBuilderTest.php | 46 ++++ tests/Testing/ParallelConsoleOutputTest.php | 25 ++ tests/Testing/ParallelTestingTest.php | 99 +++++++ 32 files changed, 1479 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Support/Facades/ParallelTesting.php create mode 100644 src/Illuminate/Testing/Concerns/TestDatabases.php create mode 100644 src/Illuminate/Testing/ParallelConsoleOutput.php create mode 100644 src/Illuminate/Testing/ParallelRunner.php create mode 100644 src/Illuminate/Testing/ParallelTesting.php create mode 100644 src/Illuminate/Testing/ParallelTestingServiceProvider.php create mode 100755 tests/Database/DatabaseAbstractSchemaGrammarTest.php create mode 100644 tests/Database/DatabaseMySqlBuilderTest.php create mode 100644 tests/Database/DatabasePostgresBuilderTest.php create mode 100644 tests/Database/DatabaseSQLiteBuilderTest.php create mode 100644 tests/Database/SqlServerBuilderTest.php create mode 100644 tests/Testing/ParallelConsoleOutputTest.php create mode 100644 tests/Testing/ParallelTestingTest.php diff --git a/composer.json b/composer.json index 581d0ead203b..df3e46d1e1ae 100644 --- a/composer.json +++ b/composer.json @@ -129,6 +129,7 @@ "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", + "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "filp/whoops": "Required for friendly error pages in development (^2.8).", "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 80611bfc92ed..04f96e43308a 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -94,6 +94,28 @@ public static function morphUsingUuids() return static::defaultMorphKeyType('uuid'); } + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + throw new LogicException('This database driver does not support creating databases.'); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + throw new LogicException('This database driver does not support dropping databases.'); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index b60dfe817b62..18071b2fbb12 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -9,6 +9,7 @@ use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; +use LogicException; use RuntimeException; abstract class Grammar extends BaseGrammar @@ -27,6 +28,29 @@ abstract class Grammar extends BaseGrammar */ protected $fluentCommands = []; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + throw new LogicException('This database driver does not support creating databases.'); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + throw new LogicException('This database driver does not support dropping databases.'); + } + /** * Compile a rename column command. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index c2952e47926c..ecaf96e2a3a1 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -26,6 +26,37 @@ class MySqlGrammar extends Grammar */ protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger']; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + return sprintf( + 'create database %s default character set %s default collate %s', + $this->wrapValue($name), + $this->wrapValue($connection->getConfig('charset')), + $this->wrapValue($connection->getConfig('collation')), + ); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + return sprintf( + 'drop database if exists %s', + $this->wrapValue($name) + ); + } + /** * Compile the query to determine the list of tables. * diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 204beecea3b2..16737493f9e1 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -35,6 +35,36 @@ class PostgresGrammar extends Grammar */ protected $fluentCommands = ['Comment']; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + return sprintf( + 'create database %s encoding %s', + $this->wrapValue($name), + $this->wrapValue($connection->getConfig('charset')), + ); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + return sprintf( + 'drop database if exists %s', + $this->wrapValue($name) + ); + } + /** * Compile the query to determine if a table exists. * diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 79f3f0f5e3ad..c3fc442e2368 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -28,6 +28,35 @@ class SqlServerGrammar extends Grammar */ protected $serials = ['tinyInteger', 'smallInteger', 'mediumInteger', 'integer', 'bigInteger']; + /** + * Compile a create database command. + * + * @param string $name + * @param \Illuminate\Database\Connection $connection + * @return string + */ + public function compileCreateDatabase($name, $connection) + { + return sprintf( + 'create database %s', + $this->wrapValue($name), + ); + } + + /** + * Compile a drop database if exists command. + * + * @param string $name + * @return string + */ + public function compileDropDatabaseIfExists($name) + { + return sprintf( + 'drop database if exists %s', + $this->wrapValue($name) + ); + } + /** * Compile the query to determine if a table exists. * diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index f07946c85e23..b7cff5568d1b 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -4,6 +4,32 @@ class MySqlBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name, $this->connection) + ); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 76673a719a41..82702a802691 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -4,6 +4,32 @@ class PostgresBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name, $this->connection) + ); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 78b6b9c78d2e..6a1dbae23ec6 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -2,8 +2,34 @@ namespace Illuminate\Database\Schema; +use Illuminate\Support\Facades\File; + class SQLiteBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return File::put($name, '') !== false; + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return File::exists($name) + ? File::delete($name) + : true; + } + /** * Drop all tables from the database. * diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index 0b3e47bec9a6..223abd44ed1c 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -4,6 +4,32 @@ class SqlServerBuilder extends Builder { + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + */ + public function createDatabase($name) + { + return $this->connection->statement( + $this->grammar->compileCreateDatabase($name, $this->connection) + ); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + */ + public function dropDatabaseIfExists($name) + { + return $this->connection->statement( + $this->grammar->compileDropDatabaseIfExists($name) + ); + } + /** * Drop all tables from the database. * diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index 2f39afd43d36..f5ffb33658f5 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Illuminate\Support\AggregateServiceProvider; use Illuminate\Support\Facades\URL; +use Illuminate\Testing\ParallelTestingServiceProvider; use Illuminate\Validation\ValidationException; class FoundationServiceProvider extends AggregateServiceProvider @@ -16,6 +17,7 @@ class FoundationServiceProvider extends AggregateServiceProvider */ protected $providers = [ FormRequestServiceProvider::class, + ParallelTestingServiceProvider::class, ]; /** diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index b32202517ceb..6bbc653102da 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -7,6 +7,7 @@ use Illuminate\Console\Application as Artisan; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Facade; +use Illuminate\Support\Facades\ParallelTesting; use Illuminate\Support\Str; use Mockery; use Mockery\Exception\InvalidCountException; @@ -81,6 +82,8 @@ protected function setUp(): void if (! $this->app) { $this->refreshApplication(); + + ParallelTesting::callSetUpTestCaseCallbacks($this); } $this->setUpTraits(); @@ -152,6 +155,8 @@ protected function tearDown(): void if ($this->app) { $this->callBeforeApplicationDestroyedCallbacks(); + ParallelTesting::callTearDownTestCaseCallbacks($this); + $this->app->flush(); $this->app = null; diff --git a/src/Illuminate/Support/Facades/ParallelTesting.php b/src/Illuminate/Support/Facades/ParallelTesting.php new file mode 100644 index 000000000000..641f9fe90eae --- /dev/null +++ b/src/Illuminate/Support/Facades/ParallelTesting.php @@ -0,0 +1,25 @@ +get('filesystems.default'); - (new Filesystem)->cleanDirectory( - $root = storage_path('framework/testing/disks/'.$disk) - ); + $root = storage_path('framework/testing/disks/'.$disk); + + if ($token = ParallelTesting::token()) { + $root = "{$root}_test_{$token}"; + } + + (new Filesystem)->cleanDirectory($root); static::set($disk, $fake = static::createLocalDriver(array_merge($config, [ 'root' => $root, diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php new file mode 100644 index 000000000000..5da0b81bd73e --- /dev/null +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -0,0 +1,162 @@ +whenNotUsingInMemoryDatabase(function ($database) { + if (ParallelTesting::option('recreate_databases')) { + Schema::dropDatabaseIfExists( + $this->testDatabase($database) + ); + } + }); + }); + + ParallelTesting::setUpTestCase(function ($testCase) { + $uses = array_flip(class_uses_recursive(get_class($testCase))); + + $databaseTraits = [ + Testing\DatabaseMigrations::class, + Testing\DatabaseTransactions::class, + Testing\RefreshDatabase::class, + ]; + + if (Arr::hasAny($uses, $databaseTraits)) { + $this->whenNotUsingInMemoryDatabase(function ($database) use ($uses) { + $testDatabase = $this->ensureTestDatabaseExists($database); + + $this->switchToDatabase($testDatabase); + + if (isset($uses[Testing\DatabaseTransactions::class])) { + $this->ensureSchemaIsUpToDate(); + } + }); + } + }); + } + + /** + * Ensure a test database exists and returns its name. + * + * @param string $database + * + * @return string + */ + protected function ensureTestDatabaseExists($database) + { + return tap($this->testDatabase($database), function ($testDatabase) use ($database) { + try { + $this->usingDatabase($testDatabase, function () { + Schema::hasTable('dummy'); + }); + } catch (QueryException $e) { + $this->usingDatabase($database, function () use ($testDatabase) { + Schema::dropDatabaseIfExists($testDatabase); + Schema::createDatabase($testDatabase); + }); + } + }); + } + + /** + * Ensure the current database test schema is up to date. + * + * @return void + */ + protected function ensureSchemaIsUpToDate() + { + if (! static::$schemaIsUpToDate) { + Artisan::call('migrate'); + + static::$schemaIsUpToDate = true; + } + } + + /** + * Runs the given callable using the given database. + * + * @param string $database + * @param callable $database + * @return void + */ + protected function usingDatabase($database, $callable) + { + $original = DB::getConfig('database'); + + try { + $this->switchToDatabase($database); + $callable(); + } finally { + $this->switchToDatabase($original); + } + } + + /** + * Apply the given callback when tests are not using in memory database. + * + * @param callable $callback + * @return void + */ + protected function whenNotUsingInMemoryDatabase($callback) + { + $database = DB::getConfig('database'); + + if ($database != ':memory:') { + $callback($database); + } + } + + /** + * Switch to the given database. + * + * @param string $database + * @return void + */ + protected function switchToDatabase($database) + { + DB::purge(); + + $default = config('database.default'); + + config()->set( + "database.connections.{$default}.database", + $database, + ); + } + + /** + * Returns the test database name. + * + * @return string + */ + protected function testDatabase($database) + { + $token = ParallelTesting::token(); + + return "{$database}_test_{$token}"; + } +} diff --git a/src/Illuminate/Testing/ParallelConsoleOutput.php b/src/Illuminate/Testing/ParallelConsoleOutput.php new file mode 100644 index 000000000000..7444be3b92d7 --- /dev/null +++ b/src/Illuminate/Testing/ParallelConsoleOutput.php @@ -0,0 +1,60 @@ +getVerbosity(), + $output->isDecorated(), + $output->getFormatter(), + ); + + $this->output = $output; + } + + /** + * Writes a message to the output. + * + * @param string|iterable $messages + * @param bool $newline + * @param int $options + * @return void + */ + public function write($messages, bool $newline = false, int $options = 0) + { + $messages = collect($messages)->filter(function ($message) { + return ! Str::contains($message, $this->ignore); + }); + + $this->output->write($messages->toArray(), $newline, $options); + } +} diff --git a/src/Illuminate/Testing/ParallelRunner.php b/src/Illuminate/Testing/ParallelRunner.php new file mode 100644 index 000000000000..e26528703bbe --- /dev/null +++ b/src/Illuminate/Testing/ParallelRunner.php @@ -0,0 +1,140 @@ +options = $options; + + if ($output instanceof ConsoleOutput) { + $output = new ParallelConsoleOutput($output); + } + + $this->runner = new WrapperRunner($options, $output); + } + + /** + * Set the application resolver callback. + * + * @param \Closure|null $resolver + * @return void + */ + public static function resolveApplicationUsing($resolver) + { + static::$applicationResolver = $resolver; + } + + /** + * Runs the test suite. + * + * @return void + */ + public function run(): void + { + (new PhpHandler)->handle($this->options->configuration()->php()); + + $this->forEachProcess(function () { + ParallelTesting::callSetUpProcessCallbacks(); + }); + + try { + $this->runner->run(); + } finally { + $this->forEachProcess(function () { + ParallelTesting::callTearDownProcessCallbacks(); + }); + } + } + + /** + * Returns the highest exit code encountered throughout the course of test execution. + * + * @return int + */ + public function getExitCode(): int + { + return $this->runner->getExitCode(); + } + + /** + * Apply the given callback for each process. + * + * @param callable $callback + * @return void + */ + protected function forEachProcess($callback) + { + collect(range(1, $this->options->processes()))->each(function ($token) use ($callback) { + tap($this->createApplication(), function ($app) use ($callback, $token) { + ParallelTesting::resolveTokenUsing(function () use ($token) { + return $token; + }); + + $callback($app); + })->flush(); + }); + } + + /** + * Creates the application. + * + * @return \Illuminate\Contracts\Foundation\Application + */ + protected function createApplication() + { + $applicationResolver = static::$applicationResolver ?: function () { + $applicationCreator = new class { + use \Tests\CreatesApplication; + }; + + return $applicationCreator->createApplication(); + }; + + return call_user_func($applicationResolver); + } +} diff --git a/src/Illuminate/Testing/ParallelTesting.php b/src/Illuminate/Testing/ParallelTesting.php new file mode 100644 index 000000000000..ba67e16c5c74 --- /dev/null +++ b/src/Illuminate/Testing/ParallelTesting.php @@ -0,0 +1,255 @@ +container = $container; + } + + /** + * Set a callback that should be used when resolving options. + * + * @param \Closure|null $callback + * @return void + */ + public function resolveOptionsUsing($resolver) + { + $this->optionsResolver = $resolver; + } + + /** + * Set a callback that should be used when resolving the unique process token. + * + * @param \Closure|null $callback + * @return void + */ + public function resolveTokenUsing($resolver) + { + $this->tokenResolver = $resolver; + } + + /** + * Register a "setUp" process callback. + * + * @param callable $callback + * @return void + */ + public function setUpProcess($callback) + { + $this->setUpProcessCallbacks[] = $callback; + } + + /** + * Register a "setUp" test case callback. + * + * @param callable $callback + * @return void + */ + public function setUpTestCase($callback) + { + $this->setUpTestCaseCallbacks[] = $callback; + } + + /** + * Register a "tearDown" process callback. + * + * @param callable $callback + * @return void + */ + public function tearDownProcess($callback) + { + $this->tearDownProcessCallbacks[] = $callback; + } + + /** + * Register a "tearDown" test case callback. + * + * @param callable $callback + * @return void + */ + public function tearDownTestCase($callback) + { + $this->tearDownTestCaseCallbacks[] = $callback; + } + + /** + * Call all of the "setUp" process callbacks. + * + * @return void + */ + public function callSetUpProcessCallbacks() + { + $this->whenRunningInParallel(function () { + foreach ($this->setUpProcessCallbacks as $callback) { + $this->container->call($callback, [ + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Call all of the "setUp" test case callbacks. + * + * @param \Illuminate\Foundation\Testing\TestCase $testCase + * @return void + */ + public function callSetUpTestCaseCallbacks($testCase) + { + $this->whenRunningInParallel(function () use ($testCase) { + foreach ($this->setUpTestCaseCallbacks as $callback) { + $this->container->call($callback, [ + 'testCase' => $testCase, + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Call all of the "tearDown" process callbacks. + * + * @return void + */ + public function callTearDownProcessCallbacks() + { + $this->whenRunningInParallel(function () { + foreach ($this->tearDownProcessCallbacks as $callback) { + $this->container->call($callback, [ + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Call all of the "tearDown" test case callbacks. + * + * @param \Illuminate\Foundation\Testing\TestCase $testCase + * @return void + */ + public function callTearDownTestCaseCallbacks($testCase) + { + $this->whenRunningInParallel(function () use ($testCase) { + foreach ($this->tearDownTestCaseCallbacks as $callback) { + $this->container->call($callback, [ + 'testCase' => $testCase, + 'token' => $this->token(), + ]); + } + }); + } + + /** + * Get an parallel testing option. + * + * @param string $option + * @return mixed + */ + public function option($option) + { + $optionsResolver = $this->optionsResolver ?: function ($option) { + $option = 'LARAVEL_PARALLEL_TESTING_'.Str::upper($option); + + return $_SERVER[$option] ?? false; + }; + + return call_user_func($optionsResolver, $option); + } + + /** + * Gets an unique test token. + * + * @return int|false + */ + public function token() + { + return $token = $this->tokenResolver + ? call_user_func($this->tokenResolver) + : ($_SERVER['TEST_TOKEN'] ?? false); + } + + /** + * Apply the callback if tests are running in parallel. + * + * @param callable $callback + * @return void + */ + protected function whenRunningInParallel($callback) + { + if ($this->inParallel()) { + $callback(); + } + } + + /** + * Indicates if the current tests are been run in parallel. + * + * @return bool + */ + protected function inParallel() + { + return ! empty($_SERVER['LARAVEL_PARALLEL_TESTING']) && $this->token(); + } +} diff --git a/src/Illuminate/Testing/ParallelTestingServiceProvider.php b/src/Illuminate/Testing/ParallelTestingServiceProvider.php new file mode 100644 index 000000000000..20b900d2e58e --- /dev/null +++ b/src/Illuminate/Testing/ParallelTestingServiceProvider.php @@ -0,0 +1,38 @@ +app->runningInConsole()) { + $this->bootTestDatabase(); + } + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + if ($this->app->runningInConsole()) { + $this->app->singleton(ParallelTesting::class, function () { + return new ParallelTesting($this->app); + }); + } + } +} diff --git a/src/Illuminate/Testing/composer.json b/src/Illuminate/Testing/composer.json index 9b15533bd7c8..2dfe3b64eac3 100644 --- a/src/Illuminate/Testing/composer.json +++ b/src/Illuminate/Testing/composer.json @@ -31,6 +31,7 @@ } }, "suggest": { + "brianium/paratest": "Required to run tests in parallel (^6.0).", "illuminate/console": "Required to assert console commands (^8.0).", "illuminate/database": "Required to assert databases (^8.0).", "illuminate/http": "Required to assert responses (^8.0).", diff --git a/tests/Database/DatabaseAbstractSchemaGrammarTest.php b/tests/Database/DatabaseAbstractSchemaGrammarTest.php new file mode 100755 index 000000000000..04e23eb264be --- /dev/null +++ b/tests/Database/DatabaseAbstractSchemaGrammarTest.php @@ -0,0 +1,37 @@ +expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support creating databases.'); + + $grammar->compileCreateDatabase('foo', m::mock(Connection::class)); + } + + public function testDropDatabaseIfExists() + { + $grammar = new class extends Grammar {}; + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support dropping databases.'); + + $grammar->compileDropDatabaseIfExists('foo'); + } +} diff --git a/tests/Database/DatabaseMySqlBuilderTest.php b/tests/Database/DatabaseMySqlBuilderTest.php new file mode 100644 index 000000000000..dd36209eb40e --- /dev/null +++ b/tests/Database/DatabaseMySqlBuilderTest.php @@ -0,0 +1,48 @@ +shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); + $connection->shouldReceive('getConfig')->once()->with('collation')->andReturn('utf8mb4_unicode_ci'); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database `my_temporary_database` default character set `utf8mb4` default collate `utf8mb4_unicode_ci`' + )->andReturn(true); + + $builder = new MySqlBuilder($connection); + $builder->createDatabase('my_temporary_database'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new MySqlGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists `my_database_a`' + )->andReturn(true); + + $builder = new MySqlBuilder($connection); + + $builder->dropDatabaseIfExists('my_database_a'); + } +} diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index c89af64847ad..d35d8ab91792 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -1155,6 +1155,48 @@ public function testGrammarsAreMacroable() $this->assertTrue($c); } + public function testCreateDatabase() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8mb4_foo'); + $connection->shouldReceive('getConfig')->once()->once()->with('collation')->andReturn('utf8mb4_unicode_ci_foo'); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + + $this->assertSame( + 'create database `my_database_a` default character set `utf8mb4_foo` default collate `utf8mb4_unicode_ci_foo`', + $statement + ); + + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8mb4_bar'); + $connection->shouldReceive('getConfig')->once()->once()->with('collation')->andReturn('utf8mb4_unicode_ci_bar'); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + + $this->assertSame( + 'create database `my_database_b` default character set `utf8mb4_bar` default collate `utf8mb4_unicode_ci_bar`', + $statement + ); + } + + public function testDropDatabaseIfExists() + { + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); + + $this->assertSame( + 'drop database if exists `my_database_a`', + $statement + ); + + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); + + $this->assertSame( + 'drop database if exists `my_database_b`', + $statement + ); + } + protected function getConnection() { return m::mock(Connection::class); diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php new file mode 100644 index 000000000000..490f66cb4ad8 --- /dev/null +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -0,0 +1,52 @@ +shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database "my_temporary_database" encoding "utf8"' + )->andReturn(true); + + $builder = $this->getBuilder($connection); + $builder->createDatabase('my_temporary_database'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new PostgresGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists "my_database_a"' + )->andReturn(true); + + $builder = $this->getBuilder($connection); + + $builder->dropDatabaseIfExists('my_database_a'); + } + + protected function getBuilder($connection) + { + return new PostgresBuilder($connection); + } +} diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 052197fd08c4..3a7f80ae3865 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -977,6 +977,44 @@ public function testAddingMultiPolygon() $this->assertSame('alter table "geo" add column "coordinates" geography(multipolygon, 4326) not null', $statements[0]); } + public function testCreateDatabase() + { + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8_foo'); + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + + $this->assertSame( + 'create database "my_database_a" encoding "utf8_foo"', + $statement + ); + + $connection = $this->getConnection(); + $connection->shouldReceive('getConfig')->once()->once()->with('charset')->andReturn('utf8_bar'); + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + + $this->assertSame( + 'create database "my_database_b" encoding "utf8_bar"', + $statement + ); + } + + public function testDropDatabaseIfExists() + { + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); + + $this->assertSame( + 'drop database if exists "my_database_a"', + $statement + ); + + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); + + $this->assertSame( + 'drop database if exists "my_database_b"', + $statement + ); + } + public function testDropAllTablesEscapesTableNames() { $statement = $this->getGrammar()->compileDropAllTables(['alpha', 'beta', 'gamma']); diff --git a/tests/Database/DatabaseSQLiteBuilderTest.php b/tests/Database/DatabaseSQLiteBuilderTest.php new file mode 100644 index 000000000000..b2587ea67d82 --- /dev/null +++ b/tests/Database/DatabaseSQLiteBuilderTest.php @@ -0,0 +1,91 @@ +singleton('files', Filesystem::class); + + Facade::setFacadeApplication($app); + } + + protected function tearDown(): void + { + m::close(); + + Container::setInstance(null); + Facade::setFacadeApplication(null); + } + + public function testCreateDatabase() + { + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once(); + + $builder = new SQLiteBuilder($connection); + + File::shouldReceive('put') + ->once() + ->with('my_temporary_database_a', '') + ->andReturn(20); // bytes + + $this->assertTrue($builder->createDatabase('my_temporary_database_a')); + + File::shouldReceive('put') + ->once() + ->with('my_temporary_database_b', '') + ->andReturn(false); + + $this->assertFalse($builder->createDatabase('my_temporary_database_b')); + } + + public function testDropDatabaseIfExists() + { + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once(); + + $builder = new SQLiteBuilder($connection); + + File::shouldReceive('exists') + ->once() + ->andReturn(true); + + File::shouldReceive('delete') + ->once() + ->with('my_temporary_database_b') + ->andReturn(true); + + $this->assertTrue($builder->dropDatabaseIfExists('my_temporary_database_b')); + + File::shouldReceive('exists') + ->once() + ->andReturn(false); + + $this->assertTrue($builder->dropDatabaseIfExists('my_temporary_database_c')); + + File::shouldReceive('exists') + ->once() + ->andReturn(true); + + File::shouldReceive('delete') + ->once() + ->with('my_temporary_database_c') + ->andReturn(false); + + $this->assertFalse($builder->dropDatabaseIfExists('my_temporary_database_c')); + } +} diff --git a/tests/Database/DatabaseSchemaBuilderTest.php b/tests/Database/DatabaseSchemaBuilderTest.php index 53a13c79128c..b22bfd7dc70e 100755 --- a/tests/Database/DatabaseSchemaBuilderTest.php +++ b/tests/Database/DatabaseSchemaBuilderTest.php @@ -4,6 +4,7 @@ use Illuminate\Database\Connection; use Illuminate\Database\Schema\Builder; +use LogicException; use Mockery as m; use PHPUnit\Framework\TestCase; use stdClass; @@ -15,6 +16,32 @@ protected function tearDown(): void m::close(); } + public function testCreateDatabase() + { + $connection = m::mock(Connection::class); + $grammar = m::mock(stdClass::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $builder = new Builder($connection); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support creating databases.'); + + $builder->createDatabase('foo'); + } + + public function testDropDatabaseIfExists() + { + $connection = m::mock(Connection::class); + $grammar = m::mock(stdClass::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $builder = new Builder($connection); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('This database driver does not support dropping databases.'); + + $builder->dropDatabaseIfExists('foo'); + } + public function testHasTableCorrectlyCallsGrammar() { $connection = m::mock(Connection::class); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 5ca3790522ab..72a072592b1a 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -894,6 +894,42 @@ public function testQuoteStringOnArray() $this->assertSame("N'中文', N'測試'", $this->getGrammar()->quoteString(['中文', '測試'])); } + public function testCreateDatabase() + { + $connection = $this->getConnection(); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_a', $connection); + + $this->assertSame( + 'create database "my_database_a"', + $statement + ); + + $statement = $this->getGrammar()->compileCreateDatabase('my_database_b', $connection); + + $this->assertSame( + 'create database "my_database_b"', + $statement + ); + } + + public function testDropDatabaseIfExists() + { + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_a'); + + $this->assertSame( + 'drop database if exists "my_database_a"', + $statement + ); + + $statement = $this->getGrammar()->compileDropDatabaseIfExists('my_database_b'); + + $this->assertSame( + 'drop database if exists "my_database_b"', + $statement + ); + } + protected function getConnection() { return m::mock(Connection::class); diff --git a/tests/Database/SqlServerBuilderTest.php b/tests/Database/SqlServerBuilderTest.php new file mode 100644 index 000000000000..de82f796056c --- /dev/null +++ b/tests/Database/SqlServerBuilderTest.php @@ -0,0 +1,46 @@ +shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'create database "my_temporary_database_a"' + )->andReturn(true); + + $builder = new SqlServerBuilder($connection); + $builder->createDatabase('my_temporary_database_a'); + } + + public function testDropDatabaseIfExists() + { + $grammar = new SqlServerGrammar(); + + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); + $connection->shouldReceive('statement')->once()->with( + 'drop database if exists "my_temporary_database_b"' + )->andReturn(true); + + $builder = new SqlServerBuilder($connection); + + $builder->dropDatabaseIfExists('my_temporary_database_b'); + } +} diff --git a/tests/Testing/ParallelConsoleOutputTest.php b/tests/Testing/ParallelConsoleOutputTest.php new file mode 100644 index 000000000000..130b6ecada6a --- /dev/null +++ b/tests/Testing/ParallelConsoleOutputTest.php @@ -0,0 +1,25 @@ +write('Running phpunit in 12 processes with laravel/laravel.'); + $this->assertEmpty($original->fetch()); + + $output->write('Configuration read from phpunit.xml.dist'); + $this->assertEmpty($original->fetch()); + + $output->write('... 3/3 (100%)'); + $this->assertSame('... 3/3 (100%)', $original->fetch()); + } +} diff --git a/tests/Testing/ParallelTestingTest.php b/tests/Testing/ParallelTestingTest.php new file mode 100644 index 000000000000..25d41f7f1b5c --- /dev/null +++ b/tests/Testing/ParallelTestingTest.php @@ -0,0 +1,99 @@ +{$caller}($this); + $this->assertFalse($state); + + $parallelTesting->{$callback}(function ($token, $testCase = null) use ($callback, &$state) { + if (in_array($callback, ['setUpTestCase', 'tearDownTestCase'])) { + $this->assertSame($this, $testCase); + } else { + $this->assertNull($testCase); + } + + $this->assertEquals(1, $token); + $state = true; + }); + + $parallelTesting->{$caller}($this); + $this->assertFalse($state); + + $parallelTesting->resolveTokenUsing(function () { + return 1; + }); + + $parallelTesting->{$caller}($this); + $this->assertTrue($state); + } + + public function testOptions() + { + $parallelTesting = new ParallelTesting(Container::getInstance()); + + $this->assertFalse($parallelTesting->option('recreate_databases')); + + $parallelTesting->resolveOptionsUsing(function ($option) { + return $option == 'recreate_databases'; + }); + + $this->assertFalse($parallelTesting->option('recreate_caches')); + $this->assertTrue($parallelTesting->option('recreate_databases')); + } + + public function testToken() + { + $parallelTesting = new ParallelTesting(Container::getInstance()); + + $this->assertFalse($parallelTesting->token()); + + $parallelTesting->resolveTokenUsing(function () { + return 1; + }); + + $this->assertSame(1, $parallelTesting->token()); + } + + public function callbacks() + { + return [ + ['setUpProcess'], + ['setUpTestCase'], + ['tearDownTestCase'], + ['tearDownProcess'], + ]; + } + + public function tearDown(): void + { + parent::tearDown(); + + Container::setInstance(null); + + unset($_SERVER['LARAVEL_PARALLEL_TESTING']); + } +} From 6e79268aa8b0d242ab78a54bce304f0cc7735876 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 25 Jan 2021 16:20:15 +0000 Subject: [PATCH 134/443] Fix PHP 8.0 showing as 8 (#36039) --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d2a186904407..19e95cff1f99 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: true matrix: - php: [7.2, 7.3, 7.4, 8.0] + php: ['7.2', '7.3', '7.4', '8.0'] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} @@ -78,7 +78,7 @@ jobs: strategy: fail-fast: true matrix: - php: [7.2, 7.3, 7.4, 8.0] + php: ['7.2', '7.3', '7.4', '8.0'] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - Windows From 14b8f794fca23575fbfb076c44eecaad1b9979c3 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 10:22:26 -0600 Subject: [PATCH 135/443] Update method name to "missing", accepts callbcak --- src/Illuminate/Routing/Route.php | 16 ++++++++-------- src/Illuminate/Routing/Router.php | 4 ++-- tests/Routing/RoutingRouteTest.php | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index bfa7a549d1d4..00323d6b417a 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -934,24 +934,24 @@ public function setAction(array $action) } /** - * Get the value of the else redirect. + * Get the value of the missing redirect. * - * @return \Illuminate\Http\RedirectResponse|null + * @return \Closure|null */ - public function getElse() + public function getMissing() { - return $this->action['else'] ?? null; + return $this->action['missing'] ?? null; } /** - * Add or change the else redirect. + * Add or change the missing redirect. * - * @param \Illuminate\Http\RedirectResponse $else + * @param \Closure $missing * @return $this */ - public function else($else) + public function missing($missing) { - $this->action['else'] = $else; + $this->action['missing'] = $missing; return $this; } diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c46f2c9e5e05..4c25592a988c 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -671,8 +671,8 @@ protected function runRoute(Request $request, Route $route) $this->runRouteWithinStack($route, $request) ); } catch (ModelNotFoundException $exception) { - if ($route->getElse()) { - return $route->getElse(); + if ($route->getMissing()) { + return $route->getMissing()($request); } throw $exception; diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index dd7c4c92fe36..851d57c472d8 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -1672,10 +1672,8 @@ public function testImplicitBindingsWithOptionalParameterWithExistingKeyInUri() $this->assertSame('taylor', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent()); } - public function testImplicitBindingsWithMissingModelHandledByElse() + public function testImplicitBindingsWithMissingModelHandledByMissing() { - $redirect = new RedirectResponse('/', 302); - $router = $this->getRouter(); $router->get('foo/{bar}', [ 'middleware' => SubstituteBindings::class, @@ -1684,7 +1682,9 @@ public function testImplicitBindingsWithMissingModelHandledByElse() return $bar->first(); }, - ])->else($redirect); + ])->missing(function() { + return new RedirectResponse('/', 302); + }); $request = Request::create('foo/taylor', 'GET'); From 2ff9969e7d659742dbf62d7fc88f07386056d517 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 10:23:17 -0600 Subject: [PATCH 136/443] Update styling --- tests/Routing/RoutingRouteTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index 851d57c472d8..a0d4548dc06e 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -1682,7 +1682,7 @@ public function testImplicitBindingsWithMissingModelHandledByMissing() return $bar->first(); }, - ])->missing(function() { + ])->missing(function () { return new RedirectResponse('/', 302); }); From ff33775e483129abf6d6a88d5152b198845724b7 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 25 Jan 2021 18:24:03 +0200 Subject: [PATCH 137/443] [8.x] Make Listeners, Mailables, and Notifications accept ShouldBeEncrypted (#36036) * accept a command in object form in Bus::assertChained * Revert " accept a command in object form in Bus::assertChained" This reverts commit 137623f34c2afd322a0f990330d805a5b7eab821. * make listeners notifictaions and mailables encryptable in queue * Update Queue.php Co-authored-by: Taylor Otwell --- src/Illuminate/Events/CallQueuedListener.php | 7 +++++++ src/Illuminate/Events/Dispatcher.php | 3 +++ src/Illuminate/Mail/SendQueuedMailable.php | 9 +++++++++ .../Notifications/SendQueuedNotifications.php | 9 +++++++++ src/Illuminate/Queue/Queue.php | 17 ++++++++++++++++- 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Events/CallQueuedListener.php b/src/Illuminate/Events/CallQueuedListener.php index 90ad3d9ac459..9201d858613b 100644 --- a/src/Illuminate/Events/CallQueuedListener.php +++ b/src/Illuminate/Events/CallQueuedListener.php @@ -61,6 +61,13 @@ class CallQueuedListener implements ShouldQueue */ public $timeout; + /** + * Indicates if the job should be encrypted. + * + * @var bool + */ + public $shouldBeEncrypted = false; + /** * Create a new job instance. * diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index dac103348a7d..5959362bc8ce 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -9,6 +9,7 @@ use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Container\Container as ContainerContract; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; +use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Arr; use Illuminate\Support\Str; @@ -600,6 +601,8 @@ protected function propagateListenerOptions($listener, $job) $job->retryUntil = method_exists($listener, 'retryUntil') ? $listener->retryUntil() : null; + + $job->shouldBeEncrypted = $listener instanceof ShouldBeEncrypted; }); } diff --git a/src/Illuminate/Mail/SendQueuedMailable.php b/src/Illuminate/Mail/SendQueuedMailable.php index a4567dadcb4e..99a954750e5b 100644 --- a/src/Illuminate/Mail/SendQueuedMailable.php +++ b/src/Illuminate/Mail/SendQueuedMailable.php @@ -5,6 +5,7 @@ use Illuminate\Bus\Queueable; use Illuminate\Contracts\Mail\Factory as MailFactory; use Illuminate\Contracts\Mail\Mailable as MailableContract; +use Illuminate\Contracts\Queue\ShouldBeEncrypted; class SendQueuedMailable { @@ -31,6 +32,13 @@ class SendQueuedMailable */ public $timeout; + /** + * Indicates if the job should be encrypted. + * + * @var bool + */ + public $shouldBeEncrypted = false; + /** * Create a new job instance. * @@ -43,6 +51,7 @@ public function __construct(MailableContract $mailable) $this->tries = property_exists($mailable, 'tries') ? $mailable->tries : null; $this->timeout = property_exists($mailable, 'timeout') ? $mailable->timeout : null; $this->afterCommit = property_exists($mailable, 'afterCommit') ? $mailable->afterCommit : null; + $this->shouldBeEncrypted = $mailable instanceof ShouldBeEncrypted; } /** diff --git a/src/Illuminate/Notifications/SendQueuedNotifications.php b/src/Illuminate/Notifications/SendQueuedNotifications.php index 2f983023f051..eed7e2204654 100644 --- a/src/Illuminate/Notifications/SendQueuedNotifications.php +++ b/src/Illuminate/Notifications/SendQueuedNotifications.php @@ -3,6 +3,7 @@ namespace Illuminate\Notifications; use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Model; @@ -49,6 +50,13 @@ class SendQueuedNotifications implements ShouldQueue */ public $timeout; + /** + * Indicates if the job should be encrypted. + * + * @var bool + */ + public $shouldBeEncrypted = false; + /** * Create a new job instance. * @@ -65,6 +73,7 @@ public function __construct($notifiables, $notification, array $channels = null) $this->tries = property_exists($notification, 'tries') ? $notification->tries : null; $this->timeout = property_exists($notification, 'timeout') ? $notification->timeout : null; $this->afterCommit = property_exists($notification, 'afterCommit') ? $notification->afterCommit : null; + $this->shouldBeEncrypted = $notification instanceof ShouldBeEncrypted; } /** diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index f036f2a871c5..654d70402899 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -152,7 +152,7 @@ protected function createObjectPayload($job, $queue) ], ]); - $command = $job instanceof ShouldBeEncrypted && $this->container->bound(Encrypter::class) + $command = $this->jobShouldBeEncrypted($job) && $this->container->bound(Encrypter::class) ? $this->container[Encrypter::class]->encrypt(serialize(clone $job)) : serialize(clone $job); @@ -213,6 +213,21 @@ public function getJobExpiration($job) ? $expiration->getTimestamp() : $expiration; } + /** + * Determine if the job should be encrypted. + * + * @param object $job + * @return bool + */ + protected function jobShouldBeEncrypted($job) + { + if ($job instanceof ShouldBeEncrypted) { + return true; + } + + return isset($job->shouldBeEncrypted) && $job->shouldBeEncrypted; + } + /** * Create a typical, string based queue payload array. * From fdf46c336f90b1c7eb94ae6bda4202aa0ea64600 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 25 Jan 2021 18:07:55 +0100 Subject: [PATCH 138/443] [6.x] Backport of Pipe through render and report exception methods (#36037) * Pipe through render and report exception methods (#36032) * Fix method_exists call * Re-add facade --- .../View/Engines/CompilerEngine.php | 4 +- src/Illuminate/View/ViewException.php | 37 +++++++++++++++++++ .../View/RenderableViewExceptionTest.php | 36 ++++++++++++++++++ .../templates/renderable-exception.blade.php | 3 ++ tests/View/fixtures/nested/basic.php | 1 - 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/View/ViewException.php create mode 100644 tests/Integration/View/RenderableViewExceptionTest.php create mode 100644 tests/Integration/View/templates/renderable-exception.blade.php diff --git a/src/Illuminate/View/Engines/CompilerEngine.php b/src/Illuminate/View/Engines/CompilerEngine.php index 03717bad0b51..cf6dac70e8a1 100755 --- a/src/Illuminate/View/Engines/CompilerEngine.php +++ b/src/Illuminate/View/Engines/CompilerEngine.php @@ -2,9 +2,9 @@ namespace Illuminate\View\Engines; -use ErrorException; use Exception; use Illuminate\View\Compilers\CompilerInterface; +use Illuminate\View\ViewException; class CompilerEngine extends PhpEngine { @@ -74,7 +74,7 @@ public function get($path, array $data = []) */ protected function handleViewException(Exception $e, $obLevel) { - $e = new ErrorException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e); + $e = new ViewException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e); parent::handleViewException($e, $obLevel); } diff --git a/src/Illuminate/View/ViewException.php b/src/Illuminate/View/ViewException.php new file mode 100644 index 000000000000..9c9463bc28ac --- /dev/null +++ b/src/Illuminate/View/ViewException.php @@ -0,0 +1,37 @@ +getPrevious(); + + if ($exception && method_exists($exception, 'report')) { + $exception->report(); + } + } + + /** + * Render the exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function render($request) + { + $exception = $this->getPrevious(); + + if ($exception && method_exists($exception, 'render')) { + return $exception->render($request); + } + } +} diff --git a/tests/Integration/View/RenderableViewExceptionTest.php b/tests/Integration/View/RenderableViewExceptionTest.php new file mode 100644 index 000000000000..93c91cb31387 --- /dev/null +++ b/tests/Integration/View/RenderableViewExceptionTest.php @@ -0,0 +1,36 @@ +get('/'); + + $response->assertSee('This is a renderable exception.'); + } + + protected function getEnvironmentSetUp($app) + { + $app['config']->set('view.paths', [__DIR__.'/templates']); + } +} + +class RenderableException extends Exception +{ + public function render($request) + { + return new Response('This is a renderable exception.'); + } +} diff --git a/tests/Integration/View/templates/renderable-exception.blade.php b/tests/Integration/View/templates/renderable-exception.blade.php new file mode 100644 index 000000000000..28649eefa7f9 --- /dev/null +++ b/tests/Integration/View/templates/renderable-exception.blade.php @@ -0,0 +1,3 @@ +@php + throw new Illuminate\Tests\Integration\View\RenderableException; +@endphp diff --git a/tests/View/fixtures/nested/basic.php b/tests/View/fixtures/nested/basic.php index 557db03de997..e69de29bb2d1 100755 --- a/tests/View/fixtures/nested/basic.php +++ b/tests/View/fixtures/nested/basic.php @@ -1 +0,0 @@ -Hello World From f364d7face83deb90b2106cd07e53bcc255de883 Mon Sep 17 00:00:00 2001 From: Jonathan Reinink Date: Mon, 25 Jan 2021 15:54:50 -0500 Subject: [PATCH 139/443] [8.x] Support JSON encoding Stringable (#36012) * Support JSON encoding Stringable * Call __toString() from jsonSerialize() in Stringable class * Update router to properly handle Stringable instances --- src/Illuminate/Routing/Router.php | 3 +++ src/Illuminate/Support/Stringable.php | 13 ++++++++++++- tests/Support/SupportStringableTest.php | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index f1b61dc74dcf..f1912bf0374e 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -18,6 +18,7 @@ use Illuminate\Routing\Events\RouteMatched; use Illuminate\Support\Collection; use Illuminate\Support\Str; +use Illuminate\Support\Stringable; use Illuminate\Support\Traits\Macroable; use JsonSerializable; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; @@ -769,6 +770,8 @@ public static function toResponse($request, $response) $response = (new HttpFoundationFactory)->createResponse($response); } elseif ($response instanceof Model && $response->wasRecentlyCreated) { $response = new JsonResponse($response, 201); + } elseif ($response instanceof Stringable) { + $response = new Response($response->__toString(), 200, ['Content-Type' => 'text/html']); } elseif (! $response instanceof SymfonyResponse && ($response instanceof Arrayable || $response instanceof Jsonable || diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index e945beaf7614..65320e1bcf3f 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -5,9 +5,10 @@ use Closure; use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\Tappable; +use JsonSerializable; use Symfony\Component\VarDumper\VarDumper; -class Stringable +class Stringable implements JsonSerializable { use Macroable, Tappable; @@ -734,6 +735,16 @@ public function dd() exit(1); } + /** + * Convert the object to a string when JSON encoded. + * + * @return string + */ + public function jsonSerialize() + { + return $this->__toString(); + } + /** * Proxy dynamic properties onto methods. * diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 851b2c0617ac..e666b2fff98b 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -546,6 +546,11 @@ public function testChunk() $this->assertSame(['foo', 'bar', 'baz'], $chunks->all()); } + public function testJsonSerialize() + { + $this->assertSame('"foo"', json_encode($this->stringable('foo'))); + } + public function testTap() { $stringable = $this->stringable('foobarbaz'); From 1f8d0f32a66baba85888085321b1863c598d3af4 Mon Sep 17 00:00:00 2001 From: Chris Morrell Date: Mon, 25 Jan 2021 16:00:49 -0500 Subject: [PATCH 140/443] [8.x] Support for escaping bound attributes (#36042) * Support for escaping bound attributes * StyleCI --- src/Illuminate/View/Compilers/ComponentTagCompiler.php | 6 +++++- tests/View/Blade/BladeComponentTagCompilerTest.php | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 9e079ac8a07c..d2f964a88c15 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -460,6 +460,10 @@ protected function getAttributesFromAttributeString(string $attributeString) $value = "'".$this->compileAttributeEchos($value)."'"; } + if (Str::startsWith($attribute, '::')) { + $attribute = substr($attribute, 1); + } + return [$attribute => $value]; })->toArray(); } @@ -490,7 +494,7 @@ protected function parseBindAttributes(string $attributeString) { $pattern = "/ (?:^|\s+) # start of the string or whitespace between attributes - : # attribute needs to start with a semicolon + :(?!:) # attribute needs to start with a single colon ([\w\-:.@]+) # match the actual attribute name = # only match attributes that have a value /xm"; diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index c9b89df6096e..a00744859d45 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -72,6 +72,14 @@ public function testColonData() withAttributes([]); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); } + public function testEscapedColonAttribute() + { + $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); + + $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\Tests\View\Blade\TestProfileComponent', 'profile', ['userId' => 1]) +withAttributes([':title' => 'user.name']); ?> @endComponentClass##END-COMPONENT-CLASS##", trim($result)); + } + public function testColonAttributesIsEscapedIfStrings() { $result = $this->compiler(['profile' => TestProfileComponent::class])->compileTags(''); From e93c478adc5f1524d3dc77fea53a3c4cd34fd79b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 25 Jan 2021 15:14:10 -0600 Subject: [PATCH 141/443] Lang Fallback (#36044) * let lang be found in base directory * allow method to override lang path --- src/Illuminate/Foundation/Application.php | 32 ++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 4fdb7059931c..6199fbbf3015 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -112,6 +112,13 @@ class Application extends Container implements ApplicationContract, CachesConfig */ protected $databasePath; + /** + * The custom language file path defined by the developer. + * + * @var string + */ + protected $langPath; + /** * The custom storage path defined by the developer. * @@ -407,7 +414,30 @@ public function useDatabasePath($path) */ public function langPath() { - return $this->resourcePath().DIRECTORY_SEPARATOR.'lang'; + if ($this->langPath) { + return $this->langPath; + } + + if (is_dir($path = $this->resourcePath().DIRECTORY_SEPARATOR.'lang')) { + return $path; + } + + return $this->basePath().DIRECTORY_SEPARATOR.'lang'; + } + + /** + * Set the language file directory. + * + * @param string $path + * @return $this + */ + public function useLangPath($path) + { + $this->langPath = $path; + + $this->instance('path.lang', $path); + + return $this; } /** From 055b880b14dfcb1ad8fa9a018c3818394e33890b Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 16:34:19 -0600 Subject: [PATCH 142/443] Update middleware instead of Router --- .../Routing/Middleware/SubstituteBindings.php | 13 +++++++++++-- src/Illuminate/Routing/Route.php | 11 ++++++++++- src/Illuminate/Routing/Router.php | 14 +++----------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Routing/Middleware/SubstituteBindings.php b/src/Illuminate/Routing/Middleware/SubstituteBindings.php index 57adde76e915..2ce0eb05ca07 100644 --- a/src/Illuminate/Routing/Middleware/SubstituteBindings.php +++ b/src/Illuminate/Routing/Middleware/SubstituteBindings.php @@ -4,6 +4,7 @@ use Closure; use Illuminate\Contracts\Routing\Registrar; +use Illuminate\Database\Eloquent\ModelNotFoundException; class SubstituteBindings { @@ -34,9 +35,17 @@ public function __construct(Registrar $router) */ public function handle($request, Closure $next) { - $this->router->substituteBindings($route = $request->route()); + try { + $this->router->substituteBindings($route = $request->route()); - $this->router->substituteImplicitBindings($route); + $this->router->substituteImplicitBindings($route); + } catch (ModelNotFoundException $exception) { + if($route->getMissing()) { + return $route->getMissing()($request); + } + + throw $exception; + } return $next($request); } diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 00323d6b417a..5e4da85ad673 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -940,7 +940,12 @@ public function setAction(array $action) */ public function getMissing() { - return $this->action['missing'] ?? null; + $missing = $this->action['missing'] ?? null; + + return is_string($missing) && + Str::startsWith($missing, 'C:32:"Opis\\Closure\\SerializableClosure') + ? unserialize($missing) + : $missing; } /** @@ -1194,6 +1199,10 @@ public function prepareForSerialization() // throw new LogicException("Unable to prepare route [{$this->uri}] for serialization. Uses Closure."); } + if (isset($this->action['missing']) && $this->action['missing'] instanceof Closure) { + $this->action['missing'] = serialize(new SerializableClosure($this->action['missing'])); + } + $this->compileRoute(); unset($this->router, $this->container); diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 4c25592a988c..a22bc971dee6 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -666,17 +666,9 @@ protected function runRoute(Request $request, Route $route) $this->events->dispatch(new RouteMatched($route, $request)); - try { - return $this->prepareResponse($request, - $this->runRouteWithinStack($route, $request) - ); - } catch (ModelNotFoundException $exception) { - if ($route->getMissing()) { - return $route->getMissing()($request); - } - - throw $exception; - } + return $this->prepareResponse($request, + $this->runRouteWithinStack($route, $request) + ); } /** From a7c1bc22549c4450a6c41c638a37eb54261a573c Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 16:37:51 -0600 Subject: [PATCH 143/443] Fix style issue --- src/Illuminate/Routing/Middleware/SubstituteBindings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Middleware/SubstituteBindings.php b/src/Illuminate/Routing/Middleware/SubstituteBindings.php index 2ce0eb05ca07..d5f49ea91d9c 100644 --- a/src/Illuminate/Routing/Middleware/SubstituteBindings.php +++ b/src/Illuminate/Routing/Middleware/SubstituteBindings.php @@ -40,7 +40,7 @@ public function handle($request, Closure $next) $this->router->substituteImplicitBindings($route); } catch (ModelNotFoundException $exception) { - if($route->getMissing()) { + if ($route->getMissing()) { return $route->getMissing()($request); } From 8bbd689146c5ac472d93e173ba0f1f3e165ba426 Mon Sep 17 00:00:00 2001 From: Adam Campbell Date: Mon, 25 Jan 2021 16:40:06 -0600 Subject: [PATCH 144/443] Update Router.php --- src/Illuminate/Routing/Router.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index a22bc971dee6..f1b61dc74dcf 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -12,7 +12,6 @@ use Illuminate\Contracts\Support\Jsonable; use Illuminate\Contracts\Support\Responsable; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; From b42c2d845cdd827ac5a53cacf16af4a0b5dd8be1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 26 Jan 2021 08:39:47 -0600 Subject: [PATCH 145/443] version --- 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 35348d53f62b..648a0cd2f21a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.14'; + const VERSION = '6.20.15'; /** * The base path for the Laravel installation. From 9d7f75e0b3c61a07987aad87af801688e5011b98 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 26 Jan 2021 18:15:42 +0100 Subject: [PATCH 146/443] Typecast page number as integer (#36055) --- src/Illuminate/Pagination/AbstractPaginator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index e09ec3b2c89c..5fefab34ce06 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -446,7 +446,7 @@ public static function currentPathResolver(Closure $resolver) public static function resolveCurrentPage($pageName = 'page', $default = 1) { if (isset(static::$currentPageResolver)) { - return call_user_func(static::$currentPageResolver, $pageName); + return (int) call_user_func(static::$currentPageResolver, $pageName); } return $default; From 09204d521100202e573fbd0e5815d246af9adbb3 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 26 Jan 2021 21:40:31 +0200 Subject: [PATCH 147/443] wip --- .../Eloquent/Concerns/HasAttributes.php | 19 ++++++------------- .../EloquentModelEncryptedCastingTest.php | 4 +++- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index e60e09574f94..e413677aaadc 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -783,11 +783,8 @@ public function fillJsonAttribute($key, $value) $path, $key, $value )); - if ($this->isEncryptedCastable($key)) { - $value = $this->castAttributeAsEncryptedString($key, $value); - } - - $this->attributes[$key] = $value; + $this->attributes[$key] = $this->isEncryptedCastable($key) ? + $this->castAttributeAsEncryptedString($key, $value) : $value; return $this; } @@ -850,17 +847,13 @@ protected function getArrayAttributeWithValue($path, $key, $value) */ protected function getArrayAttributeByKey($key) { - if(!isset($this->attributes[$key])){ + if (! isset($this->attributes[$key])) { return []; } - $value = $this->attributes[$key]; - - if ($this->isEncryptedCastable($key)) { - $value = $this->fromEncryptedString($value); - } - - return $this->fromJson($value); + return $this->fromJson($this->isEncryptedCastable($key) ? + $this->fromEncryptedString($this->attributes[$key]) : $this->attributes[$key] + ); } /** diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index 7aad90a686fc..1554af9c60ed 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -116,7 +116,9 @@ public function testJsonAttributeIsCastable() $subject = new EncryptedCast([ 'secret_json' => ['key1' => 'value1'], ]); - $subject->setAttribute('secret_json->key2', 'value2'); + $subject->fill([ + 'secret_json->key2' => 'value2', + ]); $subject->save(); $this->assertSame(['key1' => 'value1', 'key2' => 'value2'], $subject->secret_json); From 0a5face20e664410ebeb2eb7ef12f1260f0b0cfa Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 27 Jan 2021 10:30:35 -0600 Subject: [PATCH 148/443] formatting --- src/Illuminate/Routing/Route.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 5e4da85ad673..6d3df0c7175f 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -934,7 +934,7 @@ public function setAction(array $action) } /** - * Get the value of the missing redirect. + * Get the value of the action that should be taken on a missing model exception. * * @return \Closure|null */ @@ -949,7 +949,7 @@ public function getMissing() } /** - * Add or change the missing redirect. + * Define the callable that should be invoked on a missing model exception. * * @param \Closure $missing * @return $this @@ -1195,8 +1195,6 @@ public function prepareForSerialization() { if ($this->action['uses'] instanceof Closure) { $this->action['uses'] = serialize(new SerializableClosure($this->action['uses'])); - - // throw new LogicException("Unable to prepare route [{$this->uri}] for serialization. Uses Closure."); } if (isset($this->action['missing']) && $this->action['missing'] instanceof Closure) { From 306826fb60dfb5b5fb64d010e2ffa3dcb3f1c656 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Wed, 27 Jan 2021 11:58:28 -0500 Subject: [PATCH 149/443] [8.x] Fix issues with dumping PostgreSQL databases that contain multiple schemata (#36046) * Eliminate the need for search_path logic The PostgreSQL search_path logic that this commit removes was added with the intention of enabling support for a schema named anything other than "public". While the theory was sound, the implementation didn't take into account the behavior in databases in which *multiple* schemas exist. In multi-schema databases, the list of tables for which data should not be dumped was incorrect, leading to unexpected behavior. This revised approach takes advantage of PostgreSQL's support for pattern-based object references when specifying the list of tables for which data should not be dumped, and eliminates the need to perform complex search_path parsing altogether. The attendant Pull Request documentation explains how this technique works in detail. * Re-implement pg_restore fix that was reverted https://github.com/laravel/framework/issues/36054 was fixed in a previous commit, but appears to have been lost during subsequent edits in https://github.com/laravel/framework/commit/7be50a511955dea2bf4d6e30208b6fbf07eaa36e . This commit restores the changes made in https://github.com/laravel/framework/commit/502e75b2c8a4469363ed03adc974a5194e820ba7 . Fixes #36054 * Fix PostgreSQL object reference pattern quoting While not required in a psql interactive terminal, this pattern requires outer double-quotes to function as intended when passed as a CLI argument. While simple in this specific instance, pattern quoting can grow complicated (depending on the pattern), but is well explained in the PostgreSQL manual: https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-PATTERNS --- src/Illuminate/Database/Schema/PostgresSchemaState.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index 7231118f1899..c844ec542e01 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -16,16 +16,12 @@ class PostgresSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { - $schema = $connection->getConfig('schema', 'public'); - - $schema = $schema === 'public' ? '' : $schema.'.'; - $excludedTables = collect($connection->getSchemaBuilder()->getAllTables()) ->map->tablename ->reject(function ($table) { return $table === $this->migrationTable; - })->map(function ($table) use ($schema) { - return '--exclude-table-data='.$schema.$table; + })->map(function ($table) { + return '--exclude-table-data="*.'.$table.'"'; })->implode(' '); $this->makeProcess( @@ -43,7 +39,7 @@ public function dump(Connection $connection, $path) */ public function load($path) { - $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --no-owner --no-acl --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE $LARAVEL_LOAD_PATH'; + $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --no-owner --no-acl --clean --if-exists --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE $LARAVEL_LOAD_PATH'; if (Str::endsWith($path, '.sql')) { $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD psql --file=$LARAVEL_LOAD_PATH --host=$LARAVEL_LOAD_HOST --port=$LARAVEL_LOAD_PORT --username=$LARAVEL_LOAD_USER --dbname=$LARAVEL_LOAD_DATABASE'; From 1b00aba523eec1e065c61ce57cfea81a4b112a8f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 27 Jan 2021 11:34:51 -0600 Subject: [PATCH 150/443] formatting --- .../Database/Eloquent/Concerns/HasAttributes.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index e413677aaadc..aca701dd727b 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -783,8 +783,9 @@ public function fillJsonAttribute($key, $value) $path, $key, $value )); - $this->attributes[$key] = $this->isEncryptedCastable($key) ? - $this->castAttributeAsEncryptedString($key, $value) : $value; + $this->attributes[$key] = $this->isEncryptedCastable($key) + ? $this->castAttributeAsEncryptedString($key, $value) + : $value; return $this; } @@ -851,8 +852,10 @@ protected function getArrayAttributeByKey($key) return []; } - return $this->fromJson($this->isEncryptedCastable($key) ? - $this->fromEncryptedString($this->attributes[$key]) : $this->attributes[$key] + return $this->fromJson( + $this->isEncryptedCastable($key) + ? $this->fromEncryptedString($this->attributes[$key]) + : $this->attributes[$key] ); } From c0140c4cc54ab40f73b10d9368c7551c88fc1ba3 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 27 Jan 2021 23:01:27 +0200 Subject: [PATCH 151/443] [6.x] update changelog --- CHANGELOG-6.x.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 42350000b97c..8e34966a1e95 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,13 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.13...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.14...6.x) + + +## [v6.20.14 (2021-01-21)](https://github.com/laravel/framework/compare/v6.20.13...v6.20.14) + +### Fixed +- Fixed type error in `Illuminate\Http\Concerns\InteractsWithContentTypes::isJson()` ([#35956](https://github.com/laravel/framework/pull/35956)) +- Limit expected bindings ([#35972](https://github.com/laravel/framework/pull/35972), [006873d](https://github.com/laravel/framework/commit/006873df411d28bfd03fea5e7f91a2afe3918498)) ## [v6.20.13 (2021-01-19)](https://github.com/laravel/framework/compare/v6.20.12...v6.20.13) From c7c9d4ea5529f2f4025dff73263a8c77cde6e97b Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 27 Jan 2021 23:08:28 +0200 Subject: [PATCH 152/443] [7.x] update changelog --- CHANGELOG-7.x.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index 36d7fe5e06fc..3f774e4955f8 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,14 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.30.3...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.30.4...7.x) + + +## [v7.30.4 (2021-01-21)](https://github.com/laravel/framework/compare/v7.30.3...v7.30.4) + +### Fixed +- Fixed empty html mail ([#35941](https://github.com/laravel/framework/pull/35941)) +- Fixed type error in `Illuminate\Http\Concerns\InteractsWithContentTypes::isJson()` ([#35956](https://github.com/laravel/framework/pull/35956)) +- Limit expected bindings ([#35972](https://github.com/laravel/framework/pull/35972), [006873d](https://github.com/laravel/framework/commit/006873df411d28bfd03fea5e7f91a2afe3918498)) ## [v7.30.3 (2021-01-15)](https://github.com/laravel/framework/compare/v7.30.2...v7.30.3) From fae7f9bbd6518e022177c7bdf74b57019829f021 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 27 Jan 2021 23:17:57 +0200 Subject: [PATCH 153/443] [8.x] update changelog --- CHANGELOG-8.x.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index f1e61cd5215f..714aa0419dc5 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,18 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.23.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.24.0...8.x) + + +## [v8.24.0 (2021-01-21)](https://github.com/laravel/framework/compare/v8.23.1...v8.24.0) + +### Added +- Added `JobQueued` event ([8eaec03](https://github.com/laravel/framework/commit/8eaec037421aa9f3860da9d339986448b4c884eb), [5d572e7](https://github.com/laravel/framework/commit/5d572e7a6d479ef68ee92c9d67e2e9465174fb4c)) + +### Fixed +- Fixed type error in `Illuminate\Http\Concerns\InteractsWithContentTypes::isJson()` ([#35956](https://github.com/laravel/framework/pull/35956)) +- Fixed `Illuminate\Collections\Collection::sortByMany()` ([#35950](https://github.com/laravel/framework/pull/35950)) +- Fixed Limit expected bindings ([#35972](https://github.com/laravel/framework/pull/35972), [006873d](https://github.com/laravel/framework/commit/006873df411d28bfd03fea5e7f91a2afe3918498)) +- Fixed serialization of rate limited with redis middleware ([#35971](https://github.com/laravel/framework/pull/35971)) ## [v8.23.1 (2021-01-19)](https://github.com/laravel/framework/compare/v8.23.0...v8.23.1) From 0966a30d56a697426bb64babcddc32a19c44a639 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 27 Jan 2021 23:21:23 +0200 Subject: [PATCH 154/443] [6.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 8e34966a1e95..71992b608e31 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.14...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.15...6.x) + + +## [v6.20.15 (2021-01-26)](https://github.com/laravel/framework/compare/v6.20.14...v6.20.15) + +### Changed +- Pipe new through render and report exception methods ([#36037](https://github.com/laravel/framework/pull/36037)) ## [v6.20.14 (2021-01-21)](https://github.com/laravel/framework/compare/v6.20.13...v6.20.14) From a9e591e2850ecb641c2c7aad2ee6e3c2999e3e55 Mon Sep 17 00:00:00 2001 From: Bogdan Kharchenko Date: Wed, 27 Jan 2021 16:34:15 -0500 Subject: [PATCH 155/443] Markdown Support for Str and Stringable --- src/Illuminate/Support/Str.php | 17 +++++++++++++++++ src/Illuminate/Support/Stringable.php | 12 ++++++++++++ tests/Support/SupportStrTest.php | 6 ++++++ tests/Support/SupportStringableTest.php | 6 ++++++ 4 files changed, 41 insertions(+) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index bd54885d9d1b..82d70e79d63c 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -3,6 +3,7 @@ namespace Illuminate\Support; use Illuminate\Support\Traits\Macroable; +use League\CommonMark\GithubFlavoredMarkdownConverter; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; use Ramsey\Uuid\Generator\CombGenerator; use Ramsey\Uuid\Uuid; @@ -722,6 +723,20 @@ public static function ucfirst($string) return static::upper(static::substr($string, 0, 1)).static::substr($string, 1); } + /** + * Converts markdown to html. + * + * @param string $string + * @param array $options + * @return string + */ + public static function markdown($string, $options = []) + { + $converter = new GithubFlavoredMarkdownConverter($options); + + return $converter->convertToHtml($string); + } + /** * Generate a UUID (version 4). * @@ -779,4 +794,6 @@ public static function createUuidsNormally() { static::$uuidFactory = null; } + + } diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 65320e1bcf3f..56f7b6845dbe 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -6,6 +6,7 @@ use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\Tappable; use JsonSerializable; +use League\CommonMark\GithubFlavoredMarkdownConverter; use Symfony\Component\VarDumper\VarDumper; class Stringable implements JsonSerializable @@ -663,6 +664,17 @@ public function ucfirst() return new static(Str::ucfirst($this->value)); } + /** + * Converts markdown to html. + * + * @param array $options + * @return string + */ + public function markdown($options = []) + { + return new static(Str::markdown($this->value, $options)); + } + /** * Apply the callback's string changes if the given "value" is true. * diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 87bc3c0956c4..f873e3bd934d 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -511,6 +511,12 @@ public function invalidUuidList() ['ff6f8cb0-c57da-51e1-9b21-0800200c9a66'], ]; } + + public function testMarkdown() + { + $this->assertEquals("

hello world

\n", Str::markdown('*hello world*')); + $this->assertEquals("

hello world

\n", Str::markdown('# hello world')); + } } class StringableObjectStub diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index e666b2fff98b..15ab04726cb1 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -574,4 +574,10 @@ public function testPipe() $this->assertInstanceOf(Stringable::class, $this->stringable('foo')->pipe($callback)); $this->assertSame('bar', (string) $this->stringable('foo')->pipe($callback)); } + + public function testMarkdown() + { + $this->assertEquals("

hello world

\n", $this->stringable('*hello world*')->markdown()); + $this->assertEquals("

hello world

\n", $this->stringable('# hello world')->markdown()); + } } From 5a3479e37e115e2155c11b8f6a6ca2b84f652397 Mon Sep 17 00:00:00 2001 From: Bogdan Kharchenko Date: Wed, 27 Jan 2021 16:35:58 -0500 Subject: [PATCH 156/443] formatting --- src/Illuminate/Support/Str.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 82d70e79d63c..93a1ac89152a 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -794,6 +794,4 @@ public static function createUuidsNormally() { static::$uuidFactory = null; } - - } From b1381f2d876ba4cec4dbdea84ae0fb6ccce0bb79 Mon Sep 17 00:00:00 2001 From: Bogdan Kharchenko Date: Wed, 27 Jan 2021 16:37:24 -0500 Subject: [PATCH 157/443] Remove unused import --- src/Illuminate/Support/Stringable.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 56f7b6845dbe..56b2197e6698 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -6,7 +6,6 @@ use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\Tappable; use JsonSerializable; -use League\CommonMark\GithubFlavoredMarkdownConverter; use Symfony\Component\VarDumper\VarDumper; class Stringable implements JsonSerializable From ec82a4f1782554f6f391e281a5160aa4c9565fe7 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 27 Jan 2021 23:40:22 +0200 Subject: [PATCH 158/443] [8.x] update changelog --- CHANGELOG-8.x.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 714aa0419dc5..c2974b8af01e 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,29 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.24.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.25.0...8.x) + + +## [v8.25.0 (2021-01-26)](https://github.com/laravel/framework/compare/v8.24.0...v8.25.0) + +### Added +- Added `Stringable::pipe` & make Stringable tappable ([#36017](https://github.com/laravel/framework/pull/36017)) +- Accept a command in object form in Bus::assertChained ([#36031](https://github.com/laravel/framework/pull/36031)) +- Adds parallel testing ([#36034](https://github.com/laravel/framework/pull/36034)) +- Make Listeners, Mailables, and Notifications accept ShouldBeEncrypted ([#36036](https://github.com/laravel/framework/pull/36036)) +- Support JSON encoding Stringable ([#36012](https://github.com/laravel/framework/pull/36012)) +- Support for escaping bound attributes ([#36042](https://github.com/laravel/framework/pull/36042)) +- Added `Illuminate\Foundation\Application::useLangPath()` ([#36044](https://github.com/laravel/framework/pull/36044)) + +### Changed +- Pipe through new render and report exception methods ([#36032](https://github.com/laravel/framework/pull/36032)) + +### Fixed +- Fixed issue with dumping schema from a postgres database using no default schema ([#35966](https://github.com/laravel/framework/pull/35966), [7be50a5](https://github.com/laravel/framework/commit/7be50a511955dea2bf4d6e30208b6fbf07eaa36e)) +- Fixed worker --delay option ([#35991](https://github.com/laravel/framework/pull/35991)) +- Added support of PHP 7.3 to RateLimiter middleware(queue) serialization ([#35986](https://github.com/laravel/framework/pull/35986)) +- Fixed `Illuminate\Foundation\Http\Middleware\TransformsRequest::cleanArray()` ([#36002](https://github.com/laravel/framework/pull/36002)) +- ModelNotFoundException: ensure that the model class name is properly set ([#36011](https://github.com/laravel/framework/pull/36011)) +- Fixed bus fake ([e720279](https://github.com/laravel/framework/commit/e72027960fd4d8ff281938edb4632e13e391b8fd)) ## [v8.24.0 (2021-01-21)](https://github.com/laravel/framework/compare/v8.23.1...v8.24.0) From 99efd25319e678a6a58ff7ca10c1d658f481084c Mon Sep 17 00:00:00 2001 From: reza Date: Thu, 28 Jan 2021 20:16:38 +0330 Subject: [PATCH 159/443] fixes job batch serialization with PostgreSQL ref #36061 --- .../Bus/DatabaseBatchRepository.php | 35 +++++++++++- tests/Bus/BusBatchTest.php | 53 +++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index ece6301c126f..f9aefdca6c9c 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -6,6 +6,7 @@ use Closure; use DateTimeInterface; use Illuminate\Database\Connection; +use Illuminate\Database\PostgresConnection; use Illuminate\Database\Query\Expression; use Illuminate\Support\Str; @@ -102,7 +103,7 @@ public function store(PendingBatch $batch) 'pending_jobs' => 0, 'failed_jobs' => 0, 'failed_job_ids' => '[]', - 'options' => serialize($batch->options), + 'options' => $this->serialize($batch->options), 'created_at' => time(), 'cancelled_at' => null, 'finished_at' => null, @@ -283,10 +284,40 @@ protected function toBatch($batch) (int) $batch->pending_jobs, (int) $batch->failed_jobs, json_decode($batch->failed_job_ids, true), - unserialize($batch->options), + $this->unserialize($batch->options), CarbonImmutable::createFromTimestamp($batch->created_at), $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at, $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at ); } + + /** + * Serialize the given value. + * + * @param mixed $value + * @return string + */ + protected function serialize($value) + { + $serialized = serialize($value); + + return $this->connection instanceof PostgresConnection + ? base64_encode($serialized) + : $serialized; + } + + /** + * Unserialize the given value. + * + * @param string $serialized + * @return mixed + */ + protected function unserialize($serialized) + { + $serialized = $this->connection instanceof PostgresConnection + ? base64_decode($serialized) + : $serialized; + + return unserialize($serialized); + } } diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index 8f4d6c5a11d4..69c7cfa0160e 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -14,6 +14,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\PostgresConnection; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\CallQueuedClosure; use Mockery as m; @@ -339,6 +340,58 @@ public function test_chain_can_be_added_to_batch() $this->assertInstanceOf(CarbonImmutable::class, $batch->createdAt); } + public function test_options_serialization_on_postgres() + { + $pendingBatch = (new PendingBatch(new Container, collect())) + ->onQueue('test-queue'); + + $connection = m::spy(PostgresConnection::class); + + $connection->shouldReceive('table')->andReturnSelf() + ->shouldReceive('where')->andReturnSelf(); + + $repository = new DatabaseBatchRepository( + new BatchFactory(m::mock(Factory::class)), $connection, 'job_batches' + ); + + $repository->store($pendingBatch); + + $connection->shouldHaveReceived('insert') + ->withArgs(function ($argument) use ($pendingBatch) { + return unserialize(base64_decode($argument['options'])) === $pendingBatch->options; + }); + } + + public function test_options_unserialize_on_postgres() + { + $factory = m::mock(BatchFactory::class); + + $connection = m::spy(PostgresConnection::class); + + $options = [1, 2]; + + $connection->shouldReceive('table->where->first') + ->andReturn($m = (object) [ + 'id' => '', + 'name' => '', + 'total_jobs' => '', + 'pending_jobs' => '', + 'failed_jobs' => '', + 'failed_job_ids' => '[]', + 'options' => base64_encode(serialize($options)), + 'created_at' => now(), + 'cancelled_at' => null, + 'finished_at' => null, + ]); + + $batch = (new DatabaseBatchRepository($factory, $connection, 'job_batches')); + + $factory->shouldReceive('make') + ->withSomeOfArgs($batch, '', '', '', '', '', '', [1, 2]); + + $batch->find(1); + } + protected function createTestBatch($queue, $allowFailures = false) { $repository = new DatabaseBatchRepository(new BatchFactory($queue), DB::connection(), 'job_batches'); From c3ec76873d972cfb1ec1df0bfa2df148ef93eab5 Mon Sep 17 00:00:00 2001 From: reza Date: Thu, 28 Jan 2021 20:30:17 +0330 Subject: [PATCH 160/443] fixes --- tests/Bus/BusBatchTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index 69c7cfa0160e..dee89fc6a136 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -379,7 +379,7 @@ public function test_options_unserialize_on_postgres() 'failed_jobs' => '', 'failed_job_ids' => '[]', 'options' => base64_encode(serialize($options)), - 'created_at' => now(), + 'created_at' => null, 'cancelled_at' => null, 'finished_at' => null, ]); @@ -387,7 +387,7 @@ public function test_options_unserialize_on_postgres() $batch = (new DatabaseBatchRepository($factory, $connection, 'job_batches')); $factory->shouldReceive('make') - ->withSomeOfArgs($batch, '', '', '', '', '', '', [1, 2]); + ->withSomeOfArgs($batch, '', '', '', '', '', '', $options); $batch->find(1); } From 97f9747ce910953fcf834476c4a1f0625878f6b4 Mon Sep 17 00:00:00 2001 From: reza Date: Thu, 28 Jan 2021 20:51:48 +0330 Subject: [PATCH 161/443] not using base64_decode for old serialized values --- src/Illuminate/Bus/DatabaseBatchRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index f9aefdca6c9c..ea2c9f89b80f 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -314,7 +314,7 @@ protected function serialize($value) */ protected function unserialize($serialized) { - $serialized = $this->connection instanceof PostgresConnection + $serialized = $this->connection instanceof PostgresConnection && ! Str::contains($serialized, [':', ';']) ? base64_decode($serialized) : $serialized; From 667c0570cde76782045093d67536bc3d12efcd6e Mon Sep 17 00:00:00 2001 From: reza Date: Thu, 28 Jan 2021 20:59:54 +0330 Subject: [PATCH 162/443] adds test & refactor --- .../Bus/DatabaseBatchRepository.php | 6 ++--- tests/Bus/BusBatchTest.php | 22 +++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index ea2c9f89b80f..19c98ae1581a 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -314,9 +314,9 @@ protected function serialize($value) */ protected function unserialize($serialized) { - $serialized = $this->connection instanceof PostgresConnection && ! Str::contains($serialized, [':', ';']) - ? base64_decode($serialized) - : $serialized; + if ($this->connection instanceof PostgresConnection) { + $serialized = base64_decode($serialized, true) ?: $serialized; + } return unserialize($serialized); } diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index dee89fc6a136..1da999569e84 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -362,14 +362,15 @@ public function test_options_serialization_on_postgres() }); } - public function test_options_unserialize_on_postgres() + /** + * @dataProvider serializedOptions + */ + public function test_options_unserialize_on_postgres($serialize, $options) { $factory = m::mock(BatchFactory::class); $connection = m::spy(PostgresConnection::class); - $options = [1, 2]; - $connection->shouldReceive('table->where->first') ->andReturn($m = (object) [ 'id' => '', @@ -378,7 +379,7 @@ public function test_options_unserialize_on_postgres() 'pending_jobs' => '', 'failed_jobs' => '', 'failed_job_ids' => '[]', - 'options' => base64_encode(serialize($options)), + 'options' => $serialize, 'created_at' => null, 'cancelled_at' => null, 'finished_at' => null, @@ -392,6 +393,19 @@ public function test_options_unserialize_on_postgres() $batch->find(1); } + /** + * @return array + */ + public function serializedOptions() + { + $options = [1, 2]; + + return [ + [serialize($options), $options], + [base64_encode(serialize($options)), $options], + ]; + } + protected function createTestBatch($queue, $allowFailures = false) { $repository = new DatabaseBatchRepository(new BatchFactory($queue), DB::connection(), 'job_batches'); From 3a33588074c6e5051430d107b823acd6c6369c37 Mon Sep 17 00:00:00 2001 From: reza Date: Thu, 28 Jan 2021 22:34:33 +0330 Subject: [PATCH 163/443] addresses reviews --- src/Illuminate/Bus/DatabaseBatchRepository.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index 19c98ae1581a..4dd5db261bae 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -314,8 +314,8 @@ protected function serialize($value) */ protected function unserialize($serialized) { - if ($this->connection instanceof PostgresConnection) { - $serialized = base64_decode($serialized, true) ?: $serialized; + if ($this->connection instanceof PostgresConnection && ! Str::contains($serialized, [':', ';'])) { + $serialized = base64_decode($serialized); } return unserialize($serialized); From 8d5750711eed8533cd5648d0f0a9eec3cdb795dd Mon Sep 17 00:00:00 2001 From: Markus Machatschek Date: Fri, 29 Jan 2021 14:51:07 +0100 Subject: [PATCH 164/443] [8.x] Fix docblocks of facades with faking possibility (#36087) * Fix facade docblocks * Update docblock of mail fake send method --- src/Illuminate/Support/Facades/Bus.php | 8 ++++---- src/Illuminate/Support/Facades/Event.php | 4 ++-- src/Illuminate/Support/Facades/Mail.php | 4 ++-- src/Illuminate/Support/Facades/Notification.php | 4 ++-- src/Illuminate/Support/Facades/Queue.php | 6 +++--- src/Illuminate/Support/Testing/Fakes/MailFake.php | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Support/Facades/Bus.php b/src/Illuminate/Support/Facades/Bus.php index ec2c3f7ddc13..ec95d86243d6 100644 --- a/src/Illuminate/Support/Facades/Bus.php +++ b/src/Illuminate/Support/Facades/Bus.php @@ -16,12 +16,12 @@ * @method static bool|mixed getCommandHandler($command) * @method static mixed dispatch($command) * @method static mixed dispatchNow($command, $handler = null) - * @method static void assertDispatched(string $command, callable|int $callback = null) + * @method static void assertDispatched(string|\Closure $command, callable|int $callback = null) * @method static void assertDispatchedTimes(string $command, int $times = 1) - * @method static void assertNotDispatched(string $command, callable $callback = null) - * @method static void assertDispatchedAfterResponse(string $command, callable|int $callback = null) + * @method static void assertNotDispatched(string|\Closure $command, callable|int $callback = null) + * @method static void assertDispatchedAfterResponse(string|\Closure $command, callable|int $callback = null) * @method static void assertDispatchedAfterResponseTimes(string $command, int $times = 1) - * @method static void assertNotDispatchedAfterResponse(string $command, callable $callback = null) + * @method static void assertNotDispatchedAfterResponse(string|\Closure $command, callable $callback = null) * @method static void assertBatched(callable $callback) * * @see \Illuminate\Contracts\Bus\Dispatcher diff --git a/src/Illuminate/Support/Facades/Event.php b/src/Illuminate/Support/Facades/Event.php index d70d09334a1d..c6e0b014dc6c 100755 --- a/src/Illuminate/Support/Facades/Event.php +++ b/src/Illuminate/Support/Facades/Event.php @@ -13,9 +13,9 @@ * @method static array|null dispatch(string|object $event, mixed $payload = [], bool $halt = false) * @method static array|null until(string|object $event, mixed $payload = []) * @method static bool hasListeners(string $eventName) - * @method static void assertDispatched(string $event, callable|int $callback = null) + * @method static void assertDispatched(string|\Closure $event, callable|int $callback = null) * @method static void assertDispatchedTimes(string $event, int $times = 1) - * @method static void assertNotDispatched(string $event, callable|int $callback = null) + * @method static void assertNotDispatched(string|\Closure $event, callable|int $callback = null) * @method static void flush(string $event) * @method static void forget(string $event) * @method static void forgetPushed() diff --git a/src/Illuminate/Support/Facades/Mail.php b/src/Illuminate/Support/Facades/Mail.php index 887629d67950..36796e752e55 100755 --- a/src/Illuminate/Support/Facades/Mail.php +++ b/src/Illuminate/Support/Facades/Mail.php @@ -21,8 +21,8 @@ * @method static void assertNotSent(string $mailable, callable|int $callback = null) * @method static void assertNothingQueued() * @method static void assertNothingSent() - * @method static void assertQueued(string $mailable, callable|int $callback = null) - * @method static void assertSent(string $mailable, callable|int $callback = null) + * @method static void assertQueued(string|\Closure $mailable, callable|int $callback = null) + * @method static void assertSent(string|\Closure $mailable, callable|int $callback = null) * @method static void raw(string $text, $callback) * @method static void plain(string $view, array $data, $callback) * @method static void html(string $html, $callback) diff --git a/src/Illuminate/Support/Facades/Notification.php b/src/Illuminate/Support/Facades/Notification.php index b3e858978c5c..8ab683eaf74b 100644 --- a/src/Illuminate/Support/Facades/Notification.php +++ b/src/Illuminate/Support/Facades/Notification.php @@ -11,9 +11,9 @@ * @method static \Illuminate\Support\Collection sent(mixed $notifiable, string $notification, callable $callback = null) * @method static bool hasSent(mixed $notifiable, string $notification) * @method static mixed channel(string|null $name = null) - * @method static void assertNotSentTo(mixed $notifiable, string $notification, callable $callback = null) + * @method static void assertNotSentTo(mixed $notifiable, string|\Closure $notification, callable $callback = null) * @method static void assertNothingSent() - * @method static void assertSentTo(mixed $notifiable, string $notification, callable $callback = null) + * @method static void assertSentTo(mixed $notifiable, string|\Closure $notification, callable $callback = null) * @method static void assertSentToTimes(mixed $notifiable, string $notification, int $times = 1) * @method static void assertTimesSent(int $expectedCount, string $notification) * @method static void send(\Illuminate\Support\Collection|array|mixed $notifiables, $notification) diff --git a/src/Illuminate/Support/Facades/Queue.php b/src/Illuminate/Support/Facades/Queue.php index 3eeb767472b8..a057390e530f 100755 --- a/src/Illuminate/Support/Facades/Queue.php +++ b/src/Illuminate/Support/Facades/Queue.php @@ -16,10 +16,10 @@ * @method static mixed pushOn(string $queue, string|object $job, mixed $data = '') * @method static mixed pushRaw(string $payload, string $queue = null, array $options = []) * @method static string getConnectionName() - * @method static void assertNotPushed(string $job, callable $callback = null) + * @method static void assertNotPushed(string|\Closure $job, callable $callback = null) * @method static void assertNothingPushed() - * @method static void assertPushed(string $job, callable|int $callback = null) - * @method static void assertPushedOn(string $queue, string $job, callable|int $callback = null) + * @method static void assertPushed(string|\Closure $job, callable|int $callback = null) + * @method static void assertPushedOn(string $queue, string|\Closure $job, callable|int $callback = null) * @method static void assertPushedWithChain(string $job, array $expectedChain = [], callable $callback = null) * @method static void popUsing(string $workerName, callable $callback) * diff --git a/src/Illuminate/Support/Testing/Fakes/MailFake.php b/src/Illuminate/Support/Testing/Fakes/MailFake.php index d299bb1c5a31..eb548b6910b3 100644 --- a/src/Illuminate/Support/Testing/Fakes/MailFake.php +++ b/src/Illuminate/Support/Testing/Fakes/MailFake.php @@ -322,7 +322,7 @@ public function raw($text, $callback) /** * Send a new message using a view. * - * @param string|array $view + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view * @param array $data * @param \Closure|string|null $callback * @return void From f8d7cf9ea2894f513112b5365735bba86dd49ac3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Jan 2021 10:05:43 -0600 Subject: [PATCH 165/443] formatting --- .../Bus/DatabaseBatchRepository.php | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index 4dd5db261bae..03d7a3dab3cb 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -268,29 +268,6 @@ public function transaction(Closure $callback) }); } - /** - * Convert the given raw batch to a Batch object. - * - * @param object $batch - * @return \Illuminate\Bus\Batch - */ - protected function toBatch($batch) - { - return $this->factory->make( - $this, - $batch->id, - $batch->name, - (int) $batch->total_jobs, - (int) $batch->pending_jobs, - (int) $batch->failed_jobs, - json_decode($batch->failed_job_ids, true), - $this->unserialize($batch->options), - CarbonImmutable::createFromTimestamp($batch->created_at), - $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at, - $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at - ); - } - /** * Serialize the given value. * @@ -314,10 +291,34 @@ protected function serialize($value) */ protected function unserialize($serialized) { - if ($this->connection instanceof PostgresConnection && ! Str::contains($serialized, [':', ';'])) { + if ($this->connection instanceof PostgresConnection && + ! Str::contains($serialized, [':', ';'])) { $serialized = base64_decode($serialized); } return unserialize($serialized); } + + /** + * Convert the given raw batch to a Batch object. + * + * @param object $batch + * @return \Illuminate\Bus\Batch + */ + protected function toBatch($batch) + { + return $this->factory->make( + $this, + $batch->id, + $batch->name, + (int) $batch->total_jobs, + (int) $batch->pending_jobs, + (int) $batch->failed_jobs, + json_decode($batch->failed_job_ids, true), + $this->unserialize($batch->options), + CarbonImmutable::createFromTimestamp($batch->created_at), + $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at, + $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at + ); + } } From cb091a26c13882e922847bad88efd595e778fdcc Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Jan 2021 10:11:07 -0600 Subject: [PATCH 166/443] formatting --- src/Illuminate/Support/Str.php | 28 +++++++++++++-------------- src/Illuminate/Support/Stringable.php | 22 ++++++++++----------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 93a1ac89152a..06d32d4f3c81 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -377,6 +377,20 @@ public static function words($value, $words = 100, $end = '...') return rtrim($matches[0]).$end; } + /** + * Converts GitHub flavored Markdown into HTML. + * + * @param string $string + * @param array $options + * @return string + */ + public static function markdown($string, array $options = []) + { + $converter = new GithubFlavoredMarkdownConverter($options); + + return $converter->convertToHtml($string); + } + /** * Pad both sides of a string with another. * @@ -723,20 +737,6 @@ public static function ucfirst($string) return static::upper(static::substr($string, 0, 1)).static::substr($string, 1); } - /** - * Converts markdown to html. - * - * @param string $string - * @param array $options - * @return string - */ - public static function markdown($string, $options = []) - { - $converter = new GithubFlavoredMarkdownConverter($options); - - return $converter->convertToHtml($string); - } - /** * Generate a UUID (version 4). * diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 56b2197e6698..7cff183756d1 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -320,6 +320,17 @@ public function lower() return new static(Str::lower($this->value)); } + /** + * Convert GitHub flavored Markdown into HTML. + * + * @param array $options + * @return string + */ + public function markdown(array $options = []) + { + return new static(Str::markdown($this->value, $options)); + } + /** * Get the string matching the given pattern. * @@ -663,17 +674,6 @@ public function ucfirst() return new static(Str::ucfirst($this->value)); } - /** - * Converts markdown to html. - * - * @param array $options - * @return string - */ - public function markdown($options = []) - { - return new static(Str::markdown($this->value, $options)); - } - /** * Apply the callback's string changes if the given "value" is true. * From 1c11b7893fa3e9c592f6e85b2b1b0028ddd55645 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 30 Jan 2021 13:48:51 -0600 Subject: [PATCH 167/443] allow trait to be moved --- src/Illuminate/Testing/ParallelRunner.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Testing/ParallelRunner.php b/src/Illuminate/Testing/ParallelRunner.php index e26528703bbe..b2bcdf1b7447 100644 --- a/src/Illuminate/Testing/ParallelRunner.php +++ b/src/Illuminate/Testing/ParallelRunner.php @@ -2,11 +2,13 @@ namespace Illuminate\Testing; +use Illuminate\Contracts\Console\Kernel; use Illuminate\Support\Facades\ParallelTesting; use ParaTest\Runners\PHPUnit\Options; use ParaTest\Runners\PHPUnit\RunnerInterface; use ParaTest\Runners\PHPUnit\WrapperRunner; use PHPUnit\TextUI\XmlConfiguration\PhpHandler; +use RuntimeException; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; @@ -128,13 +130,23 @@ protected function forEachProcess($callback) protected function createApplication() { $applicationResolver = static::$applicationResolver ?: function () { - $applicationCreator = new class { - use \Tests\CreatesApplication; - }; + if (trait_exists(\Tests\CreatesApplication::class)) { + $applicationCreator = new class { + use \Tests\CreatesApplication; + }; - return $applicationCreator->createApplication(); + return $applicationCreator->createApplication(); + } elseif (file_exists(getcwd().'/bootstrap/app.php')) { + $app = require getcwd().'/bootstrap/app.php'; + + $app->make(Kernel::class)->bootstrap(); + + return $app; + } + + throw new RuntimeException('Parallel Runner unable to resolve application.'); }; return call_user_func($applicationResolver); } -} +} \ No newline at end of file From 6e90f9af9ed752f346c0bdba9cd0ea16ee13d6a8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 30 Jan 2021 13:49:25 -0600 Subject: [PATCH 168/443] Apply fixes from StyleCI (#36099) --- src/Illuminate/Testing/ParallelRunner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/ParallelRunner.php b/src/Illuminate/Testing/ParallelRunner.php index b2bcdf1b7447..802fe22ca30d 100644 --- a/src/Illuminate/Testing/ParallelRunner.php +++ b/src/Illuminate/Testing/ParallelRunner.php @@ -149,4 +149,4 @@ protected function createApplication() return call_user_func($applicationResolver); } -} \ No newline at end of file +} From f0e1d78ee461c85020d827236fce2386b7544eaa Mon Sep 17 00:00:00 2001 From: Jonathan Goode Date: Sat, 30 Jan 2021 19:50:02 +0000 Subject: [PATCH 169/443] Correct grammar (#36094) --- src/Illuminate/Auth/SessionGuard.php | 2 +- src/Illuminate/Bus/UpdatedBatchJobCounts.php | 2 +- src/Illuminate/Collections/LazyCollection.php | 2 +- src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php | 2 +- src/Illuminate/Database/Eloquent/Relations/MorphTo.php | 2 +- src/Illuminate/Database/PDO/Connection.php | 2 +- src/Illuminate/Database/PDO/SqlServerConnection.php | 2 +- src/Illuminate/Database/Query/Builder.php | 2 +- src/Illuminate/Database/Query/Grammars/Grammar.php | 2 +- src/Illuminate/Database/Schema/Blueprint.php | 4 ++-- src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php | 2 +- src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php | 2 +- src/Illuminate/Database/SqlServerConnection.php | 2 +- src/Illuminate/Hashing/ArgonHasher.php | 2 +- src/Illuminate/Http/Client/Factory.php | 2 +- src/Illuminate/Http/Request.php | 6 +++--- src/Illuminate/Mail/Message.php | 2 +- src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php | 2 +- src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php | 4 ++-- src/Illuminate/Routing/RouteAction.php | 2 +- src/Illuminate/Support/ConfigurationUrlParser.php | 2 +- src/Illuminate/Support/Testing/Fakes/BusFake.php | 2 +- src/Illuminate/Testing/ParallelTesting.php | 2 +- src/Illuminate/Testing/TestResponse.php | 4 ++-- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 4 ++-- src/Illuminate/Validation/Validator.php | 2 +- src/Illuminate/View/Compilers/ComponentTagCompiler.php | 2 +- .../View/Compilers/Concerns/CompilesConditionals.php | 2 +- 28 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 1e6f8c2b5165..1f6863141c4c 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -320,7 +320,7 @@ protected function attemptBasic(Request $request, $field, $extraConditions = []) } /** - * Get the credential array for a HTTP Basic request. + * Get the credential array for an HTTP Basic request. * * @param \Symfony\Component\HttpFoundation\Request $request * @param string $field diff --git a/src/Illuminate/Bus/UpdatedBatchJobCounts.php b/src/Illuminate/Bus/UpdatedBatchJobCounts.php index cc4bdd700b7c..83d33a44f2f7 100644 --- a/src/Illuminate/Bus/UpdatedBatchJobCounts.php +++ b/src/Illuminate/Bus/UpdatedBatchJobCounts.php @@ -32,7 +32,7 @@ public function __construct(int $pendingJobs = 0, int $failedJobs = 0) } /** - * Determine if all jobs have ran exactly once. + * Determine if all jobs have run exactly once. * * @return bool */ diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 650213133ced..df186d864399 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -547,7 +547,7 @@ public function intersectByKeys($items) } /** - * Determine if the items is empty or not. + * Determine if the items are empty or not. * * @return bool */ diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index ede942018f6f..fcf71d5a87c3 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -53,7 +53,7 @@ public function make(array $attributes = []) } /** - * Create and return an un-saved instances of the related models. + * Create and return an un-saved instance of the related models. * * @param iterable $records * @return \Illuminate\Database\Eloquent\Collection diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index c9db5d2b2c6c..e21764131f72 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -324,7 +324,7 @@ public function morphWithCount(array $withCount) } /** - * Specify constraints on the query for a given morph types. + * Specify constraints on the query for a given morph type. * * @param array $callbacks * @return \Illuminate\Database\Eloquent\Relations\MorphTo diff --git a/src/Illuminate/Database/PDO/Connection.php b/src/Illuminate/Database/PDO/Connection.php index 879b7587cf3a..c0d57a9f436d 100644 --- a/src/Illuminate/Database/PDO/Connection.php +++ b/src/Illuminate/Database/PDO/Connection.php @@ -139,7 +139,7 @@ public function commit() } /** - * Roll back a database transaction. + * Rollback a database transaction. * * @return void */ diff --git a/src/Illuminate/Database/PDO/SqlServerConnection.php b/src/Illuminate/Database/PDO/SqlServerConnection.php index eb7f104c0fca..bbbb8b0b6972 100644 --- a/src/Illuminate/Database/PDO/SqlServerConnection.php +++ b/src/Illuminate/Database/PDO/SqlServerConnection.php @@ -102,7 +102,7 @@ public function commit() } /** - * Roll back a database transaction. + * Rollback a database transaction. * * @return void */ diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 7a7df49a28c5..710d0a3a568c 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -195,7 +195,7 @@ class Builder ]; /** - * Whether use write pdo for select. + * Whether to use write pdo for the select. * * @var bool */ diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 8b0a3b311b78..b7305e8ea382 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -459,7 +459,7 @@ protected function dateBasedWhere($type, Builder $query, $where) } /** - * Compile a where clause comparing two columns.. + * Compile a where clause comparing two columns. * * @param \Illuminate\Database\Query\Builder $query * @param array $where diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 36dfbb7597b6..41ed3d90c361 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1607,7 +1607,7 @@ public function getChangedColumns() } /** - * Determine if the blueprint has auto increment columns. + * Determine if the blueprint has auto-increment columns. * * @return bool */ @@ -1619,7 +1619,7 @@ public function hasAutoIncrementColumn() } /** - * Get the auto increment column starting values. + * Get the auto-increment column starting values. * * @return array */ diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index ecaf96e2a3a1..c1a2c5586b54 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -191,7 +191,7 @@ public function compileAdd(Blueprint $blueprint, Fluent $command) } /** - * Compile the auto incrementing column starting values. + * Compile the auto-incrementing column starting values. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return array diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 16737493f9e1..adaf21f90e4c 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -117,7 +117,7 @@ public function compileAdd(Blueprint $blueprint, Fluent $command) } /** - * Compile the auto incrementing column starting values. + * Compile the auto-incrementing column starting values. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @return array diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index b0b8490d062a..87628b99cc9f 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -43,7 +43,7 @@ public function transaction(Closure $callback, $attempts = 1) $this->getPdo()->exec('COMMIT TRAN'); } - // If we catch an exception, we will roll back so nothing gets messed + // If we catch an exception, we will rollback so nothing gets messed // up in the database. Then we'll re-throw the exception so it can // be handled how the developer sees fit for their applications. catch (Throwable $e) { diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index 41109c9b0799..ea3a2f34cc00 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -180,7 +180,7 @@ protected function time(array $options) } /** - * Extract the threads value from the options array. + * Extract the thread's value from the options array. * * @param array $options * @return int diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 7a21d96dca31..0f182b6a65cb 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -225,7 +225,7 @@ public function assertSent($callback) } /** - * Assert that the given request were sent in the given order. + * Assert that the given request was sent in the given order. * * @param array $callbacks * @return void diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index cf6b90cb1da0..944a62e4b372 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -212,7 +212,7 @@ public function routeIs(...$patterns) } /** - * Determine if the current request URL and query string matches a pattern. + * Determine if the current request URL and query string match a pattern. * * @param mixed ...$patterns * @return bool @@ -241,7 +241,7 @@ public function ajax() } /** - * Determine if the request is the result of an PJAX call. + * Determine if the request is the result of a PJAX call. * * @return bool */ @@ -251,7 +251,7 @@ public function pjax() } /** - * Determine if the request is the result of an prefetch call. + * Determine if the request is the result of a prefetch call. * * @return bool */ diff --git a/src/Illuminate/Mail/Message.php b/src/Illuminate/Mail/Message.php index d701fba9fb39..cab6c026d9fe 100755 --- a/src/Illuminate/Mail/Message.php +++ b/src/Illuminate/Mail/Message.php @@ -137,7 +137,7 @@ public function bcc($address, $name = null, $override = false) } /** - * Add a reply to address to the message. + * Add a "reply to" address to the message. * * @param string|array $address * @param string|null $name diff --git a/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php b/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php index 2ba7c91602d2..e66259f59b6e 100644 --- a/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php +++ b/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php @@ -58,7 +58,7 @@ public function __construct($connection, $name) } /** - * Set the maximum number of locks that can obtained per time window. + * Set the maximum number of locks that can be obtained per time window. * * @param int $maxLocks * @return $this diff --git a/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php b/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php index ee378fcc7ff8..c32cb50f7213 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php @@ -24,7 +24,7 @@ class DurationLimiterBuilder public $name; /** - * The maximum number of locks that can obtained per time window. + * The maximum number of locks that can be obtained per time window. * * @var int */ @@ -58,7 +58,7 @@ public function __construct($connection, $name) } /** - * Set the maximum number of locks that can obtained per time window. + * Set the maximum number of locks that can be obtained per time window. * * @param int $maxLocks * @return $this diff --git a/src/Illuminate/Routing/RouteAction.php b/src/Illuminate/Routing/RouteAction.php index 5a8188e27bbd..74035d4ce064 100644 --- a/src/Illuminate/Routing/RouteAction.php +++ b/src/Illuminate/Routing/RouteAction.php @@ -96,7 +96,7 @@ protected static function makeInvokable($action) } /** - * Determine if the given array actions contains a serialized Closure. + * Determine if the given array actions contain a serialized Closure. * * @param array $action * @return bool diff --git a/src/Illuminate/Support/ConfigurationUrlParser.php b/src/Illuminate/Support/ConfigurationUrlParser.php index 946252fb6d15..be54b9a83d5b 100644 --- a/src/Illuminate/Support/ConfigurationUrlParser.php +++ b/src/Illuminate/Support/ConfigurationUrlParser.php @@ -170,7 +170,7 @@ protected function parseStringsToNativeTypes($value) } /** - * Get all of the current drivers aliases. + * Get all of the current drivers' aliases. * * @return array */ diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index f9ef5d4cd68c..5b5b68534583 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -544,7 +544,7 @@ public function recordPendingBatch(PendingBatch $pendingBatch) } /** - * Determine if an command should be faked or actually dispatched. + * Determine if a command should be faked or actually dispatched. * * @param mixed $command * @return bool diff --git a/src/Illuminate/Testing/ParallelTesting.php b/src/Illuminate/Testing/ParallelTesting.php index ba67e16c5c74..842b809f822f 100644 --- a/src/Illuminate/Testing/ParallelTesting.php +++ b/src/Illuminate/Testing/ParallelTesting.php @@ -219,7 +219,7 @@ public function option($option) } /** - * Gets an unique test token. + * Gets a unique test token. * * @return int|false */ diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index e4bb3f8d6045..0f2a3a749551 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -234,7 +234,7 @@ public function assertHeader($headerName, $value = null) } /** - * Asserts that the response does not contains the given header. + * Asserts that the response does not contain the given header. * * @param string $headerName * @return $this @@ -358,7 +358,7 @@ public function assertCookieNotExpired($cookieName) } /** - * Asserts that the response does not contains the given cookie. + * Asserts that the response does not contain the given cookie. * * @param string $cookieName * @return $this diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 4efd422cd711..46fcc8441a17 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1063,7 +1063,7 @@ public function validateIn($attribute, $value, $parameters) } /** - * Validate that the values of an attribute is in another attribute. + * Validate that the values of an attribute are in another attribute. * * @param string $attribute * @param mixed $value @@ -1579,7 +1579,7 @@ public function validateRequiredWith($attribute, $value, $parameters) } /** - * Validate that an attribute exists when all other attributes exists. + * Validate that an attribute exists when all other attributes exist. * * @param string $attribute * @param mixed $value diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 8cea4babb6db..a3c7ea80c4bd 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -1230,7 +1230,7 @@ public function addCustomAttributes(array $customAttributes) } /** - * Set the callback that used to format an implicit attribute.. + * Set the callback that used to format an implicit attribute. * * @param callable|null $formatter * @return $this diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index d2f964a88c15..77b49ddaf42c 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -469,7 +469,7 @@ protected function getAttributesFromAttributeString(string $attributeString) } /** - * Parse the attribute bag in a given attribute string into it's fully-qualified syntax. + * Parse the attribute bag in a given attribute string into its fully-qualified syntax. * * @param string $attributeString * @return string diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php b/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php index 6f2169d69b89..9b79359a57d2 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php @@ -283,7 +283,7 @@ protected function compileEndSwitch() } /** - * Compile an once block into valid PHP. + * Compile a once block into valid PHP. * * @param string|null $id * @return string From 818232948bd04b2601b58d4998955508f5064716 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 1 Feb 2021 15:20:21 +0100 Subject: [PATCH 170/443] [6.x] Fix report method for ViewException (#36110) * Fix report method for ViewException * Update ViewException.php * Apply fixes from StyleCI (#36111) --- .../Console/stubs/exception-render-report.stub | 2 +- .../Foundation/Console/stubs/exception-report.stub | 2 +- src/Illuminate/View/ViewException.php | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub b/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub index 712a40789e76..4d1070c2f687 100644 --- a/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub +++ b/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub @@ -9,7 +9,7 @@ class DummyClass extends Exception /** * Report the exception. * - * @return void + * @return bool|null */ public function report() { diff --git a/src/Illuminate/Foundation/Console/stubs/exception-report.stub b/src/Illuminate/Foundation/Console/stubs/exception-report.stub index 8db5c4f3c2b2..643149863e91 100644 --- a/src/Illuminate/Foundation/Console/stubs/exception-report.stub +++ b/src/Illuminate/Foundation/Console/stubs/exception-report.stub @@ -9,7 +9,7 @@ class DummyClass extends Exception /** * Report the exception. * - * @return void + * @return bool|null */ public function report() { diff --git a/src/Illuminate/View/ViewException.php b/src/Illuminate/View/ViewException.php index 9c9463bc28ac..e6797a29a1e7 100644 --- a/src/Illuminate/View/ViewException.php +++ b/src/Illuminate/View/ViewException.php @@ -3,21 +3,25 @@ namespace Illuminate\View; use ErrorException; +use Illuminate\Container\Container; +use Illuminate\Support\Reflector; class ViewException extends ErrorException { /** * Report the exception. * - * @return void + * @return bool|null */ public function report() { $exception = $this->getPrevious(); - if ($exception && method_exists($exception, 'report')) { - $exception->report(); + if (Reflector::isCallable($reportCallable = [$exception, 'report'])) { + return Container::getInstance()->call($reportCallable); } + + return false; } /** From c26c78cf3bcbaf39e63dcb4a410905c62cb1d282 Mon Sep 17 00:00:00 2001 From: Alexandru Dorash Date: Mon, 1 Feb 2021 16:35:53 +0200 Subject: [PATCH 171/443] Replace direct application class mention by illuminate contract (#36105) Make Eloquent Factory use illuminate contract as reference to application Co-authored-by: Alexandru Doras --- src/Illuminate/Database/Eloquent/Factories/Factory.php | 2 +- tests/Database/DatabaseEloquentFactoryTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index 36f3dad84a8a..abf9d91748ee 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -5,9 +5,9 @@ use Closure; use Faker\Generator; use Illuminate\Container\Container; +use Illuminate\Contracts\Foundation\Application; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Application; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index 7f0935f39e27..47ac43c548aa 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -3,13 +3,13 @@ namespace Illuminate\Tests\Database; use Illuminate\Container\Container; +use Illuminate\Contracts\Foundation\Application; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Model as Eloquent; -use Illuminate\Foundation\Application; use Mockery; use PHPUnit\Framework\TestCase; From 3aa9657c9519b2ab73ab93f3917f750a029bfbcc Mon Sep 17 00:00:00 2001 From: Zing Date: Mon, 1 Feb 2021 22:54:22 +0800 Subject: [PATCH 172/443] [6.x] Fix the return type of spop for phpredis (#36106) * PhpRedis return value of spop compatibility * fix style * use func_get_args() instead of [$key, $count] * Update PhpRedisConnection.php Co-authored-by: Taylor Otwell --- .../Redis/Connections/PhpRedisConnection.php | 2 +- tests/Redis/RedisConnectionTest.php | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index 0950ec97cdcb..0c4015df9880 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -197,7 +197,7 @@ public function brpop(...$arguments) */ public function spop($key, $count = 1) { - return $this->command('spop', [$key, $count]); + return $this->command('spop', func_get_args()); } /** diff --git a/tests/Redis/RedisConnectionTest.php b/tests/Redis/RedisConnectionTest.php index 5326a09dd608..e3a04e6db591 100644 --- a/tests/Redis/RedisConnectionTest.php +++ b/tests/Redis/RedisConnectionTest.php @@ -690,6 +690,33 @@ public function testItSscansForKeys() } } + public function testItSPopsForKeys() + { + foreach ($this->connections() as $redis) { + $members = ['test:spop:1', 'test:spop:2', 'test:spop:3', 'test:spop:4']; + + foreach ($members as $member) { + $redis->sadd('set', $member); + } + + $result = $redis->spop('set'); + $this->assertIsNotArray($result); + $this->assertContains($result, $members); + + $result = $redis->spop('set', 1); + + $this->assertIsArray($result); + $this->assertCount(1, $result); + + $result = $redis->spop('set', 2); + + $this->assertIsArray($result); + $this->assertCount(2, $result); + + $redis->flushAll(); + } + } + public function testPhpRedisScanOption() { foreach ($this->connections() as $redis) { From 6319d94ccaf8169b103813a82139814573ddef09 Mon Sep 17 00:00:00 2001 From: Jonathan Goode Date: Tue, 2 Feb 2021 13:42:30 +0000 Subject: [PATCH 173/443] Add missing articles (#36122) --- src/Illuminate/Auth/GuardHelpers.php | 2 +- .../Broadcasting/Broadcasters/AblyBroadcaster.php | 2 +- .../Broadcasters/UsePusherChannelConventions.php | 2 +- src/Illuminate/Console/Scheduling/Event.php | 4 ++-- .../Database/Eloquent/Concerns/GuardsAttributes.php | 2 +- .../Database/Eloquent/Concerns/HasAttributes.php | 2 +- src/Illuminate/Database/Eloquent/Model.php | 2 +- .../Database/Eloquent/Relations/BelongsToMany.php | 2 +- .../Database/Eloquent/Relations/HasOneOrMany.php | 2 +- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- .../Database/Migrations/MigrationRepositoryInterface.php | 2 +- src/Illuminate/Events/Dispatcher.php | 2 +- src/Illuminate/Foundation/Application.php | 6 +++--- src/Illuminate/Foundation/Console/ServeCommand.php | 2 +- src/Illuminate/Foundation/Http/Kernel.php | 2 +- src/Illuminate/Http/Resources/Json/JsonResource.php | 2 +- src/Illuminate/Http/Resources/MergeValue.php | 2 +- src/Illuminate/Mail/SendQueuedMailable.php | 2 +- src/Illuminate/Notifications/SendQueuedNotifications.php | 2 +- src/Illuminate/Pagination/AbstractPaginator.php | 2 +- src/Illuminate/Queue/Middleware/RateLimited.php | 2 +- src/Illuminate/Queue/WorkerOptions.php | 2 +- src/Illuminate/Redis/Connections/PhpRedisConnection.php | 4 ++-- src/Illuminate/Redis/Connectors/PhpRedisConnector.php | 2 +- src/Illuminate/Routing/Console/ControllerMakeCommand.php | 2 +- src/Illuminate/Support/DateFactory.php | 2 +- src/Illuminate/Support/Str.php | 2 +- src/Illuminate/Support/Stringable.php | 2 +- src/Illuminate/Testing/PendingCommand.php | 2 +- src/Illuminate/Validation/Concerns/FormatsMessages.php | 2 +- src/Illuminate/Validation/ValidationData.php | 2 +- src/Illuminate/View/Compilers/BladeCompiler.php | 2 +- src/Illuminate/View/Compilers/ComponentTagCompiler.php | 2 +- .../View/Compilers/Concerns/CompilesConditionals.php | 2 +- src/Illuminate/View/Concerns/ManagesLayouts.php | 2 +- tests/Foundation/Testing/WormholeTest.php | 8 ++++---- 36 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/Illuminate/Auth/GuardHelpers.php b/src/Illuminate/Auth/GuardHelpers.php index 4d5328c6bc87..aa9ebf9ec64a 100644 --- a/src/Illuminate/Auth/GuardHelpers.php +++ b/src/Illuminate/Auth/GuardHelpers.php @@ -25,7 +25,7 @@ trait GuardHelpers protected $provider; /** - * Determine if current user is authenticated. If not, throw an exception. + * Determine if the current user is authenticated. If not, throw an exception. * * @return \Illuminate\Contracts\Auth\Authenticatable * diff --git a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php index 7857c26dce3f..63927dd0181d 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php @@ -120,7 +120,7 @@ public function broadcast(array $channels, $event, array $payload = []) } /** - * Return true if channel is protected by authentication. + * Return true if the channel is protected by authentication. * * @param string $channel * @return bool diff --git a/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelConventions.php b/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelConventions.php index 07c707ceb046..690cf3d4aca2 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelConventions.php +++ b/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelConventions.php @@ -7,7 +7,7 @@ trait UsePusherChannelConventions { /** - * Return true if channel is protected by authentication. + * Return true if the channel is protected by authentication. * * @param string $channel * @return bool diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 0bfaeaf8c429..a680c1a64cb0 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -87,7 +87,7 @@ class Event public $expiresAt = 1440; /** - * Indicates if the command should run in background. + * Indicates if the command should run in the background. * * @var bool */ @@ -587,7 +587,7 @@ protected function pingCallback($url) } /** - * State that the command should run in background. + * State that the command should run in the background. * * @return $this */ diff --git a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php index 9cbee56764ea..60b510cede60 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php @@ -130,7 +130,7 @@ public static function reguard() } /** - * Determine if current state is "unguarded". + * Determine if the current state is "unguarded". * * @return bool */ diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index aca701dd727b..459b14c73399 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1525,7 +1525,7 @@ protected function hasChanges($changes, $attributes = null) } /** - * Get the attributes that have been changed since last sync. + * Get the attributes that have been changed since the last sync. * * @return array */ diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 528f9ca497a0..575148909050 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1131,7 +1131,7 @@ public function delete() /** * Force a hard delete on a soft deleted model. * - * This method protects developers from running forceDelete when trait is missing. + * This method protects developers from running forceDelete when the trait is missing. * * @return bool|null */ diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 03a47861643c..9e7ed7a53a66 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -569,7 +569,7 @@ public function orderByPivot($column, $direction = 'asc') } /** - * Find a related model by its primary key or return new instance of the related model. + * Find a related model by its primary key or return a new instance of the related model. * * @param mixed $id * @param array $columns diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index fcf71d5a87c3..f09133c8bf6c 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -182,7 +182,7 @@ protected function buildDictionary(Collection $results) } /** - * Find a model by its primary key or return new instance of the related model. + * Find a model by its primary key or return a new instance of the related model. * * @param mixed $id * @param array $columns diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 2185ec641ac6..13d27df32437 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -49,7 +49,7 @@ abstract class Relation protected static $constraints = true; /** - * An array to map class names to their morph names in database. + * An array to map class names to their morph names in the database. * * @var array */ diff --git a/src/Illuminate/Database/Migrations/MigrationRepositoryInterface.php b/src/Illuminate/Database/Migrations/MigrationRepositoryInterface.php index 9d5a134409f0..840a5e1dfce1 100755 --- a/src/Illuminate/Database/Migrations/MigrationRepositoryInterface.php +++ b/src/Illuminate/Database/Migrations/MigrationRepositoryInterface.php @@ -12,7 +12,7 @@ interface MigrationRepositoryInterface public function getRan(); /** - * Get list of migrations. + * Get the list of migrations. * * @param int $steps * @return array diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 5959362bc8ce..d1e5da9e47f2 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -286,7 +286,7 @@ protected function shouldBroadcast(array $payload) } /** - * Check if event should be broadcasted by condition. + * Check if the event should be broadcasted by the condition. * * @param mixed $event * @return bool diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index db29744e018a..f48e2ce76805 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -560,7 +560,7 @@ public function environment(...$environments) } /** - * Determine if application is in local environment. + * Determine if the application is in the local environment. * * @return bool */ @@ -570,7 +570,7 @@ public function isLocal() } /** - * Determine if application is in production environment. + * Determine if the application is in the production environment. * * @return bool */ @@ -1260,7 +1260,7 @@ public function setFallbackLocale($fallbackLocale) } /** - * Determine if application locale is the given locale. + * Determine if the application locale is the given locale. * * @param string $locale * @return bool diff --git a/src/Illuminate/Foundation/Console/ServeCommand.php b/src/Illuminate/Foundation/Console/ServeCommand.php index 20b7f59c8f7f..a41393179530 100644 --- a/src/Illuminate/Foundation/Console/ServeCommand.php +++ b/src/Illuminate/Foundation/Console/ServeCommand.php @@ -149,7 +149,7 @@ protected function port() } /** - * Check if command has reached its max amount of port tries. + * Check if the command has reached its max amount of port tries. * * @return bool */ diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index 656bf0f1d164..ea64ce94255c 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -254,7 +254,7 @@ public function hasMiddleware($middleware) } /** - * Add a new middleware to beginning of the stack if it does not already exist. + * Add a new middleware to the beginning of the stack if it does not already exist. * * @param string $middleware * @return $this diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index 808aa234d5b8..3f2175f4dfe6 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -69,7 +69,7 @@ public static function make(...$parameters) } /** - * Create new anonymous resource collection. + * Create a new anonymous resource collection. * * @param mixed $resource * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection diff --git a/src/Illuminate/Http/Resources/MergeValue.php b/src/Illuminate/Http/Resources/MergeValue.php index ee557e8f3b87..fb6880fb725c 100644 --- a/src/Illuminate/Http/Resources/MergeValue.php +++ b/src/Illuminate/Http/Resources/MergeValue.php @@ -15,7 +15,7 @@ class MergeValue public $data; /** - * Create new merge value instance. + * Create a new merge value instance. * * @param \Illuminate\Support\Collection|\JsonSerializable|array $data * @return void diff --git a/src/Illuminate/Mail/SendQueuedMailable.php b/src/Illuminate/Mail/SendQueuedMailable.php index 99a954750e5b..1009789b4bf0 100644 --- a/src/Illuminate/Mail/SendQueuedMailable.php +++ b/src/Illuminate/Mail/SendQueuedMailable.php @@ -89,7 +89,7 @@ public function failed($e) } /** - * Get number of seconds before a released mailable will be available. + * Get the number of seconds before a released mailable will be available. * * @return mixed */ diff --git a/src/Illuminate/Notifications/SendQueuedNotifications.php b/src/Illuminate/Notifications/SendQueuedNotifications.php index eed7e2204654..d83c8906e366 100644 --- a/src/Illuminate/Notifications/SendQueuedNotifications.php +++ b/src/Illuminate/Notifications/SendQueuedNotifications.php @@ -128,7 +128,7 @@ public function failed($e) } /** - * Get number of seconds before a released notification will be available. + * Get the number of seconds before a released notification will be available. * * @return mixed */ diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index bc1ecf9ddc17..763091067057 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -739,7 +739,7 @@ public function __call($method, $parameters) } /** - * Render the contents of the paginator when casting to string. + * Render the contents of the paginator when casting to a string. * * @return string */ diff --git a/src/Illuminate/Queue/Middleware/RateLimited.php b/src/Illuminate/Queue/Middleware/RateLimited.php index 129741f7a6c7..3dd1b435bdc9 100644 --- a/src/Illuminate/Queue/Middleware/RateLimited.php +++ b/src/Illuminate/Queue/Middleware/RateLimited.php @@ -99,7 +99,7 @@ protected function handleJob($job, $next, array $limits) } /** - * Do not release the job back to the queue if limit is exceeded. + * Do not release the job back to the queue if the limit is exceeded. * * @return $this */ diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 0680f545096c..766f4676029a 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -54,7 +54,7 @@ class WorkerOptions public $force; /** - * Indicates if the worker should stop when queue is empty. + * Indicates if the worker should stop when the queue is empty. * * @var bool */ diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index 7eb11629a58b..fdfd3af1d24a 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -71,7 +71,7 @@ public function mget(array $keys) } /** - * Set the string value in argument as value of the key. + * Set the string value in the argument as the value of the key. * * @param string $key * @param mixed $value @@ -556,7 +556,7 @@ public function disconnect() } /** - * Apply prefix to the given key if necessary. + * Apply a prefix to the given key if necessary. * * @param string $key * @return string diff --git a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php index 090247feba18..37a980a1d779 100644 --- a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php +++ b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php @@ -50,7 +50,7 @@ public function connectToCluster(array $config, array $clusterOptions, array $op } /** - * Build a single cluster seed string from array. + * Build a single cluster seed string from an array. * * @param array $server * @return string diff --git a/src/Illuminate/Routing/Console/ControllerMakeCommand.php b/src/Illuminate/Routing/Console/ControllerMakeCommand.php index 6c78e4a959e5..0bd4b6214da0 100755 --- a/src/Illuminate/Routing/Console/ControllerMakeCommand.php +++ b/src/Illuminate/Routing/Console/ControllerMakeCommand.php @@ -86,7 +86,7 @@ protected function getDefaultNamespace($rootNamespace) /** * Build the class with the given name. * - * Remove the base controller import if we are already in base namespace. + * Remove the base controller import if we are already in the base namespace. * * @param string $name * @return string diff --git a/src/Illuminate/Support/DateFactory.php b/src/Illuminate/Support/DateFactory.php index 72f22231dbf0..e1d0ca14cda8 100644 --- a/src/Illuminate/Support/DateFactory.php +++ b/src/Illuminate/Support/DateFactory.php @@ -217,7 +217,7 @@ public function __call($method, $parameters) return $dateClass::$method(...$parameters); } - // If that fails, create the date with the default class.. + // If that fails, create the date with the default class... $date = $defaultClassName::$method(...$parameters); // If the configured class has an "instance" method, we'll try to pass our date into there... diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 06d32d4f3c81..c1ea0017b782 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -696,7 +696,7 @@ public static function studly($value) } /** - * Returns the portion of string specified by the start and length parameters. + * Returns the portion of the string specified by the start and length parameters. * * @param string $string * @param int $start diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 7cff183756d1..ff5f44c5fded 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -607,7 +607,7 @@ public function studly() } /** - * Returns the portion of string specified by the start and length parameters. + * Returns the portion of the string specified by the start and length parameters. * * @param int $start * @param int|null $length diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index 3e08c53ccee7..e0f4417f607a 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -52,7 +52,7 @@ class PendingCommand protected $expectedExitCode; /** - * Determine if command has executed. + * Determine if the command has executed. * * @var bool */ diff --git a/src/Illuminate/Validation/Concerns/FormatsMessages.php b/src/Illuminate/Validation/Concerns/FormatsMessages.php index e380b6e1807a..39d102a331ba 100644 --- a/src/Illuminate/Validation/Concerns/FormatsMessages.php +++ b/src/Illuminate/Validation/Concerns/FormatsMessages.php @@ -116,7 +116,7 @@ protected function getFromLocalArray($attribute, $lowerRule, $source = null) } /** - * Get the custom error message from translator. + * Get the custom error message from the translator. * * @param string $key * @return string diff --git a/src/Illuminate/Validation/ValidationData.php b/src/Illuminate/Validation/ValidationData.php index 74f552597c1c..86da0fd3a17a 100644 --- a/src/Illuminate/Validation/ValidationData.php +++ b/src/Illuminate/Validation/ValidationData.php @@ -8,7 +8,7 @@ class ValidationData { /** - * Initialize and gather data for given attribute. + * Initialize and gather data for the given attribute. * * @param string $attribute * @param array $masterData diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 1d08d0c0821c..f9b431436a2d 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -100,7 +100,7 @@ class BladeCompiler extends Compiler implements CompilerInterface protected $echoFormat = 'e(%s)'; /** - * Array of footer lines to be added to template. + * Array of footer lines to be added to the template. * * @var array */ diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 77b49ddaf42c..a69a704ec420 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -48,7 +48,7 @@ class ComponentTagCompiler protected $boundAttributes = []; /** - * Create new component tag compiler. + * Create a new component tag compiler. * * @param array $aliases * @param array $namespaces diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php b/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php index 9b79359a57d2..6bae1e1cba4a 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php @@ -7,7 +7,7 @@ trait CompilesConditionals { /** - * Identifier for the first case in switch statement. + * Identifier for the first case in the switch statement. * * @var bool */ diff --git a/src/Illuminate/View/Concerns/ManagesLayouts.php b/src/Illuminate/View/Concerns/ManagesLayouts.php index 785b9fa594de..d7d455933128 100644 --- a/src/Illuminate/View/Concerns/ManagesLayouts.php +++ b/src/Illuminate/View/Concerns/ManagesLayouts.php @@ -175,7 +175,7 @@ public static function parentPlaceholder($section = '') } /** - * Check if section exists. + * Check if the section exists. * * @param string $name * @return bool diff --git a/tests/Foundation/Testing/WormholeTest.php b/tests/Foundation/Testing/WormholeTest.php index 13174e8f189f..e6fbfa13edcf 100644 --- a/tests/Foundation/Testing/WormholeTest.php +++ b/tests/Foundation/Testing/WormholeTest.php @@ -11,17 +11,17 @@ class WormholeTest extends TestCase { public function testCanTravelBackToPresent() { - // Preserve the timelines we want to compare the reality with.. + // Preserve the timelines we want to compare the reality with... $present = now(); $future = now()->addDays(10); - // Travel in time.. + // Travel in time... (new Wormhole(10))->days(); - // Assert we are now in the future.. + // Assert we are now in the future... $this->assertEquals($future->format('Y-m-d'), now()->format('Y-m-d')); - // Assert we can go back to the present.. + // Assert we can go back to the present... $this->assertEquals($present->format('Y-m-d'), Wormhole::back()->format('Y-m-d')); } From 046d11924814cb72c1261cc2cbe16b5c01cb0bcc Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 2 Feb 2021 21:46:31 +0800 Subject: [PATCH 174/443] [8.x] Ensure both Carbon and CarbonImmutable get the same test now (#36117) * [8.x] Ensure both Carbon and CarbonImmutable get the same test now. In project where we might use mixes of Carbon and CarbonImmutable you need to remember to always setTestNow() for both scenario, this PR solved it by ensuring both instance has the same date and time during tests. Signed-off-by: Mior Muhammad Zaki * Refactor test Signed-off-by: Mior Muhammad Zaki --- .../Foundation/Testing/Wormhole.php | 22 +++++++++---------- src/Illuminate/Support/Carbon.php | 10 ++++++++- tests/Support/SupportCarbonTest.php | 10 +++++++++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Wormhole.php b/src/Illuminate/Foundation/Testing/Wormhole.php index ef02e5a26f03..d660fe026a75 100644 --- a/src/Illuminate/Foundation/Testing/Wormhole.php +++ b/src/Illuminate/Foundation/Testing/Wormhole.php @@ -2,7 +2,7 @@ namespace Illuminate\Foundation\Testing; -use Illuminate\Support\Facades\Date; +use Illuminate\Support\Carbon; class Wormhole { @@ -32,7 +32,7 @@ public function __construct($value) */ public function milliseconds($callback = null) { - Date::setTestNow(Date::now()->addMilliseconds($this->value)); + Carbon::setTestNow(Carbon::now()->addMilliseconds($this->value)); return $this->handleCallback($callback); } @@ -45,7 +45,7 @@ public function milliseconds($callback = null) */ public function seconds($callback = null) { - Date::setTestNow(Date::now()->addSeconds($this->value)); + Carbon::setTestNow(Carbon::now()->addSeconds($this->value)); return $this->handleCallback($callback); } @@ -58,7 +58,7 @@ public function seconds($callback = null) */ public function minutes($callback = null) { - Date::setTestNow(Date::now()->addMinutes($this->value)); + Carbon::setTestNow(Carbon::now()->addMinutes($this->value)); return $this->handleCallback($callback); } @@ -71,7 +71,7 @@ public function minutes($callback = null) */ public function hours($callback = null) { - Date::setTestNow(Date::now()->addHours($this->value)); + Carbon::setTestNow(Carbon::now()->addHours($this->value)); return $this->handleCallback($callback); } @@ -84,7 +84,7 @@ public function hours($callback = null) */ public function days($callback = null) { - Date::setTestNow(Date::now()->addDays($this->value)); + Carbon::setTestNow(Carbon::now()->addDays($this->value)); return $this->handleCallback($callback); } @@ -97,7 +97,7 @@ public function days($callback = null) */ public function weeks($callback = null) { - Date::setTestNow(Date::now()->addWeeks($this->value)); + Carbon::setTestNow(Carbon::now()->addWeeks($this->value)); return $this->handleCallback($callback); } @@ -110,7 +110,7 @@ public function weeks($callback = null) */ public function years($callback = null) { - Date::setTestNow(Date::now()->addYears($this->value)); + Carbon::setTestNow(Carbon::now()->addYears($this->value)); return $this->handleCallback($callback); } @@ -122,9 +122,9 @@ public function years($callback = null) */ public static function back() { - Date::setTestNow(); + Carbon::setTestNow(); - return Date::now(); + return Carbon::now(); } /** @@ -137,7 +137,7 @@ protected function handleCallback($callback) { if ($callback) { return tap($callback(), function () { - Date::setTestNow(); + Carbon::setTestNow(); }); } } diff --git a/src/Illuminate/Support/Carbon.php b/src/Illuminate/Support/Carbon.php index 9383c3fd897d..004b27b0751e 100644 --- a/src/Illuminate/Support/Carbon.php +++ b/src/Illuminate/Support/Carbon.php @@ -3,8 +3,16 @@ namespace Illuminate\Support; use Carbon\Carbon as BaseCarbon; +use Carbon\CarbonImmutable as BaseCarbonImmutable; class Carbon extends BaseCarbon { - // + /** + * {@inheritdoc} + */ + public static function setTestNow($testNow = null) + { + BaseCarbon::setTestNow($testNow); + BaseCarbonImmutable::setTestNow($testNow); + } } diff --git a/tests/Support/SupportCarbonTest.php b/tests/Support/SupportCarbonTest.php index ea4a53bfff91..cdd865b8b470 100644 --- a/tests/Support/SupportCarbonTest.php +++ b/tests/Support/SupportCarbonTest.php @@ -4,6 +4,7 @@ use BadMethodCallException; use Carbon\Carbon as BaseCarbon; +use Carbon\CarbonImmutable as BaseCarbonImmutable; use DateTime; use DateTimeInterface; use Illuminate\Support\Carbon; @@ -108,4 +109,13 @@ public function testDeserializationOccursCorrectly() $this->assertInstanceOf(Carbon::class, $deserialized); } + + public function testSetTestNowWillPersistBetweenImmutableAndMutableInstance() + { + Carbon::setTestNow(new Carbon('2017-06-27 13:14:15.000000')); + + $this->assertSame('2017-06-27 13:14:15', Carbon::now()->toDateTimeString()); + $this->assertSame('2017-06-27 13:14:15', BaseCarbon::now()->toDateTimeString()); + $this->assertSame('2017-06-27 13:14:15', BaseCarbonImmutable::now()->toDateTimeString()); + } } From 46e3bfbd7b6a75ecd3846d90095d74649a56cbf7 Mon Sep 17 00:00:00 2001 From: Sina Date: Tue, 2 Feb 2021 17:17:20 +0330 Subject: [PATCH 175/443] [8.x] Support retrieving URL for Sftp adapter (#36120) * Support retrieving URL for Sftp adapter * CS Fix * Update FilesystemAdapter.php Co-authored-by: Taylor Otwell --- src/Illuminate/Filesystem/FilesystemAdapter.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 1c33b9892676..896bfbd6f35a 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -20,6 +20,7 @@ use League\Flysystem\FileExistsException; use League\Flysystem\FileNotFoundException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\Sftp\SftpAdapter as Sftp; use PHPUnit\Framework\Assert as PHPUnit; use Psr\Http\Message\StreamInterface; use RuntimeException; @@ -449,7 +450,7 @@ public function url($path) return $this->driver->getUrl($path); } elseif ($adapter instanceof AwsS3Adapter) { return $this->getAwsUrl($adapter, $path); - } elseif ($adapter instanceof Ftp) { + } elseif ($adapter instanceof Ftp || $adapter instanceof Sftp) { return $this->getFtpUrl($path); } elseif ($adapter instanceof LocalAdapter) { return $this->getLocalUrl($path); From 806082fb559fe595cb17cd6aa8571f03ed287814 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Feb 2021 07:50:12 -0600 Subject: [PATCH 176/443] version --- 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 648a0cd2f21a..236cd15d06f3 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.15'; + const VERSION = '6.20.16'; /** * The base path for the Laravel installation. From 855c98657900463be2b98806e3492bdd817d729b Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 2 Feb 2021 16:06:23 +0200 Subject: [PATCH 177/443] Update exception-render-report.stub (#36123) --- .../Foundation/Console/stubs/exception-render-report.stub | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub b/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub index 76ffbf5ba3c3..4d1070c2f687 100644 --- a/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub +++ b/src/Illuminate/Foundation/Console/stubs/exception-render-report.stub @@ -9,11 +9,7 @@ class DummyClass extends Exception /** * Report the exception. * -<<<<<<< HEAD - * @return bool|void -======= * @return bool|null ->>>>>>> 6.x */ public function report() { From cede001e1362afb6824867853784ac4cca5c77c6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Feb 2021 08:07:13 -0600 Subject: [PATCH 178/443] update --- src/Illuminate/Foundation/Console/stubs/exception-report.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/stubs/exception-report.stub b/src/Illuminate/Foundation/Console/stubs/exception-report.stub index 786e0d2915a3..643149863e91 100644 --- a/src/Illuminate/Foundation/Console/stubs/exception-report.stub +++ b/src/Illuminate/Foundation/Console/stubs/exception-report.stub @@ -9,7 +9,7 @@ class DummyClass extends Exception /** * Report the exception. * - * @return bool|void + * @return bool|null */ public function report() { From 275c78c97e007e4a9d771d4d1caa1c77ebfdcf94 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Feb 2021 08:07:24 -0600 Subject: [PATCH 179/443] version --- 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 8b24c1496c85..648cfc6bcde3 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.26.0'; + const VERSION = '8.26.1'; /** * The base path for the Laravel installation. From 1884c4df4cc0d15b0721897153854c55c5e8ccbf Mon Sep 17 00:00:00 2001 From: leo108 Date: Tue, 2 Feb 2021 22:49:15 +0800 Subject: [PATCH 180/443] Fix incorrect PHPDoc (#36124) --- src/Illuminate/Testing/Concerns/TestDatabases.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php index 5da0b81bd73e..ec58e8e17065 100644 --- a/src/Illuminate/Testing/Concerns/TestDatabases.php +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -100,7 +100,7 @@ protected function ensureSchemaIsUpToDate() * Runs the given callable using the given database. * * @param string $database - * @param callable $database + * @param callable $callable * @return void */ protected function usingDatabase($database, $callable) From 4d171296f393e23171bc6a0ace6978692a4387a5 Mon Sep 17 00:00:00 2001 From: "Gabriel G. Casuso" Date: Tue, 2 Feb 2021 22:32:36 +0100 Subject: [PATCH 181/443] [8.x] Set process timeout to null for load mysql schema into database (#36126) --- src/Illuminate/Database/Schema/MySqlSchemaState.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/MySqlSchemaState.php b/src/Illuminate/Database/Schema/MySqlSchemaState.php index 2d46ebe32355..68b6814a83cb 100644 --- a/src/Illuminate/Database/Schema/MySqlSchemaState.php +++ b/src/Illuminate/Database/Schema/MySqlSchemaState.php @@ -71,7 +71,9 @@ public function load($path) { $command = 'mysql '.$this->connectionString().' --database="${:LARAVEL_LOAD_DATABASE}" < "${:LARAVEL_LOAD_PATH}"'; - $this->makeProcess($command)->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [ + $process = $this->makeProcess($command)->setTimeout(null); + + $process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [ 'LARAVEL_LOAD_PATH' => $path, ])); } From 7d9f008dd1143b191e01443160c78d8d6ae94967 Mon Sep 17 00:00:00 2001 From: pascalbaljet Date: Wed, 3 Feb 2021 10:22:46 +0100 Subject: [PATCH 182/443] Added class() method to ComponentAttributeBag class --- src/Illuminate/View/ComponentAttributeBag.php | 25 +++++++++++++++++++ tests/View/ViewComponentAttributeBagTest.php | 3 +++ 2 files changed, 28 insertions(+) diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index 7a2b9f959ea6..8c99ec0da8db 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -235,6 +235,31 @@ public function prepends($value) return new AppendableAttributeValue($value); } + /** + * Conditionally merge classes into the attribute bag. + * + * @param mixed|array $classList + * @return static + */ + public function class($classList) + { + $classList = Arr::wrap($classList); + + $classes = []; + + foreach ($classList as $class => $constraint) { + // If the "class" value is a numeric key, we can assume + // that no constraint has been specified. + if (is_numeric($class)) { + $classes[] = $constraint; + } elseif ($constraint) { + $classes[] = $class; + } + } + + return $this->merge(['class' => implode(' ', $classes)]); + } + /** * Resolve an appendable attribute value default value. * diff --git a/tests/View/ViewComponentAttributeBagTest.php b/tests/View/ViewComponentAttributeBagTest.php index c91e74589e24..4fab0a42d37e 100644 --- a/tests/View/ViewComponentAttributeBagTest.php +++ b/tests/View/ViewComponentAttributeBagTest.php @@ -27,6 +27,9 @@ public function testAttributeRetrieval() $this->assertSame('font-bold', $bag->get('class')); $this->assertSame('bar', $bag->get('foo', 'bar')); $this->assertSame('font-bold', $bag['class']); + $this->assertSame('class="mt-4 font-bold" name="test"', (string) $bag->class('mt-4')); + $this->assertSame('class="mt-4 font-bold" name="test"', (string) $bag->class(['mt-4'])); + $this->assertSame('class="mt-4 ml-2 font-bold" name="test"', (string) $bag->class(['mt-4', 'ml-2' => true, 'mr-2' => false])); $bag = new ComponentAttributeBag([]); From 2ee67d00c2ef0f185aa33ef0134f175c75c638d0 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 3 Feb 2021 17:37:13 +0000 Subject: [PATCH 183/443] Mixed cannot occur in a union --- src/Illuminate/View/ComponentAttributeBag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index 8c99ec0da8db..889ffd54feec 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -70,7 +70,7 @@ public function has($key) /** * Only include the given attribute from the attribute array. * - * @param mixed|array $keys + * @param mixed $keys * @return static */ public function only($keys) From dfa5420ab6d828ba270d6ae10db59dd02f9811c2 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Thu, 4 Feb 2021 22:23:29 +0800 Subject: [PATCH 184/443] [8.x] Don't pluralise string if string ends with none alphanumeric character (#36137) * [8.x] Don't pluralise string if string ends with none alphanumeric character. Signed-off-by: Mior Muhammad Zaki * Fixes unicode support. Signed-off-by: Mior Muhammad Zaki * Update test name. Signed-off-by: Mior Muhammad Zaki * Add multiple words. Signed-off-by: Mior Muhammad Zaki * Reroder tests. --- src/Illuminate/Support/Pluralizer.php | 2 +- tests/Support/SupportPluralizerTest.php | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Pluralizer.php b/src/Illuminate/Support/Pluralizer.php index e7539a99aff2..5babd0e0e153 100755 --- a/src/Illuminate/Support/Pluralizer.php +++ b/src/Illuminate/Support/Pluralizer.php @@ -69,7 +69,7 @@ class Pluralizer */ public static function plural($value, $count = 2) { - if ((int) abs($count) === 1 || static::uncountable($value)) { + if ((int) abs($count) === 1 || static::uncountable($value) || preg_match('/^(.*)[A-Za-z0-9\x{0080}-\x{FFFF}]$/u', $value) == 0) { return $value; } diff --git a/tests/Support/SupportPluralizerTest.php b/tests/Support/SupportPluralizerTest.php index 5e4f4298ccef..3b6da4a26ac3 100755 --- a/tests/Support/SupportPluralizerTest.php +++ b/tests/Support/SupportPluralizerTest.php @@ -16,6 +16,8 @@ public function testBasicPlural() { $this->assertSame('children', Str::plural('child')); $this->assertSame('cod', Str::plural('cod')); + $this->assertSame('The words', Str::plural('The word')); + $this->assertSame('Bouquetés', Str::plural('Bouqueté')); } public function testCaseSensitiveSingularUsage() @@ -68,6 +70,21 @@ public function testPluralStudlyWithCount() $this->assertPluralStudly('RealHumans', 'RealHuman', -2); } + public function testPluralNotAppliedForStringEndingWithNonAlphanumericCharacter() + { + $this->assertSame('Alien.', Str::plural('Alien.')); + $this->assertSame('Alien!', Str::plural('Alien!')); + $this->assertSame('Alien ', Str::plural('Alien ')); + $this->assertSame('50%', Str::plural('50%')); + } + + public function testPluralAppliedForStringEndingWithNumericCharacter() + { + $this->assertSame('User1s', Str::plural('User1')); + $this->assertSame('User2s', Str::plural('User2')); + $this->assertSame('User3s', Str::plural('User3')); + } + private function assertPluralStudly($expected, $value, $count = 2) { $this->assertSame($expected, Str::pluralStudly($value, $count)); From 87fe04daf668c4c1de9269a003760e677b575fcb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Feb 2021 08:24:02 -0600 Subject: [PATCH 185/443] Apply fixes from StyleCI (#36139) --- tests/Support/SupportPluralizerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/SupportPluralizerTest.php b/tests/Support/SupportPluralizerTest.php index 3b6da4a26ac3..ee3af6e45c04 100755 --- a/tests/Support/SupportPluralizerTest.php +++ b/tests/Support/SupportPluralizerTest.php @@ -77,7 +77,7 @@ public function testPluralNotAppliedForStringEndingWithNonAlphanumericCharacter( $this->assertSame('Alien ', Str::plural('Alien ')); $this->assertSame('50%', Str::plural('50%')); } - + public function testPluralAppliedForStringEndingWithNumericCharacter() { $this->assertSame('User1s', Str::plural('User1')); From 5a33384ee11641465970cd6a0165c3b89e19e89c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Feb 2021 08:36:15 -0600 Subject: [PATCH 186/443] formatting --- src/Illuminate/View/ComponentAttributeBag.php | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index 889ffd54feec..e4a6eef709b8 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -173,6 +173,29 @@ public function exceptProps($keys) return $this->except($props); } + /** + * Conditionally merge classes into the attribute bag. + * + * @param mixed|array $classList + * @return static + */ + public function class($classList) + { + $classList = Arr::wrap($classList); + + $classes = []; + + foreach ($classList as $class => $constraint) { + if (is_numeric($class)) { + $classes[] = $constraint; + } elseif ($constraint) { + $classes[] = $class; + } + } + + return $this->merge(['class' => implode(' ', $classes)]); + } + /** * Merge additional attributes / values into the attribute bag. * @@ -235,31 +258,6 @@ public function prepends($value) return new AppendableAttributeValue($value); } - /** - * Conditionally merge classes into the attribute bag. - * - * @param mixed|array $classList - * @return static - */ - public function class($classList) - { - $classList = Arr::wrap($classList); - - $classes = []; - - foreach ($classList as $class => $constraint) { - // If the "class" value is a numeric key, we can assume - // that no constraint has been specified. - if (is_numeric($class)) { - $classes[] = $constraint; - } elseif ($constraint) { - $classes[] = $class; - } - } - - return $this->merge(['class' => implode(' ', $classes)]); - } - /** * Resolve an appendable attribute value default value. * From 7b99b40e2e190ed44b979f4bc647909c3960fcf0 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Thu, 4 Feb 2021 22:22:33 +0200 Subject: [PATCH 187/443] [6.x] update changelog --- CHANGELOG-6.x.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 71992b608e31..8b7d54876d3f 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,16 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.15...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.16...6.x) + + +## [v6.20.15 (2021-02-02)](https://github.com/laravel/framework/compare/v6.20.15...v6.20.16) + +### Fixed +- Fixed `Illuminate\View\ViewException::report()` ([#36110](https://github.com/laravel/framework/pull/36110)) +- Fixed `Illuminate\Redis\Connections\PhpRedisConnection::spop()` ([#36106](https://github.com/laravel/framework/pull/36106)) + +### Changed +- Typecast page number as integer in `Illuminate\Pagination\AbstractPaginator::resolveCurrentPage()` ([#36055](https://github.com/laravel/framework/pull/36055)) ## [v6.20.15 (2021-01-26)](https://github.com/laravel/framework/compare/v6.20.14...v6.20.15) From d7e3b9b82b20b3a3440cbcb8a8f60914fad33812 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Thu, 4 Feb 2021 22:24:52 +0200 Subject: [PATCH 188/443] [6.x] update changelog --- CHANGELOG-6.x.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 8b7d54876d3f..ee1b7ced29b4 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -3,7 +3,7 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v6.20.16...6.x) -## [v6.20.15 (2021-02-02)](https://github.com/laravel/framework/compare/v6.20.15...v6.20.16) +## [v6.20.16 (2021-02-02)](https://github.com/laravel/framework/compare/v6.20.15...v6.20.16) ### Fixed - Fixed `Illuminate\View\ViewException::report()` ([#36110](https://github.com/laravel/framework/pull/36110)) From 4efad4249f53a9ca98ea60e802cc96bdc1ebad14 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Thu, 4 Feb 2021 22:46:33 +0200 Subject: [PATCH 189/443] [8.x] update changelog --- CHANGELOG-8.x.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index c2974b8af01e..71ebe2bdcd36 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,24 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.25.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.26.0...8.x) + + +## [v8.26.0 (2021-02-02)](https://github.com/laravel/framework/compare/v8.25.0...v8.26.0) + +### Added +- Allow to fillJsonAttribute with encrypted field ([#36063](https://github.com/laravel/framework/pull/36063)) +- Added `Route::missing()` ([#36035](https://github.com/laravel/framework/pull/36035)) +- Added `Illuminate\Support\Str::markdown()` and `Illuminate\Support\Stringable::markdown()` ([#36071](https://github.com/laravel/framework/pull/36071)) +- Support retrieving URL for Sftp adapter ([#36120](https://github.com/laravel/framework/pull/36120)) + +### Fixed +- Fixed issues with dumping PostgreSQL databases that contain multiple schemata ([#36046](https://github.com/laravel/framework/pull/36046)) +- Fixes job batch serialization for PostgreSQL ([#36081](https://github.com/laravel/framework/pull/36081)) +- Fixed `Illuminate\View\ViewException::report()` ([#36110](https://github.com/laravel/framework/pull/36110)) + +### Changed +- Typecast page number as integer in `Illuminate\Pagination\AbstractPaginator::resolveCurrentPage()` ([#36055](https://github.com/laravel/framework/pull/36055)) +- Changed `Illuminate\Testing\ParallelRunner::createApplication()` ([1c11b78](https://github.com/laravel/framework/commit/1c11b7893fa3e9c592f6e85b2b1b0028ddd55645)) ## [v8.25.0 (2021-01-26)](https://github.com/laravel/framework/compare/v8.24.0...v8.25.0) From e47ca2ac92559533d731a82077fcb068e781f266 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Thu, 4 Feb 2021 22:49:14 +0200 Subject: [PATCH 190/443] [8.x] update changelog --- CHANGELOG-8.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 71ebe2bdcd36..3d20cc369a0c 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,12 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.26.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.26.1...8.x) + + +## [v8.26.1 (2021-02-02)](https://github.com/laravel/framework/compare/v8.26.0...v8.26.1) + +### Fixed +- Fixed merge conflict in `src/Illuminate/Foundation/Console/stubs/exception-render-report.stub` ([#36123](https://github.com/laravel/framework/pull/36123)) ## [v8.26.0 (2021-02-02)](https://github.com/laravel/framework/compare/v8.25.0...v8.26.0) From 8e6f4b1296d173e1d48a449763e0941751a71630 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 4 Feb 2021 20:25:41 +0200 Subject: [PATCH 191/443] allow adding multiple columns after a column --- src/Illuminate/Database/Schema/Blueprint.php | 56 +++++++++++++++---- .../DatabaseMySqlSchemaGrammarTest.php | 13 +++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 41ed3d90c361..3f20564bfe1d 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -71,6 +71,13 @@ class Blueprint */ public $temporary = false; + /** + * The column to add new columns after. + * + * @var string + */ + public $after; + /** * Create a new schema blueprint. * @@ -836,14 +843,12 @@ public function unsignedBigInteger($column, $autoIncrement = false) */ public function foreignId($column) { - $this->columns[] = $column = new ForeignIdColumnDefinition($this, [ + return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [ 'type' => 'bigInteger', 'name' => $column, 'autoIncrement' => false, 'unsigned' => true, - ]); - - return $column; + ])); } /** @@ -1189,10 +1194,10 @@ public function uuid($column) */ public function foreignUuid($column) { - return $this->columns[] = new ForeignIdColumnDefinition($this, [ + return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [ 'type' => 'uuid', 'name' => $column, - ]); + ])); } /** @@ -1435,6 +1440,39 @@ public function rememberToken() return $this->string('remember_token', 100)->nullable(); } + /** + * @param string $column + * @param \Closure $callback + * @return void + */ + public function after($column, Closure $callback ) + { + $this->after = $column; + + $callback($this); + + $this->after = null; + } + + /** + * Add a new column definition to the blueprint. + * + * @param \Illuminate\Database\Schema\ColumnDefinition $definition + * @return \Illuminate\Database\Schema\ColumnDefinition + */ + protected function addColumnDefinition($definition) + { + $this->columns[] = $definition; + + if ($this->after) { + $definition->after($this->after); + + $this->after = $definition->name; + } + + return $definition; + } + /** * Add a new index command to the blueprint. * @@ -1504,11 +1542,9 @@ protected function createIndexName($type, array $columns) */ public function addColumn($type, $name, array $parameters = []) { - $this->columns[] = $column = new ColumnDefinition( + return $this->addColumnDefinition(new ColumnDefinition( array_merge(compact('type', 'name'), $parameters) - ); - - return $column; + )); } /** diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index d35d8ab91792..4c8813130677 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -504,6 +504,19 @@ public function testAddingColumnAfterAnotherColumn() $this->assertSame('alter table `users` add `name` varchar(255) not null after `foo`', $statements[0]); } + public function testAddingMultipleColumnsAfterAnotherColumn() + { + $blueprint = new Blueprint('users'); + $blueprint->after('foo', function ($blueprint) { + $blueprint->string('one'); + $blueprint->string('two'); + }); + $blueprint->string('three'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $this->assertCount(1, $statements); + $this->assertSame('alter table `users` add `one` varchar(255) not null after `foo`, add `two` varchar(255) not null after `one`, add `three` varchar(255) not null', $statements[0]); + } + public function testAddingGeneratedColumn() { $blueprint = new Blueprint('products'); From 7e4725495ee79427efda231b89b99d6f89769ead Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 4 Feb 2021 20:29:15 +0200 Subject: [PATCH 192/443] update style --- src/Illuminate/Database/Schema/Blueprint.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 3f20564bfe1d..ae802cd60683 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1441,11 +1441,13 @@ public function rememberToken() } /** + * Add the columns from the callback after the given column. + * * @param string $column * @param \Closure $callback * @return void */ - public function after($column, Closure $callback ) + public function after($column, Closure $callback) { $this->after = $column; From 7fd4510377ae7a7aa9806d1e9190abbe522246c3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Feb 2021 16:38:11 -0600 Subject: [PATCH 193/443] formatting --- src/Illuminate/Database/Schema/Blueprint.php | 70 ++++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index ae802cd60683..622659995410 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1440,41 +1440,6 @@ public function rememberToken() return $this->string('remember_token', 100)->nullable(); } - /** - * Add the columns from the callback after the given column. - * - * @param string $column - * @param \Closure $callback - * @return void - */ - public function after($column, Closure $callback) - { - $this->after = $column; - - $callback($this); - - $this->after = null; - } - - /** - * Add a new column definition to the blueprint. - * - * @param \Illuminate\Database\Schema\ColumnDefinition $definition - * @return \Illuminate\Database\Schema\ColumnDefinition - */ - protected function addColumnDefinition($definition) - { - $this->columns[] = $definition; - - if ($this->after) { - $definition->after($this->after); - - $this->after = $definition->name; - } - - return $definition; - } - /** * Add a new index command to the blueprint. * @@ -1549,6 +1514,41 @@ public function addColumn($type, $name, array $parameters = []) )); } + /** + * Add a new column definition to the blueprint. + * + * @param \Illuminate\Database\Schema\ColumnDefinition $definition + * @return \Illuminate\Database\Schema\ColumnDefinition + */ + protected function addColumnDefinition($definition) + { + $this->columns[] = $definition; + + if ($this->after) { + $definition->after($this->after); + + $this->after = $definition->name; + } + + return $definition; + } + + /** + * Add the columns from the callback after the given column. + * + * @param string $column + * @param \Closure $callback + * @return void + */ + public function after($column, Closure $callback) + { + $this->after = $column; + + $callback($this); + + $this->after = null; + } + /** * Remove a column from the schema blueprint. * From 2ecc0b484aaf5aa356f799f629dde7242e56084f Mon Sep 17 00:00:00 2001 From: Ryan Brereton-Canham <9389421+ryzr@users.noreply.github.com> Date: Sun, 7 Feb 2021 11:01:28 +1030 Subject: [PATCH 194/443] [8.x] Update CallQueuedClosure to catch Throwable/Error (#36159) * Update CallQueuedClosure to catch Throwable/Error - Laravel Version: 8.26.1 - PHP Version: 8.0.0 ### Description: Queued closures that throw an Error will throw again when handled by CallQueuedClosure@failed, as its currently type-hinted for Exceptions only. ### Steps To Reproduce: ```php Bus::chain([ function () { SomeClassThatDoesntExist::throw(); } ])->dispatch(); ``` The above will first throw `Error Class "SomeClassThatDoesntExist" not found`. The queue will attempt to handle it and throw again: `TypeError Illuminate\Queue\CallQueuedClosure::failed(): Argument #1 ($e) must be of type Exception, Error given, called in /var/task/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php on line 261` * style: styleci fixes * Update CallQueuedClosure.php Co-authored-by: Taylor Otwell --- src/Illuminate/Queue/CallQueuedClosure.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Queue/CallQueuedClosure.php b/src/Illuminate/Queue/CallQueuedClosure.php index f101b6f0b996..28e1f35b268a 100644 --- a/src/Illuminate/Queue/CallQueuedClosure.php +++ b/src/Illuminate/Queue/CallQueuedClosure.php @@ -3,7 +3,6 @@ namespace Illuminate\Queue; use Closure; -use Exception; use Illuminate\Bus\Batchable; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Container\Container; @@ -87,10 +86,10 @@ public function onFailure($callback) /** * Handle a job failure. * - * @param \Exception $e + * @param \Throwable $e * @return void */ - public function failed(Exception $e) + public function failed($e) { foreach ($this->failureCallbacks as $callback) { call_user_func($callback instanceof SerializableClosure ? $callback->getClosure() : $callback, $e); From 5306a18340f03ac791d86e3b5de04c7031207e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Mon, 8 Feb 2021 15:46:23 +0100 Subject: [PATCH 195/443] feat: add query log methods to the DB facade (#36177) --- src/Illuminate/Support/Facades/DB.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 47c3ab543fa3..4e32a6f1a0d7 100755 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -26,6 +26,11 @@ * @method static void listen(\Closure $callback) * @method static void rollBack(int $toLevel = null) * @method static void setDefaultConnection(string $name) + * @method static void enableQueryLog() + * @method static void disableQueryLog() + * @method static bool logging() + * @method static array getQueryLog() + * @method static void flushQueryLog() * * @see \Illuminate\Database\DatabaseManager * @see \Illuminate\Database\Connection From 6c77f47ccf1861ec82e663f7e886a6290e3df276 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Tue, 9 Feb 2021 01:49:31 +1100 Subject: [PATCH 196/443] add commonmark as recommended package for Illuminate\Support (#36171) --- src/Illuminate/Support/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 61c69eed0132..657c625c5eb3 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -42,6 +42,7 @@ }, "suggest": { "illuminate/filesystem": "Required to use the composer class (^8.0).", + "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^1.3).", "ramsey/uuid": "Required to use Str::uuid() (^4.0).", "symfony/process": "Required to use the composer class (^5.1.4).", "symfony/var-dumper": "Required to use the dd function (^5.1.4).", From 79b98fe1ca041091bb0c292274c7096f0370a5ab Mon Sep 17 00:00:00 2001 From: jandemsar Date: Mon, 8 Feb 2021 09:53:49 -0500 Subject: [PATCH 197/443] [8.x] Fix Eager loading partially nullable morphTo relations (#36129) * Filter non-empty keys by type * Fix failed style check * Remove unnecessary callback --- src/Illuminate/Database/Eloquent/Relations/MorphTo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index e21764131f72..2f449876fac7 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -164,7 +164,7 @@ protected function gatherKeysByType($type, $keyType) ? array_keys($this->dictionary[$type]) : array_map(function ($modelId) { return (string) $modelId; - }, array_keys($this->dictionary[$type])); + }, array_filter(array_keys($this->dictionary[$type]))); } /** From a5e5afb61c1bd4231b3190bc1bdd9d8a19eb57da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:49:57 +0100 Subject: [PATCH 198/443] feat: add query log methods to the DB facade (#36188) --- src/Illuminate/Support/Facades/DB.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index a249b4a099b4..bcbe62ced0cc 100755 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -24,6 +24,11 @@ * @method static int transactionLevel() * @method static array pretend(\Closure $callback) * @method static void listen(\Closure $callback) + * @method static void enableQueryLog() + * @method static void disableQueryLog() + * @method static bool logging() + * @method static array getQueryLog() + * @method static void flushQueryLog() * * @see \Illuminate\Database\DatabaseManager * @see \Illuminate\Database\Connection From 2f96f8416dd279fcc7633aaf27c35c099e7c4d3a Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Mon, 8 Feb 2021 17:04:18 -0300 Subject: [PATCH 199/443] [8.x] Allow components to use custom attribute bag (#36186) * allow components to use custom attribute bag * Update Component.php Co-authored-by: Taylor Otwell --- src/Illuminate/View/AnonymousComponent.php | 2 +- src/Illuminate/View/Component.php | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php index a7887c5ad83f..516bc9ebeef5 100644 --- a/src/Illuminate/View/AnonymousComponent.php +++ b/src/Illuminate/View/AnonymousComponent.php @@ -48,7 +48,7 @@ public function render() */ public function data() { - $this->attributes = $this->attributes ?: new ComponentAttributeBag; + $this->attributes = $this->attributes ?: $this->newAttributeBag(); return $this->data + ['attributes' => $this->attributes]; } diff --git a/src/Illuminate/View/Component.php b/src/Illuminate/View/Component.php index fb1e448a1c3c..402a13abdc53 100644 --- a/src/Illuminate/View/Component.php +++ b/src/Illuminate/View/Component.php @@ -121,7 +121,7 @@ protected function createBladeViewFromString($factory, $contents) */ public function data() { - $this->attributes = $this->attributes ?: new ComponentAttributeBag; + $this->attributes = $this->attributes ?: $this->newAttributeBag(); return array_merge($this->extractPublicProperties(), $this->extractPublicMethods()); } @@ -266,13 +266,24 @@ public function withName($name) */ public function withAttributes(array $attributes) { - $this->attributes = $this->attributes ?: new ComponentAttributeBag; + $this->attributes = $this->attributes ?: $this->newAttributeBag(); $this->attributes->setAttributes($attributes); return $this; } + /** + * Get a new attribute bag instance. + * + * @param array $attributes + * @return \Illuminate\View\ComponentAttributeBag + */ + protected function newAttributeBag(array $attributes = []) + { + return new ComponentAttributeBag($attributes); + } + /** * Determine if the component should be rendered. * From b6e38e81ba00768b2cb989a4363dc4be3d2de2b6 Mon Sep 17 00:00:00 2001 From: MostafaRabia Date: Tue, 9 Feb 2021 15:57:56 +0200 Subject: [PATCH 200/443] Make height of image working with yahoo (#36201) In yahoo it not show `height` but shows `max-height`. I tested remove `hieght` and show the result on yahoo, google and outlook, it's perfect, but i would prefer use `height` too with it for anything would happen. --- src/Illuminate/Mail/resources/views/html/themes/default.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Mail/resources/views/html/themes/default.css b/src/Illuminate/Mail/resources/views/html/themes/default.css index 350fb838fa6b..2483b11685a3 100644 --- a/src/Illuminate/Mail/resources/views/html/themes/default.css +++ b/src/Illuminate/Mail/resources/views/html/themes/default.css @@ -113,6 +113,7 @@ img { .logo { height: 75px; + max-height: 75px; width: 75px; } From 196aa0410f93e0dfda076df330b761c271f93858 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 9 Feb 2021 16:04:04 +0200 Subject: [PATCH 201/443] make sole relationship friendly (#36200) --- .../Database/Eloquent/Relations/Relation.php | 26 +++++++++++++++++++ .../DatabaseEloquentIntegrationTest.php | 14 ++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 13d27df32437..8f54675e10dd 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -6,6 +6,8 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Database\MultipleRecordsFoundException; use Illuminate\Database\Query\Expression; use Illuminate\Support\Arr; use Illuminate\Support\Traits\ForwardsCalls; @@ -151,6 +153,30 @@ public function getEager() return $this->get(); } + /** + * Execute the query and get the first result if it's the sole matching record. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Model + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + */ + public function sole($columns = ['*']) + { + $result = $this->take(2)->get($columns); + + if ($result->isEmpty()) { + throw (new ModelNotFoundException)->setModel(get_class($this->model)); + } + + if ($result->count() > 1) { + throw new MultipleRecordsFoundException; + } + + return $result->first(); + } + /** * Execute the query as a "select" statement. * diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index c3b33a9d941b..6e0a7e44afa1 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -805,6 +805,20 @@ public function testHasOnMorphToRelationship() $this->assertEquals(1, $photos->count()); } + public function testBelongsToManyRelationshipModelsAreProperlyHydratedWithSoleQuery() + { + $user = EloquentTestUserWithCustomFriendPivot::create(['email' => 'taylorotwell@gmail.com']); + $user->friends()->create(['email' => 'abigailotwell@gmail.com']); + + $user->friends()->get()->each(function ($friend) { + $this->assertTrue($friend->pivot instanceof EloquentTestFriendPivot); + }); + + $soleFriend = $user->friends()->where('email', 'abigailotwell@gmail.com')->sole(); + + $this->assertTrue($soleFriend->pivot instanceof EloquentTestFriendPivot); + } + public function testBelongsToManyRelationshipModelsAreProperlyHydratedOverChunkedRequest() { $user = EloquentTestUser::create(['email' => 'taylorotwell@gmail.com']); From 4880ca605b47608cc10906cd3ab9690c38006932 Mon Sep 17 00:00:00 2001 From: MostafaRabia Date: Tue, 9 Feb 2021 16:19:19 +0200 Subject: [PATCH 202/443] Update layout.blade.php (#36198) The mail design in gmail app wasn't responsive, and I managed to solve the problem. --- src/Illuminate/Mail/resources/views/html/layout.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Mail/resources/views/html/layout.blade.php b/src/Illuminate/Mail/resources/views/html/layout.blade.php index 684e0f7d05e6..21d349b39ea7 100644 --- a/src/Illuminate/Mail/resources/views/html/layout.blade.php +++ b/src/Illuminate/Mail/resources/views/html/layout.blade.php @@ -5,8 +5,6 @@ - - + + From 3d5c09717ea693b8e3475ca8e8e2f966b169ddb8 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Tue, 9 Feb 2021 14:30:06 +0000 Subject: [PATCH 203/443] [8.x] Fixes parallel testing when a database is configured using URLs (#36204) * Fixes parallel testing with databases using URLs * Fixes wording on tests --- .../Testing/Concerns/TestDatabases.php | 17 ++- tests/Testing/Concerns/TestDatabasesTest.php | 108 ++++++++++++++++++ tests/Testing/ParallelConsoleOutputTest.php | 2 +- tests/Testing/ParallelTestingTest.php | 2 +- tests/Testing/TestResponseTest.php | 2 +- 5 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 tests/Testing/Concerns/TestDatabasesTest.php diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php index ec58e8e17065..6dfe56105f1b 100644 --- a/src/Illuminate/Testing/Concerns/TestDatabases.php +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -142,10 +142,19 @@ protected function switchToDatabase($database) $default = config('database.default'); - config()->set( - "database.connections.{$default}.database", - $database, - ); + $url = config("database.connections.{$default}.url"); + + if ($url) { + config()->set( + "database.connections.{$default}.url", + preg_replace('/^(.*)(\/[\w-]*)(\??.*)$/', "$1/{$database}$3", $url), + ); + } else { + config()->set( + "database.connections.{$default}.database", + $database, + ); + } } /** diff --git a/tests/Testing/Concerns/TestDatabasesTest.php b/tests/Testing/Concerns/TestDatabasesTest.php new file mode 100644 index 000000000000..5115ccb50d35 --- /dev/null +++ b/tests/Testing/Concerns/TestDatabasesTest.php @@ -0,0 +1,108 @@ +singleton('config', function () { + return m::mock(Config::class) + ->shouldReceive('get') + ->once() + ->with('database.default', null) + ->andReturn('mysql') + ->getMock(); + }); + + $_SERVER['LARAVEL_PARALLEL_TESTING'] = 1; + } + + public function testSwitchToDatabaseWithoutUrl() + { + DB::shouldReceive('purge')->once(); + + config()->shouldReceive('get') + ->once() + ->with('database.connections.mysql.url', false) + ->andReturn(false); + + config()->shouldReceive('set') + ->once() + ->with('database.connections.mysql.database', 'my_database_test_1'); + + $this->switchToDatabase('my_database_test_1'); + } + + /** + * @dataProvider databaseUrls + */ + public function testSwitchToDatabaseWithUrl($testDatabase, $url, $testUrl) + { + DB::shouldReceive('purge')->once(); + + config()->shouldReceive('get') + ->once() + ->with('database.connections.mysql.url', false) + ->andReturn($url); + + config()->shouldReceive('set') + ->once() + ->with('database.connections.mysql.url', $testUrl); + + $this->switchToDatabase($testDatabase); + } + + public function switchToDatabase($database) + { + $instance = new class { + use TestDatabases; + }; + + $method = new ReflectionMethod($instance, 'switchToDatabase'); + tap($method)->setAccessible(true)->invoke($instance, $database); + } + + public function databaseUrls() + { + return [ + [ + 'my_database_test_1', + 'mysql://root:@127.0.0.1/my_database?charset=utf8mb4', + 'mysql://root:@127.0.0.1/my_database_test_1?charset=utf8mb4', + ], + [ + 'my_database_test_1', + 'mysql://my-user:@localhost/my_database', + 'mysql://my-user:@localhost/my_database_test_1', + ], + [ + 'my-database_test_1', + 'postgresql://my_database_user:@127.0.0.1/my-database?charset=utf8', + 'postgresql://my_database_user:@127.0.0.1/my-database_test_1?charset=utf8', + ], + ]; + } + + public function tearDown(): void + { + parent::tearDown(); + + Container::setInstance(null); + + unset($_SERVER['LARAVEL_PARALLEL_TESTING']); + + m::close(); + } +} diff --git a/tests/Testing/ParallelConsoleOutputTest.php b/tests/Testing/ParallelConsoleOutputTest.php index 130b6ecada6a..1543be66aee3 100644 --- a/tests/Testing/ParallelConsoleOutputTest.php +++ b/tests/Testing/ParallelConsoleOutputTest.php @@ -1,6 +1,6 @@ Date: Mon, 8 Feb 2021 21:20:21 -0500 Subject: [PATCH 204/443] Add query builder map method --- .../Database/Concerns/BuildsQueries.php | 21 +++++++++++++++ .../Database/EloquentWhereTest.php | 27 +++++++++++++++++++ .../Integration/Database/QueryBuilderTest.php | 14 ++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 38b04e8bcdcb..c320f9d58987 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -7,6 +7,7 @@ use Illuminate\Database\RecordsNotFoundException; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; +use Illuminate\Support\Collection; trait BuildsQueries { @@ -149,6 +150,26 @@ public function first($columns = ['*']) return $this->take(1)->get($columns)->first(); } + /** + * Run a map over each item while chunking. + * + * @param callable $callback + * @param int $count + * @return \Illuminate\Support\Collection + */ + public function map(callable $callback, $count = 1000) + { + $collection = Collection::make(); + + $this->chunk($count, function ($items) use ($collection, $callback) { + $items->each(function ($item) use ($collection, $callback) { + $collection->push($callback($item)); + }); + }); + + return $collection; + } + /** * Execute the query and get the first result if it's the sole matching record. * diff --git a/tests/Integration/Database/EloquentWhereTest.php b/tests/Integration/Database/EloquentWhereTest.php index 1d7d5f337328..d9614e5ca5d2 100644 --- a/tests/Integration/Database/EloquentWhereTest.php +++ b/tests/Integration/Database/EloquentWhereTest.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\MultipleRecordsFoundException; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; /** @@ -134,6 +135,32 @@ public function testSoleFailsIfNoRecords() $this->assertSame(UserWhereTest::class, $exception->getModel()); } + + public function testMap() + { + UserWhereTest::create([ + 'name' => 'first-name', + 'email' => 'first-email', + 'address' => 'first-address', + ]); + + UserWhereTest::create([ + 'name' => 'second-name', + 'email' => 'second-email', + 'address' => 'second-address', + ]); + + DB::enableQueryLog(); + + $results = UserWhereTest::orderBy('id')->map(function ($user) { + return $user->name; + }, 1); + + $this->assertCount(2, $results); + $this->assertSame('first-name', $results[0]); + $this->assertSame('second-name', $results[1]); + $this->assertCount(3, DB::getQueryLog()); + } } class UserWhereTest extends Model diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 66a65cbdaa43..b1b7e376261e 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -213,4 +213,18 @@ public function testPaginateWithSpecificColumns() (object) ['title' => 'Bar Post', 'content' => 'Lorem Ipsum.'], ]); } + + public function testMap() + { + DB::enableQueryLog(); + + $results = DB::table('posts')->orderBy('id')->map(function ($post) { + return $post->title; + }, 1); + + $this->assertCount(2, $results); + $this->assertSame('Foo Post', $results[0]); + $this->assertSame('Bar Post', $results[1]); + $this->assertCount(3, DB::getQueryLog()); + } } From 048ac6d49f2f7b2d64eb1695848df4590c38be98 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Feb 2021 08:42:12 -0600 Subject: [PATCH 205/443] rename method --- .../Database/Concerns/BuildsQueries.php | 40 +++++++++---------- .../Database/EloquentWhereTest.php | 4 +- .../Integration/Database/QueryBuilderTest.php | 4 +- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index c320f9d58987..34af0405e723 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -51,6 +51,26 @@ public function chunk($count, callable $callback) return true; } + /** + * Run a map over each item while chunking. + * + * @param callable $callback + * @param int $count + * @return \Illuminate\Support\Collection + */ + public function chunkMap(callable $callback, $count = 1000) + { + $collection = Collection::make(); + + $this->chunk($count, function ($items) use ($collection, $callback) { + $items->each(function ($item) use ($collection, $callback) { + $collection->push($callback($item)); + }); + }); + + return $collection; + } + /** * Execute a callback over each item while chunking. * @@ -150,26 +170,6 @@ public function first($columns = ['*']) return $this->take(1)->get($columns)->first(); } - /** - * Run a map over each item while chunking. - * - * @param callable $callback - * @param int $count - * @return \Illuminate\Support\Collection - */ - public function map(callable $callback, $count = 1000) - { - $collection = Collection::make(); - - $this->chunk($count, function ($items) use ($collection, $callback) { - $items->each(function ($item) use ($collection, $callback) { - $collection->push($callback($item)); - }); - }); - - return $collection; - } - /** * Execute the query and get the first result if it's the sole matching record. * diff --git a/tests/Integration/Database/EloquentWhereTest.php b/tests/Integration/Database/EloquentWhereTest.php index d9614e5ca5d2..7d46a8e34616 100644 --- a/tests/Integration/Database/EloquentWhereTest.php +++ b/tests/Integration/Database/EloquentWhereTest.php @@ -136,7 +136,7 @@ public function testSoleFailsIfNoRecords() $this->assertSame(UserWhereTest::class, $exception->getModel()); } - public function testMap() + public function testChunkMap() { UserWhereTest::create([ 'name' => 'first-name', @@ -152,7 +152,7 @@ public function testMap() DB::enableQueryLog(); - $results = UserWhereTest::orderBy('id')->map(function ($user) { + $results = UserWhereTest::orderBy('id')->chunkMap(function ($user) { return $user->name; }, 1); diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index b1b7e376261e..d9257dc6f309 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -214,11 +214,11 @@ public function testPaginateWithSpecificColumns() ]); } - public function testMap() + public function testChunkMap() { DB::enableQueryLog(); - $results = DB::table('posts')->orderBy('id')->map(function ($post) { + $results = DB::table('posts')->orderBy('id')->chunkMap(function ($post) { return $post->title; }, 1); From 12a67216a839618c3711cd6d053904e1f21247f2 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Tue, 9 Feb 2021 15:10:49 +0000 Subject: [PATCH 206/443] Clear resolved instances from facades (#36206) --- tests/Support/SupportFacadesEventTest.php | 1 + tests/Testing/Concerns/TestDatabasesTest.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/Support/SupportFacadesEventTest.php b/tests/Support/SupportFacadesEventTest.php index 8c62c0826ba1..15c4a4acc7ab 100644 --- a/tests/Support/SupportFacadesEventTest.php +++ b/tests/Support/SupportFacadesEventTest.php @@ -38,6 +38,7 @@ protected function setUp(): void protected function tearDown(): void { Event::clearResolvedInstances(); + Event::setFacadeApplication(null); m::close(); } diff --git a/tests/Testing/Concerns/TestDatabasesTest.php b/tests/Testing/Concerns/TestDatabasesTest.php index 5115ccb50d35..7042bd5362c3 100644 --- a/tests/Testing/Concerns/TestDatabasesTest.php +++ b/tests/Testing/Concerns/TestDatabasesTest.php @@ -100,6 +100,8 @@ public function tearDown(): void parent::tearDown(); Container::setInstance(null); + DB::clearResolvedInstances(); + DB::setFacadeApplication(null); unset($_SERVER['LARAVEL_PARALLEL_TESTING']); From a6680d98f9dadaa363aa7d5218517a08706cee64 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Feb 2021 09:14:54 -0600 Subject: [PATCH 207/443] version --- 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 648cfc6bcde3..a7280e64a32a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.26.1'; + const VERSION = '8.27.0'; /** * The base path for the Laravel installation. From 1e0549a72a3bb1f40e1a0051d2cd57147158f991 Mon Sep 17 00:00:00 2001 From: Markus Machatschek Date: Wed, 10 Feb 2021 15:21:41 +0100 Subject: [PATCH 208/443] [8.x] Fix undefined property with sole query (#36216) * Add test to verify bug * Fix sole query exception undefined property --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- tests/Database/DatabaseEloquentIntegrationTest.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 8f54675e10dd..29131b275e3d 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -167,7 +167,7 @@ public function sole($columns = ['*']) $result = $this->take(2)->get($columns); if ($result->isEmpty()) { - throw (new ModelNotFoundException)->setModel(get_class($this->model)); + throw (new ModelNotFoundException)->setModel(get_class($this->related)); } if ($result->count() > 1) { diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 6e0a7e44afa1..d3a7ffb3a414 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -819,6 +819,13 @@ public function testBelongsToManyRelationshipModelsAreProperlyHydratedWithSoleQu $this->assertTrue($soleFriend->pivot instanceof EloquentTestFriendPivot); } + public function testBelongsToManyRelationshipMissingModelExceptionWithSoleQueryWorks() + { + $this->expectException(ModelNotFoundException::class); + $user = EloquentTestUserWithCustomFriendPivot::create(['email' => 'taylorotwell@gmail.com']); + $user->friends()->where('email', 'abigailotwell@gmail.com')->sole(); + } + public function testBelongsToManyRelationshipModelsAreProperlyHydratedOverChunkedRequest() { $user = EloquentTestUser::create(['email' => 'taylorotwell@gmail.com']); From c086fc59488aa8dbd6a75672aa2dbf6d24c39f84 Mon Sep 17 00:00:00 2001 From: James Funk Date: Wed, 10 Feb 2021 07:24:17 -0700 Subject: [PATCH 209/443] [8.x] Resolving non-instantiables corrupts Container::$with (#36212) * Pop Container:: when using parameter default value, or array for variadic * Adding test for variadic parameter * Style fix --- src/Illuminate/Container/Container.php | 4 + .../ContainerResolveNonInstantiableTest.php | 75 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/Container/ContainerResolveNonInstantiableTest.php diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 765df0d873d8..2cfa72f51bb7 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -985,10 +985,14 @@ protected function resolveClass(ReflectionParameter $parameter) // the value of the dependency, similarly to how we do this with scalars. catch (BindingResolutionException $e) { if ($parameter->isDefaultValueAvailable()) { + array_pop($this->with); + return $parameter->getDefaultValue(); } if ($parameter->isVariadic()) { + array_pop($this->with); + return []; } diff --git a/tests/Container/ContainerResolveNonInstantiableTest.php b/tests/Container/ContainerResolveNonInstantiableTest.php new file mode 100644 index 000000000000..1f39322c40b8 --- /dev/null +++ b/tests/Container/ContainerResolveNonInstantiableTest.php @@ -0,0 +1,75 @@ +make(ParentClass::class, ['i' => 42]); + + $this->assertSame(42, $object->i); + } + + public function testResolvingNonInstantiableWithVariadicRemovesWiths() + { + $container = new Container; + $parent = $container->make(VariadicParentClass::class, ['i' => 42]); + + $this->assertCount(0, $parent->child->objects); + $this->assertSame(42, $parent->i); + } +} + +interface TestInterface +{ +} + +class ParentClass +{ + /** + * @var int + */ + public $i; + + public function __construct(TestInterface $testObject = null, int $i = 0) + { + $this->i = $i; + } +} + +class VariadicParentClass +{ + /** + * @var \Illuminate\Tests\Container\ChildClass + */ + public $child; + + /** + * @var int + */ + public $i; + + public function __construct(ChildClass $child, int $i = 0) + { + $this->child = $child; + $this->i = $i; + } +} + +class ChildClass +{ + /** + * @var array + */ + public $objects; + + public function __construct(TestInterface ...$objects) + { + $this->objects = $objects; + } +} From fe72373ea803871d90f352b3e68ccbd812d5519e Mon Sep 17 00:00:00 2001 From: Paul A Date: Wed, 10 Feb 2021 16:32:46 +0200 Subject: [PATCH 210/443] [8.x] Allow using dot syntax for $responseKey (#36196) * Allow using dot syntax for $responseKey. * Add tests. * Update message. * Formatting. * Update src/Illuminate/Testing/TestResponse.php Co-authored-by: Paul A. Co-authored-by: Taylor Otwell --- src/Illuminate/Testing/TestResponse.php | 6 ++-- tests/Testing/TestResponseTest.php | 46 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 0f2a3a749551..1bfc75285518 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -692,13 +692,13 @@ public function assertJsonMissingValidationErrors($keys = null, $responseKey = ' $json = $this->json(); - if (! array_key_exists($responseKey, $json)) { - PHPUnit::assertArrayNotHasKey($responseKey, $json); + if (! Arr::has($json, $responseKey)) { + PHPUnit::assertTrue(true); return $this; } - $errors = $json[$responseKey]; + $errors = Arr::get($json, $responseKey, []); if (is_null($keys) && count($errors) > 0) { PHPUnit::fail( diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 6c828f01db1c..42d16e72d3fa 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1048,6 +1048,27 @@ public function testAssertJsonMissingValidationErrorsCanFail2() $response->assertJsonMissingValidationErrors('bar'); } + public function testAssertJsonMissingValidationErrorsCanFail3() + { + $this->expectException(AssertionFailedError::class); + + $baseResponse = tap(new Response, function ($response) { + $response->setContent( + json_encode([ + 'data' => [ + 'errors' => [ + 'foo' => ['one'], + ], + ], + ]), + ); + }); + + $response = TestResponse::fromBaseResponse($baseResponse); + + $response->assertJsonMissingValidationErrors('foo', 'data.errors'); + } + public function testAssertJsonMissingValidationErrorsWithoutArgument() { $data = ['status' => 'ok']; @@ -1109,6 +1130,31 @@ public function testAssertJsonMissingValidationErrorsCustomErrorsName() $testResponse->assertJsonMissingValidationErrors('bar', 'data'); } + public function testAssertJsonMissingValidationErrorsNestedCustomErrorsName1() + { + $data = [ + 'status' => 'ok', + 'data' => [ + 'errors' => ['foo' => 'oops'], + ], + ]; + + $testResponse = TestResponse::fromBaseResponse( + (new Response)->setContent(json_encode($data)) + ); + + $testResponse->assertJsonMissingValidationErrors('bar', 'data.errors'); + } + + public function testAssertJsonMissingValidationErrorsNestedCustomErrorsName2() + { + $testResponse = TestResponse::fromBaseResponse( + (new Response)->setContent(json_encode([])) + ); + + $testResponse->assertJsonMissingValidationErrors('bar', 'data.errors'); + } + public function testMacroable() { TestResponse::macro('foo', function () { From 5ab3464b8755293815e57c0de0829feaf7242aae Mon Sep 17 00:00:00 2001 From: Michal Cech Date: Thu, 11 Feb 2021 16:45:46 +0100 Subject: [PATCH 211/443] full trace for http errors (#36219) --- .../Testing/Concerns/InteractsWithExceptionHandling.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php index 40e3d777ffbd..0304940ff061 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php @@ -124,7 +124,7 @@ public function render($request, Throwable $e) if ($e instanceof NotFoundHttpException) { throw new NotFoundHttpException( - "{$request->method()} {$request->url()}", null, $e->getCode() + "{$request->method()} {$request->url()}", $e, $e->getCode() ); } From 07f31a7019e93c29fbdb3a8393ad8a504392ae1d Mon Sep 17 00:00:00 2001 From: foremtehan <53290883+foremtehan@users.noreply.github.com> Date: Fri, 12 Feb 2021 18:18:46 +0330 Subject: [PATCH 212/443] [8.x] `lines` method for File's Docblock (#36237) --- src/Illuminate/Support/Facades/File.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/File.php b/src/Illuminate/Support/Facades/File.php index 2dfad0b2fde2..13cfdde63cfd 100755 --- a/src/Illuminate/Support/Facades/File.php +++ b/src/Illuminate/Support/Facades/File.php @@ -40,6 +40,7 @@ * @method static string|false mimeType(string $path) * @method static void ensureDirectoryExists(string $path, int $mode = 0755, bool $recursive = true) * @method static void link(string $target, string $link) + * @method static \Illuminate\Support\LazyCollection lines(string $path) * @method static void relativeLink(string $target, string $link) * @method static void replace(string $path, string $content) * From a4a5116f2d9b9062c1ef293839ce339715899ba2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Feb 2021 09:05:31 -0600 Subject: [PATCH 213/443] Fix attribute nesting on anonymous components (#36240) * fix attribute nesting * Apply fixes from StyleCI (#36239) * add test * adjust order --- src/Illuminate/View/AnonymousComponent.php | 7 ++++++- tests/Integration/View/BladeTest.php | 7 +++++++ .../View/templates/components/base-input.blade.php | 11 +++++++++++ .../View/templates/components/child-input.blade.php | 1 + .../View/templates/uses-child-input.blade.php | 1 + 5 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/View/templates/components/base-input.blade.php create mode 100644 tests/Integration/View/templates/components/child-input.blade.php create mode 100644 tests/Integration/View/templates/uses-child-input.blade.php diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php index 516bc9ebeef5..2fb21e1afc4a 100644 --- a/src/Illuminate/View/AnonymousComponent.php +++ b/src/Illuminate/View/AnonymousComponent.php @@ -50,6 +50,11 @@ public function data() { $this->attributes = $this->attributes ?: $this->newAttributeBag(); - return $this->data + ['attributes' => $this->attributes]; + return array_merge( + optional($this->data['attributes'] ?? null)->getAttributes() ?: [], + $this->attributes->getAttributes(), + $this->data, + ['attributes' => $this->attributes] + ); } } diff --git a/tests/Integration/View/BladeTest.php b/tests/Integration/View/BladeTest.php index 864a041f5d21..b3d57f8f7776 100644 --- a/tests/Integration/View/BladeTest.php +++ b/tests/Integration/View/BladeTest.php @@ -69,6 +69,13 @@ public function test_appendable_attributes() ', trim($view)); } + public function tested_nested_anonymous_attribute_proxying_works_correctly() + { + $view = View::make('uses-child-input')->render(); + + $this->assertSame('', trim($view)); + } + protected function getEnvironmentSetUp($app) { $app['config']->set('view.paths', [__DIR__.'/templates']); diff --git a/tests/Integration/View/templates/components/base-input.blade.php b/tests/Integration/View/templates/components/base-input.blade.php new file mode 100644 index 000000000000..4d8f09367c55 --- /dev/null +++ b/tests/Integration/View/templates/components/base-input.blade.php @@ -0,0 +1,11 @@ +@props(['disabled' => false]) + +@php +if ($disabled) { + $class = 'disabled-class'; +} else { + $class = 'not-disabled-class'; +} +@endphp + +merge(['class' => $class]) }} {{ $disabled ? 'disabled' : '' }} /> \ No newline at end of file diff --git a/tests/Integration/View/templates/components/child-input.blade.php b/tests/Integration/View/templates/components/child-input.blade.php new file mode 100644 index 000000000000..711e20d4e613 --- /dev/null +++ b/tests/Integration/View/templates/components/child-input.blade.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/Integration/View/templates/uses-child-input.blade.php b/tests/Integration/View/templates/uses-child-input.blade.php new file mode 100644 index 000000000000..bc5bdade5d89 --- /dev/null +++ b/tests/Integration/View/templates/uses-child-input.blade.php @@ -0,0 +1 @@ + \ No newline at end of file From 20a5688e8d4e14faaa6225fcaef4c9b6adb30ac1 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Fri, 12 Feb 2021 09:42:01 -0600 Subject: [PATCH 214/443] Allow users to specify configuration keys to be used for primitive binding Syntactic sugar around fancy calls to `->give()`. ``` $container ->when(ContainerTestContextInjectFromConfigIndividualValues::class) ->needs('$username') ->giveConfig('test.username'); ``` Is the same as: ``` $container ->when(ContainerTestContextInjectFromConfigIndividualValues::class) ->needs('$username') ->give(function () { return config('test.username'); }); ``` and ``` $container ->when(ContainerTestContextInjectFromConfigIndividualValues::class) ->needs('$username') ->give(fn() => config('test.username')); ``` --- .../Container/ContextualBindingBuilder.php | 16 ++ tests/Container/ContextualBindingTest.php | 146 ++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/src/Illuminate/Container/ContextualBindingBuilder.php b/src/Illuminate/Container/ContextualBindingBuilder.php index 5da6ccab388b..d2ff1de07984 100644 --- a/src/Illuminate/Container/ContextualBindingBuilder.php +++ b/src/Illuminate/Container/ContextualBindingBuilder.php @@ -81,4 +81,20 @@ public function giveTagged($tag) return is_array($taggedServices) ? $taggedServices : iterator_to_array($taggedServices); }); } + + /** + * Define configuration key to be used to look up in configuration to bind as a primitive. + * + * @param string $key + * @param ?string $default + * @return void + */ + public function giveConfig($key, $default = null) + { + $this->give(function ($container) use ($key, $default) { + $config = $container->get('config'); + + return $config->get($key, $default); + }); + } } diff --git a/tests/Container/ContextualBindingTest.php b/tests/Container/ContextualBindingTest.php index 17a7d73f00ea..1ddd5ebf8aba 100644 --- a/tests/Container/ContextualBindingTest.php +++ b/tests/Container/ContextualBindingTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Container; +use Illuminate\Config\Repository; use Illuminate\Container\Container; use PHPUnit\Framework\TestCase; @@ -359,6 +360,127 @@ public function testContextualBindingGivesTagsForVariadic() $this->assertInstanceOf(ContainerContextImplementationStub::class, $resolvedInstance->stubs[0]); $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->stubs[1]); } + + public function testContextualBindingGivesValuesFromConfigOptionalValueNull() + { + $container = new Container; + + $container->singleton('config', function () { + return new Repository([ + 'test' => [ + 'username' => 'laravel', + 'password' => 'hunter42', + ], + ]); + }); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$username') + ->giveConfig('test.username'); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$password') + ->giveConfig('test.password'); + + $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); + + $this->assertEquals('laravel', $resolvedInstance->username); + $this->assertEquals('hunter42', $resolvedInstance->password); + $this->assertNull($resolvedInstance->alias); + } + + public function testContextualBindingGivesValuesFromConfigOptionalValueSet() + { + $container = new Container; + + $container->singleton('config', function () { + return new Repository([ + 'test' => [ + 'username' => 'laravel', + 'password' => 'hunter42', + 'alias' => 'lumen', + ], + ]); + }); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$username') + ->giveConfig('test.username'); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$password') + ->giveConfig('test.password'); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$alias') + ->giveConfig('test.alias'); + + $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); + + $this->assertEquals('laravel', $resolvedInstance->username); + $this->assertEquals('hunter42', $resolvedInstance->password); + $this->assertEquals('lumen', $resolvedInstance->alias); + } + + public function testContextualBindingGivesValuesFromConfigWithDefault() + { + $container = new Container; + + $container->singleton('config', function () { + return new Repository([ + 'test' => [ + 'password' => 'hunter42', + ], + ]); + }); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$username') + ->giveConfig('test.username', 'DEFAULT_USERNAME'); + + $container + ->when(ContainerTestContextInjectFromConfigIndividualValues::class) + ->needs('$password') + ->giveConfig('test.password'); + + $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); + + $this->assertEquals('DEFAULT_USERNAME', $resolvedInstance->username); + $this->assertEquals('hunter42', $resolvedInstance->password); + $this->assertNull($resolvedInstance->alias); + } + + public function testContextualBindingGivesValuesFromConfigArray() + { + $container = new Container; + + $container->singleton('config', function () { + return new Repository([ + 'test' => [ + 'username' => 'laravel', + 'password' => 'hunter42', + 'alias' => 'lumen', + ], + ]); + }); + + $container + ->when(ContainerTestContextInjectFromConfigArray::class) + ->needs('$settings') + ->giveConfig('test'); + + $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigArray::class); + + $this->assertEquals('laravel', $resolvedInstance->settings['username']); + $this->assertEquals('hunter42', $resolvedInstance->settings['password']); + $this->assertEquals('lumen', $resolvedInstance->settings['alias']); + } } interface IContainerContextContractStub @@ -474,3 +596,27 @@ public function __construct(ContainerContextNonContractStub $other, IContainerCo $this->stubs = $stubs; } } + +class ContainerTestContextInjectFromConfigIndividualValues +{ + public $username; + public $password; + public $alias = null; + + public function __construct($username, $password, $alias = null) + { + $this->username = $username; + $this->password = $password; + $this->alias = $alias; + } +} + +class ContainerTestContextInjectFromConfigArray +{ + public $settings; + + public function __construct($settings) + { + $this->settings = $settings; + } +} From d5ffd8efdd04b11a2b1199cc7f2148337418191f Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 12 Feb 2021 22:02:52 +0100 Subject: [PATCH 215/443] Remove problem matchers (#36246) --- .github/workflows/tests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 19e95cff1f99..476648be81cc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -48,9 +48,6 @@ jobs: tools: composer:v2 coverage: none - - name: Setup problem matchers - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Set Minimum Guzzle Version uses: nick-invision/retry@v1 with: @@ -100,9 +97,6 @@ jobs: tools: composer:v2 coverage: none - - name: Setup problem matchers - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Set Minimum Guzzle Version uses: nick-invision/retry@v1 with: From 262102b4e1379e4dff9f687ec822b292634d132d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Feb 2021 15:15:27 -0600 Subject: [PATCH 216/443] formatting --- src/Illuminate/Container/ContextualBindingBuilder.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Container/ContextualBindingBuilder.php b/src/Illuminate/Container/ContextualBindingBuilder.php index d2ff1de07984..1d15dcd3da6a 100644 --- a/src/Illuminate/Container/ContextualBindingBuilder.php +++ b/src/Illuminate/Container/ContextualBindingBuilder.php @@ -83,18 +83,16 @@ public function giveTagged($tag) } /** - * Define configuration key to be used to look up in configuration to bind as a primitive. + * Specify the configuration item to bind as a primitive. * - * @param string $key - * @param ?string $default + * @param string $key + * @param ?string $default * @return void */ public function giveConfig($key, $default = null) { $this->give(function ($container) use ($key, $default) { - $config = $container->get('config'); - - return $config->get($key, $default); + return $container->get('config')->get($key, $default); }); } } From 3d4067e40a4eb8bc97b28706676cdd1fbab8f276 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 13 Feb 2021 20:09:37 +0100 Subject: [PATCH 217/443] [8.x] Ensure $prefix is a string (#36254) * Ensure $prefix is a string Because PHP 8.1 will no longer allow it and throw: `rtrim(): Passing null to parameter #1 ($string) of type string is deprecated` * Update prefix() PHPDoc * Update Route.php Co-authored-by: Taylor Otwell --- src/Illuminate/Routing/Route.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 6d3df0c7175f..b56e735a7fa1 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -746,6 +746,8 @@ public function getPrefix() */ public function prefix($prefix) { + $prefix = $prefix ?? ''; + $this->updatePrefixOnAction($prefix); $uri = rtrim($prefix, '/').'/'.ltrim($this->uri, '/'); From ee3187481ced821d3c84482ab23b63efdbe91cf1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 13 Feb 2021 13:17:33 -0600 Subject: [PATCH 218/443] [8.x] ArrayObject + Collection Custom Casts (#36245) * add array and collection object casts * add encrypted counterparts * add test * Apply fixes from StyleCI (#36247) * Fix tests --- .../Database/Eloquent/Casts/ArrayObject.php | 40 ++++++++++ .../Database/Eloquent/Casts/AsArrayObject.php | 35 +++++++++ .../Database/Eloquent/Casts/AsCollection.php | 31 ++++++++ .../Eloquent/Casts/AsEncryptedArrayObject.php | 36 +++++++++ .../Eloquent/Casts/AsEncryptedCollection.php | 32 ++++++++ ...ArrayObjectAndCollectionCustomCastTest.php | 75 +++++++++++++++++++ 6 files changed, 249 insertions(+) create mode 100644 src/Illuminate/Database/Eloquent/Casts/ArrayObject.php create mode 100644 src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php create mode 100644 src/Illuminate/Database/Eloquent/Casts/AsCollection.php create mode 100644 src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php create mode 100644 src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php create mode 100644 tests/Integration/Database/DatabaseArrayObjectAndCollectionCustomCastTest.php diff --git a/src/Illuminate/Database/Eloquent/Casts/ArrayObject.php b/src/Illuminate/Database/Eloquent/Casts/ArrayObject.php new file mode 100644 index 000000000000..596ed836006b --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Casts/ArrayObject.php @@ -0,0 +1,40 @@ +getArrayCopy()); + } + + /** + * Get the instance as an array. + * + * @return array + */ + public function toArray() + { + return $this->getArrayCopy(); + } + + /** + * Get the array that should be JSON serialized. + * + * @return array + */ + public function jsonSerialize() + { + return $this->getArrayCopy(); + } +} diff --git a/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php b/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php new file mode 100644 index 000000000000..8d950e2daff4 --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php @@ -0,0 +1,35 @@ + json_encode($value)]; + } + + public function serialize($model, string $key, $value, array $attributes) + { + return $value->getArrayCopy(); + } + }; + } +} diff --git a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php new file mode 100644 index 000000000000..e96834f6e4d3 --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php @@ -0,0 +1,31 @@ + json_encode($value)]; + } + }; + } +} diff --git a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php new file mode 100644 index 000000000000..b14fa8123e9b --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php @@ -0,0 +1,36 @@ + Crypt::encryptString(json_encode($value))]; + } + + public function serialize($model, string $key, $value, array $attributes) + { + return $value->getArrayCopy(); + } + }; + } +} diff --git a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php new file mode 100644 index 000000000000..bb4f288d4196 --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php @@ -0,0 +1,32 @@ + Crypt::encryptString(json_encode($value))]; + } + }; + } +} diff --git a/tests/Integration/Database/DatabaseArrayObjectAndCollectionCustomCastTest.php b/tests/Integration/Database/DatabaseArrayObjectAndCollectionCustomCastTest.php new file mode 100644 index 000000000000..7f5b8e30f220 --- /dev/null +++ b/tests/Integration/Database/DatabaseArrayObjectAndCollectionCustomCastTest.php @@ -0,0 +1,75 @@ +increments('id'); + $table->text('array_object'); + $table->text('collection'); + $table->timestamps(); + }); + } + + public function test_array_object_and_collection_casting() + { + $model = new TestEloquentModelWithCustomArrayObjectCast; + + $model->array_object = ['name' => 'Taylor']; + $model->collection = collect(['name' => 'Taylor']); + + $model->save(); + + $model = $model->fresh(); + + $this->assertEquals(['name' => 'Taylor'], $model->array_object->toArray()); + $this->assertEquals(['name' => 'Taylor'], $model->collection->toArray()); + + $model->array_object['age'] = 34; + $model->array_object['meta']['title'] = 'Developer'; + + $model->save(); + + $model = $model->fresh(); + + $this->assertEquals([ + 'name' => 'Taylor', + 'age' => 34, + 'meta' => ['title' => 'Developer'], + ], $model->array_object->toArray()); + } +} + +class TestEloquentModelWithCustomArrayObjectCast extends Model +{ + /** + * The attributes that aren't mass assignable. + * + * @var string[] + */ + protected $guarded = []; + + /** + * The attributes that should be cast to native types. + * + * @var array + */ + protected $casts = [ + 'array_object' => AsArrayObject::class, + 'collection' => AsCollection::class, + ]; +} From ac219bf51e76ab067a273600b689f35cd4d146ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Mon, 15 Feb 2021 15:59:35 +0100 Subject: [PATCH 219/443] [8.x] Clean up custom Queue payload between tests (#36271) * Clean up custom Queue payload between tests * StyleCI * Method accepts null * Follow DatabaseServiceProvider where register() method clear booted (#2) models. Signed-off-by: Mior Muhammad Zaki Co-authored-by: Mior Muhammad Zaki --- src/Illuminate/Queue/Queue.php | 2 +- src/Illuminate/Queue/QueueServiceProvider.php | 2 + tests/Integration/Queue/CustomPayloadTest.php | 61 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Queue/CustomPayloadTest.php diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 654d70402899..08a390622602 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -253,7 +253,7 @@ protected function createStringPayload($job, $queue, $data) /** * Register a callback to be executed when creating job payloads. * - * @param callable $callback + * @param callable|null $callback * @return void */ public static function createPayloadUsing($callback) diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index b87e55379579..a4d963c5ac24 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -27,6 +27,8 @@ class QueueServiceProvider extends ServiceProvider implements DeferrableProvider */ public function register() { + Queue::createPayloadUsing(null); + $this->registerManager(); $this->registerConnection(); $this->registerWorker(); diff --git a/tests/Integration/Queue/CustomPayloadTest.php b/tests/Integration/Queue/CustomPayloadTest.php new file mode 100644 index 000000000000..dd7f71ba93b1 --- /dev/null +++ b/tests/Integration/Queue/CustomPayloadTest.php @@ -0,0 +1,61 @@ +app->make(QueueingDispatcher::class); + + $dispatcher->dispatchToQueue(new MyJob); + } +} + +class QueueServiceProvider extends ServiceProvider +{ + public function register() + { + $this->app->bind('one.time.password', function () { + return random_int(1, 10); + }); + + Queue::createPayloadUsing(function () { + $password = $this->app->make('one.time.password'); + + $this->app->offsetUnset('one.time.password'); + + return ['password' => $password]; + }); + } +} + +class MyJob implements ShouldQueue +{ + public $connection = 'sync'; + + public function handle() + { + } +} From ed78a1d526322e2d9b25773e33d5e30b86f625d7 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 15 Feb 2021 09:01:29 -0600 Subject: [PATCH 220/443] add missing import (#36266) the `Expression` class does not exist in the current namespace, so it needs to be imported. --- src/Illuminate/Testing/Constraints/HasInDatabase.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Testing/Constraints/HasInDatabase.php b/src/Illuminate/Testing/Constraints/HasInDatabase.php index 73af3ddc13b7..039ee4425d99 100644 --- a/src/Illuminate/Testing/Constraints/HasInDatabase.php +++ b/src/Illuminate/Testing/Constraints/HasInDatabase.php @@ -3,6 +3,7 @@ namespace Illuminate\Testing\Constraints; use Illuminate\Database\Connection; +use Illuminate\Database\Query\Expression; use PHPUnit\Framework\Constraint\Constraint; class HasInDatabase extends Constraint From 0146a3b4b018494fc0faaaed9facd6bd09854458 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 15 Feb 2021 16:04:20 +0100 Subject: [PATCH 221/443] Ensure null values won't break on PHP 8.1 (#36264) strcasecmp will no longer accept `null` on PHP >= 8.1 --- src/Illuminate/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 944a62e4b372..068cf23790da 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -257,8 +257,8 @@ public function pjax() */ public function prefetch() { - return strcasecmp($this->server->get('HTTP_X_MOZ'), 'prefetch') === 0 || - strcasecmp($this->headers->get('Purpose'), 'prefetch') === 0; + return strcasecmp($this->server->get('HTTP_X_MOZ') ?? '', 'prefetch') === 0 || + strcasecmp($this->headers->get('Purpose') ?? '', 'prefetch') === 0; } /** From aedc04c1528cc96557b19a9f4bb5987404052b5b Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 15 Feb 2021 16:06:32 +0100 Subject: [PATCH 222/443] Align PHP 8.1 behavior (#36262) While not explicitly allowed in the PHPDoc, `e(null)` returns `""` with PHP < 8.1 On PHP >= 8.1, an error is thrown if `null` is passed to `htmlspecialchars`. As `e(null)` is still a common case (for instance via Blade in view templates) I think it's safest to just default the `null` value to an empty string to get the same behavior with the next PHP minor version. --- src/Illuminate/Support/helpers.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index bf110f8918b4..57bdcc294d8f 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -101,7 +101,7 @@ function class_uses_recursive($class) /** * Encode HTML special characters in a string. * - * @param \Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|string $value + * @param \Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|string|null $value * @param bool $doubleEncode * @return string */ @@ -115,7 +115,7 @@ function e($value, $doubleEncode = true) return $value->toHtml(); } - return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', $doubleEncode); + return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8', $doubleEncode); } } From eee817aa38de261ed1c205d9cf9315e4b563d57c Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 15 Feb 2021 16:06:58 +0100 Subject: [PATCH 223/443] Handle directive $value as a string (#36260) - As per PHPDoc `Str::startsWith` and `Str::endsWith` are not supposed to handle `null` values - strncmp() will no longer accept `null` in PHP 8.1 - It needs a `string` in the end (`trim`) so it would be relevant to cast it first. --- src/Illuminate/View/Compilers/BladeCompiler.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index f9b431436a2d..5a530184e20e 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -449,6 +449,8 @@ protected function compileStatement($match) */ protected function callCustomDirective($name, $value) { + $value = $value ?? ''; + if (Str::startsWith($value, '(') && Str::endsWith($value, ')')) { $value = Str::substr($value, 1, -1); } From 3b515cea9cab30e2832ca7b7b9be7923d732cb5e Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 15 Feb 2021 16:07:11 +0100 Subject: [PATCH 224/443] Use explicit flag as default sorting (#36261) PHP 8.1 will no longer support passing `null` as `asort()` flag. --- 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 beaac46fe280..8645ac2cb6f4 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1086,7 +1086,7 @@ public function sort($callback = null) $callback && is_callable($callback) ? uasort($items, $callback) - : asort($items, $callback); + : asort($items, $callback ?? SORT_REGULAR); return new static($items); } From fcc94677e0e2869f5204f22b7f5f147f03aee67f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 15 Feb 2021 09:14:22 -0600 Subject: [PATCH 225/443] format list --- src/Illuminate/Database/Eloquent/Builder.php | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index f9b3f4c6219d..ca84d06cdbc1 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -79,8 +79,25 @@ class Builder * @var string[] */ protected $passthru = [ - 'insert', 'insertOrIgnore', 'insertGetId', 'insertUsing', 'getBindings', 'toSql', 'dump', 'dd', - 'exists', 'doesntExist', 'count', 'min', 'max', 'avg', 'average', 'sum', 'getConnection', 'raw', 'getGrammar', + 'average', + 'avg', + 'count', + 'dd', + 'doesntExist', + 'dump', + 'exists', + 'getBindings', + 'getConnection', + 'getGrammar', + 'insert', + 'insertGetId', + 'insertOrIgnore', + 'insertUsing', + 'max', + 'min', + 'raw', + 'sum', + 'toSql', ]; /** From d9e28dcb1f4a5638b33829d919bd7417321ab39e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 15 Feb 2021 13:03:36 -0600 Subject: [PATCH 226/443] fix middleware group display --- .../Foundation/Console/RouteListCommand.php | 4 +++- src/Illuminate/Routing/Router.php | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index d14e58cf6315..46fbf5ff6256 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -67,6 +67,8 @@ public function __construct(Router $router) */ public function handle() { + $this->router->flushMiddlewareGroups(); + if (empty($this->router->getRoutes())) { return $this->error("Your application doesn't have any routes."); } @@ -163,7 +165,7 @@ protected function displayRoutes(array $routes) } /** - * Get before filters. + * Get the middleware for the route. * * @param \Illuminate\Routing\Route $route * @return string diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index f1912bf0374e..f0f167228050 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -947,6 +947,18 @@ public function pushMiddlewareToGroup($group, $middleware) return $this; } + /** + * Flush the router's middleware groups. + * + * @return $this + */ + public function flushMiddlewareGroups() + { + $this->middlewareGroups = []; + + return $this; + } + /** * Add a new route parameter binder. * From af3a651ad6ae3e90bd673fe7a6bfc1ce9e569d25 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 15 Feb 2021 16:04:43 -0600 Subject: [PATCH 227/443] add view path method --- src/Illuminate/Foundation/Application.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index a7280e64a32a..8f4137f38bf5 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -486,6 +486,21 @@ public function resourcePath($path = '') return $this->basePath.DIRECTORY_SEPARATOR.'resources'.($path ? DIRECTORY_SEPARATOR.$path : $path); } + /** + * Get the path to the views directory. + * + * This method returns the first configured path in the array of view paths. + * + * @param string $path + * @return string + */ + public function viewPath($path = '') + { + $basePath = $this['config']->get('view.paths')[0]; + + return rtrim($basePath, DIRECTORY_SEPARATOR).($path ? DIRECTORY_SEPARATOR.$path : $path); + } + /** * Get the path to the environment file directory. * From c0e07808606b591e9591d52f22552ebf257f399c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Feb 2021 08:16:34 -0600 Subject: [PATCH 228/443] version --- 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 8f4137f38bf5..32c9ff9cae48 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.27.0'; + const VERSION = '8.28.0'; /** * The base path for the Laravel installation. From e23253c09c9991b6ed84d3871b30f0d5bf7acbeb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Feb 2021 12:04:38 -0600 Subject: [PATCH 229/443] Revert "[8.x] Clean up custom Queue payload between tests (#36271)" (#36287) This reverts commit ac219bf51e76ab067a273600b689f35cd4d146ee. --- src/Illuminate/Queue/Queue.php | 2 +- src/Illuminate/Queue/QueueServiceProvider.php | 2 - tests/Integration/Queue/CustomPayloadTest.php | 61 ------------------- 3 files changed, 1 insertion(+), 64 deletions(-) delete mode 100644 tests/Integration/Queue/CustomPayloadTest.php diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 08a390622602..654d70402899 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -253,7 +253,7 @@ protected function createStringPayload($job, $queue, $data) /** * Register a callback to be executed when creating job payloads. * - * @param callable|null $callback + * @param callable $callback * @return void */ public static function createPayloadUsing($callback) diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index a4d963c5ac24..b87e55379579 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -27,8 +27,6 @@ class QueueServiceProvider extends ServiceProvider implements DeferrableProvider */ public function register() { - Queue::createPayloadUsing(null); - $this->registerManager(); $this->registerConnection(); $this->registerWorker(); diff --git a/tests/Integration/Queue/CustomPayloadTest.php b/tests/Integration/Queue/CustomPayloadTest.php deleted file mode 100644 index dd7f71ba93b1..000000000000 --- a/tests/Integration/Queue/CustomPayloadTest.php +++ /dev/null @@ -1,61 +0,0 @@ -app->make(QueueingDispatcher::class); - - $dispatcher->dispatchToQueue(new MyJob); - } -} - -class QueueServiceProvider extends ServiceProvider -{ - public function register() - { - $this->app->bind('one.time.password', function () { - return random_int(1, 10); - }); - - Queue::createPayloadUsing(function () { - $password = $this->app->make('one.time.password'); - - $this->app->offsetUnset('one.time.password'); - - return ['password' => $password]; - }); - } -} - -class MyJob implements ShouldQueue -{ - public $connection = 'sync'; - - public function handle() - { - } -} From 73dd43d92fcde6c6abc00658ae33391397ca119d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Feb 2021 12:07:44 -0600 Subject: [PATCH 230/443] version --- 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 32c9ff9cae48..e1a302521061 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.28.0'; + const VERSION = '8.28.1'; /** * The base path for the Laravel installation. From 34d58b5222a1dbd07c3bc2a3645394331744b509 Mon Sep 17 00:00:00 2001 From: Patrick O'Meara Date: Thu, 18 Feb 2021 00:50:33 +1100 Subject: [PATCH 231/443] Check for closure before class exists (#36293) * class_exists on a closure throws an exception in PHP8 --- src/Illuminate/Routing/Router.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index f0f167228050..dfdb7ae7332e 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -712,7 +712,13 @@ public function gatherRouteMiddleware(Route $route) })->flatten()->reject(function ($name) use ($excluded) { if (empty($excluded)) { return false; - } elseif (in_array($name, $excluded, true)) { + } + + if ($name instanceof Closure) { + return false; + } + + if (in_array($name, $excluded, true)) { return true; } From 3c89871ca2fb83c9aad87576d47c5694824c21f2 Mon Sep 17 00:00:00 2001 From: Sibghatullah Mujaddid Date: Wed, 17 Feb 2021 21:51:11 +0800 Subject: [PATCH 232/443] The label for page number in pagination should always be as string (#36292) --- src/Illuminate/Pagination/LengthAwarePaginator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Pagination/LengthAwarePaginator.php b/src/Illuminate/Pagination/LengthAwarePaginator.php index 0260b974bc4b..3e5adad0a316 100644 --- a/src/Illuminate/Pagination/LengthAwarePaginator.php +++ b/src/Illuminate/Pagination/LengthAwarePaginator.php @@ -109,7 +109,7 @@ protected function linkCollection() return collect($item)->map(function ($url, $page) { return [ 'url' => $url, - 'label' => $page, + 'label' => (string) $page, 'active' => $this->currentPage() === $page, ]; }); From 4aefa5408c403d999ae21266222a66368671fc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Wed, 17 Feb 2021 14:56:25 +0100 Subject: [PATCH 233/443] [8.x] Clean up custom Queue payload between tests (#36295) * Clean up custom Queue payload between tests * StyleCI * Method accepts null * Use Illuminate\Foundation\Testing\TestCase instead of (#3) Orchestra\Testbench\TestCase Signed-off-by: Mior Muhammad Zaki Co-authored-by: Mior Muhammad Zaki --- .../Foundation/Testing/TestCase.php | 3 + src/Illuminate/Queue/Queue.php | 2 +- tests/Integration/Queue/CustomPayloadTest.php | 64 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Queue/CustomPayloadTest.php diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index 6bbc653102da..ee19a864b591 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -6,6 +6,7 @@ use Carbon\CarbonImmutable; use Illuminate\Console\Application as Artisan; use Illuminate\Database\Eloquent\Model; +use Illuminate\Queue\Queue; use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\ParallelTesting; use Illuminate\Support\Str; @@ -199,6 +200,8 @@ protected function tearDown(): void Artisan::forgetBootstrappers(); + Queue::createPayloadUsing(null); + if ($this->callbackException) { throw $this->callbackException; } diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 654d70402899..08a390622602 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -253,7 +253,7 @@ protected function createStringPayload($job, $queue, $data) /** * Register a callback to be executed when creating job payloads. * - * @param callable $callback + * @param callable|null $callback * @return void */ public static function createPayloadUsing($callback) diff --git a/tests/Integration/Queue/CustomPayloadTest.php b/tests/Integration/Queue/CustomPayloadTest.php new file mode 100644 index 000000000000..3d1088b52c4d --- /dev/null +++ b/tests/Integration/Queue/CustomPayloadTest.php @@ -0,0 +1,64 @@ +app->make(QueueingDispatcher::class); + + $dispatcher->dispatchToQueue(new MyJob); + } +} + +class QueueServiceProvider extends ServiceProvider +{ + public function register() + { + $this->app->bind('one.time.password', function () { + return random_int(1, 10); + }); + + Queue::createPayloadUsing(function () { + $password = $this->app->make('one.time.password'); + + $this->app->offsetUnset('one.time.password'); + + return ['password' => $password]; + }); + } +} + +class MyJob implements ShouldQueue +{ + public $connection = 'sync'; + + public function handle() + { + } +} From e66fb52eab0a3e5fee1aa400bbc94f2882883e5a Mon Sep 17 00:00:00 2001 From: Will Browning <20662079+willbrowningme@users.noreply.github.com> Date: Wed, 17 Feb 2021 14:46:56 +0000 Subject: [PATCH 234/443] Fix flushDb (cache:clear) for redis clusters (#36281) When running `php artisan cache:clear` with a redis cluster, the flushDb() function is currently unable to run on each master if you are using a password or TLS scheme - https://github.com/laravel/framework/issues/35180 For redis clusters an empty `$config` array is passed through to the constructor of `vendor\laravel\framework\src\Illuminate\Redis\Connections\PhpRedisConnection.php` causing authentication to fail. However, even if you update `vendor\laravel\framework\src\Illuminate\Redis\Connectors\PhpRedisConnector.php` to pass through the cluster password it still fails because `$redis = tap(new Redis)->connect($host, $port);` does not connect to each master node using the correct TLS scheme or any steam context such as `local_cert`, `local_pk`, `cafile` or `verify_peer_name`. This pull request fixes the issue by using `Directed node commands` as described here - https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands It uses the already authenticated `RedisCluster` connection with correct scheme and context to direct the `flushdb` command to each master node to succesfully clear the cache. --- .../Redis/Connections/PhpRedisConnection.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index de9263029c2f..86e239e6f118 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -501,14 +501,8 @@ public function flushdb() return $this->command('flushdb'); } - foreach ($this->client->_masters() as [$host, $port]) { - $redis = tap(new Redis)->connect($host, $port); - - if (isset($this->config['password']) && ! empty($this->config['password'])) { - $redis->auth($this->config['password']); - } - - $redis->flushDb(); + foreach ($this->client->_masters() as $master) { + $this->client->flushDb($master); } } From 918db609866061fe421c1d124ab98cec535ea278 Mon Sep 17 00:00:00 2001 From: SPie Date: Wed, 17 Feb 2021 17:24:09 +0100 Subject: [PATCH 235/443] Removed filter on username for redis configuration parameter. (#36299) --- src/Illuminate/Redis/RedisManager.php | 2 +- tests/Redis/RedisConnectorTest.php | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 3dd4ec73e34f..3d01818da2ae 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -192,7 +192,7 @@ protected function parseConnectionConfiguration($config) } return array_filter($parsed, function ($key) { - return ! in_array($key, ['driver', 'username'], true); + return ! in_array($key, ['driver'], true); }, ARRAY_FILTER_USE_KEY); } diff --git a/tests/Redis/RedisConnectorTest.php b/tests/Redis/RedisConnectorTest.php index ff5f93470e8d..965ef46eb69a 100644 --- a/tests/Redis/RedisConnectorTest.php +++ b/tests/Redis/RedisConnectorTest.php @@ -161,4 +161,27 @@ public function testScheme() $this->assertSame("tcp://{$host}", $phpRedisClient->getHost()); $this->assertEquals($port, $phpRedisClient->getPort()); } + + public function testPredisConfigurationWithUsername() + { + $host = env('REDIS_HOST', '127.0.0.1'); + $port = env('REDIS_PORT', 6379); + $username = 'testuser'; + $password = 'testpw'; + + $predis = new RedisManager(new Application, 'predis', [ + 'default' => [ + 'host' => $host, + 'port' => $port, + 'username' => $username, + 'password' => $password, + 'database' => 5, + 'timeout' => 0.5, + ], + ]); + $predisClient = $predis->connection()->client(); + $parameters = $predisClient->getConnection()->getParameters(); + $this->assertEquals($username, $parameters->username); + $this->assertEquals($password, $parameters->password); + } } From 16ab3237bcf232195476aa2530a8f747f5705a4a Mon Sep 17 00:00:00 2001 From: Geoff Garbers Date: Wed, 17 Feb 2021 19:55:19 +0200 Subject: [PATCH 236/443] [8.x] Make use of specified ownerKey in MorphTo::associate() (attempt #2) (#36303) * Check ownerKey first, before defaulting to getKeyName. * Fix tests for fetching ownerKey. --- src/Illuminate/Database/Eloquent/Relations/MorphTo.php | 2 +- tests/Database/DatabaseEloquentMorphToTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index 2f449876fac7..8a6c7a2cbca8 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -226,7 +226,7 @@ protected function matchToMorphParents($type, Collection $results) public function associate($model) { $this->parent->setAttribute( - $this->foreignKey, $model instanceof Model ? $model->getKey() : null + $this->foreignKey, $model instanceof Model ? $model->{$this->ownerKey ?: $model->getKeyName()} : null ); $this->parent->setAttribute( diff --git a/tests/Database/DatabaseEloquentMorphToTest.php b/tests/Database/DatabaseEloquentMorphToTest.php index a6bd248ff563..0b0741de406c 100644 --- a/tests/Database/DatabaseEloquentMorphToTest.php +++ b/tests/Database/DatabaseEloquentMorphToTest.php @@ -132,7 +132,7 @@ public function testAssociateMethodSetsForeignKeyAndTypeOnModel() $relation = $this->getRelationAssociate($parent); $associate = m::mock(Model::class); - $associate->shouldReceive('getKey')->once()->andReturn(1); + $associate->shouldReceive('getAttribute')->once()->andReturn(1); $associate->shouldReceive('getMorphClass')->once()->andReturn('Model'); $parent->shouldReceive('setAttribute')->once()->with('foreign_key', 1); From a48d4b8c37f0ffbe649b318dc69adb0c5ae12531 Mon Sep 17 00:00:00 2001 From: Victor Dauchy <26772554+vdauchy@users.noreply.github.com> Date: Thu, 18 Feb 2021 10:10:24 -0500 Subject: [PATCH 237/443] Facades/URL phpdoc update (#36307) --- src/Illuminate/Support/Facades/URL.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Facades/URL.php b/src/Illuminate/Support/Facades/URL.php index 05866345fea5..7d9941d7c027 100755 --- a/src/Illuminate/Support/Facades/URL.php +++ b/src/Illuminate/Support/Facades/URL.php @@ -10,6 +10,8 @@ * @method static string secureAsset(string $path) * @method static string current() * @method static string full() + * @method static void macro(string $name, object|callable $macro) + * @method static void mixin(object $mixin, bool $replace = true) * @method static string previous($fallback = false) * @method static string route(string $name, $parameters = [], bool $absolute = true) * @method static string secure(string $path, array $parameters = []) From aeb0bf52354a7b790c70c00aba60674cc384097a Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 18 Feb 2021 15:11:09 +0000 Subject: [PATCH 238/443] Adds "setUpTestDatabase" support to Parallel Testing (#36301) --- .../Testing/Concerns/TestDatabases.php | 36 +++++++++++-------- src/Illuminate/Testing/ParallelTesting.php | 36 +++++++++++++++++++ tests/Testing/ParallelTestingTest.php | 1 + 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php index 6dfe56105f1b..7f81c604bcdc 100644 --- a/src/Illuminate/Testing/Concerns/TestDatabases.php +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -47,13 +47,17 @@ protected function bootTestDatabase() if (Arr::hasAny($uses, $databaseTraits)) { $this->whenNotUsingInMemoryDatabase(function ($database) use ($uses) { - $testDatabase = $this->ensureTestDatabaseExists($database); + [$testDatabase, $created] = $this->ensureTestDatabaseExists($database); $this->switchToDatabase($testDatabase); if (isset($uses[Testing\DatabaseTransactions::class])) { $this->ensureSchemaIsUpToDate(); } + + if ($created) { + ParallelTesting::callSetUpTestDatabaseCallbacks($testDatabase); + } }); } }); @@ -64,22 +68,26 @@ protected function bootTestDatabase() * * @param string $database * - * @return string + * @return array */ protected function ensureTestDatabaseExists($database) { - return tap($this->testDatabase($database), function ($testDatabase) use ($database) { - try { - $this->usingDatabase($testDatabase, function () { - Schema::hasTable('dummy'); - }); - } catch (QueryException $e) { - $this->usingDatabase($database, function () use ($testDatabase) { - Schema::dropDatabaseIfExists($testDatabase); - Schema::createDatabase($testDatabase); - }); - } - }); + $testDatabase = $this->testDatabase($database); + + try { + $this->usingDatabase($testDatabase, function () { + Schema::hasTable('dummy'); + }); + } catch (QueryException $e) { + $this->usingDatabase($database, function () use ($testDatabase) { + Schema::dropDatabaseIfExists($testDatabase); + Schema::createDatabase($testDatabase); + }); + + return [$testDatabase, true]; + } + + return [$testDatabase, false]; } /** diff --git a/src/Illuminate/Testing/ParallelTesting.php b/src/Illuminate/Testing/ParallelTesting.php index 842b809f822f..11ebcfa89ed6 100644 --- a/src/Illuminate/Testing/ParallelTesting.php +++ b/src/Illuminate/Testing/ParallelTesting.php @@ -42,6 +42,13 @@ class ParallelTesting */ protected $setUpTestCaseCallbacks = []; + /** + * All of the registered "setUp" test database callbacks. + * + * @var array + */ + protected $setUpTestDatabaseCallbacks = []; + /** * All of the registered "tearDown" process callbacks. * @@ -111,6 +118,17 @@ public function setUpTestCase($callback) $this->setUpTestCaseCallbacks[] = $callback; } + /** + * Register a "setUp" test database callback. + * + * @param callable $callback + * @return void + */ + public function setUpTestDatabase($callback) + { + $this->setUpTestDatabaseCallbacks[] = $callback; + } + /** * Register a "tearDown" process callback. * @@ -167,6 +185,24 @@ public function callSetUpTestCaseCallbacks($testCase) }); } + /** + * Call all of the "setUp" test database callbacks. + * + * @param string $database + * @return void + */ + public function callSetUpTestDatabaseCallbacks($database) + { + $this->whenRunningInParallel(function () use ($database) { + foreach ($this->setUpTestDatabaseCallbacks as $callback) { + $this->container->call($callback, [ + 'database' => $database, + 'token' => $this->token(), + ]); + } + }); + } + /** * Call all of the "tearDown" process callbacks. * diff --git a/tests/Testing/ParallelTestingTest.php b/tests/Testing/ParallelTestingTest.php index 802eddfbc0ae..d7a0406019ed 100644 --- a/tests/Testing/ParallelTestingTest.php +++ b/tests/Testing/ParallelTestingTest.php @@ -83,6 +83,7 @@ public function callbacks() return [ ['setUpProcess'], ['setUpTestCase'], + ['setUpTestDatabase'], ['tearDownTestCase'], ['tearDownProcess'], ]; From 5fd4e39310e3163bc15fa7db2e7b9f34f3e5d8e8 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 18 Feb 2021 16:51:31 +0100 Subject: [PATCH 239/443] Update changelog --- CHANGELOG-8.x.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 3d20cc369a0c..8e03e4d36aa9 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,59 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.26.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.28.1...8.x) + + +## [v8.28.1 (2021-02-16)](https://github.com/laravel/framework/compare/v8.28.0...v8.28.1) + +### Fixed +- Revert "[8.x] Clean up custom Queue payload between tests" ([#36287](https://github.com/laravel/framework/pull/36287)) + + +## [v8.28.0 (2021-02-16)](https://github.com/laravel/framework/compare/v8.27.0...v8.28.0) + +### Added +- Allow users to specify configuration keys to be used for primitive binding ([#36241](https://github.com/laravel/framework/pull/36241)) +- ArrayObject + Collection Custom Casts ([#36245](https://github.com/laravel/framework/pull/36245)) +- Add view path method ([af3a651](https://github.com/laravel/framework/commit/af3a651ad6ae3e90bd673fe7a6bfc1ce9e569d25)) + +### Changed +- Allow using dot syntax for `$responseKey` ([#36196](https://github.com/laravel/framework/pull/36196)) +- Full trace for http errors ([#36219](https://github.com/laravel/framework/pull/36219)) + +### Fixed +- Fix undefined property with sole query ([#36216](https://github.com/laravel/framework/pull/36216)) +- Resolving non-instantiables corrupts `Container::$with` ([#36212](https://github.com/laravel/framework/pull/36212)) +- Fix attribute nesting on anonymous components ([#36240](https://github.com/laravel/framework/pull/36240)) +- Ensure `$prefix` is a string ([#36254](https://github.com/laravel/framework/pull/36254)) +- Add missing import ([#34569](https://github.com/laravel/framework/pull/34569)) +- Align PHP 8.1 behavior of `e()` ([#36262](https://github.com/laravel/framework/pull/36262)) +- Ensure null values won't break on PHP 8.1 ([#36264](https://github.com/laravel/framework/pull/36264)) +- Handle directive `$value` as a string ([#36260](https://github.com/laravel/framework/pull/36260)) +- Use explicit flag as default sorting ([#36261](https://github.com/laravel/framework/pull/36261)) +- Fix middleware group display ([d9e28dc](https://github.com/laravel/framework/commit/d9e28dcb1f4a5638b33829d919bd7417321ab39e)) + + +## [v8.27.0 (2021-02-09)](https://github.com/laravel/framework/compare/v8.26.1...v8.27.0) + +### Added +- Conditionally merge classes into a Blade Component attribute bag ([#36131](https://github.com/laravel/framework/pull/36131)) +- Allow adding multiple columns after a column ([#36145](https://github.com/laravel/framework/pull/36145)) +- Add query builder `chunkMap` method ([#36193](https://github.com/laravel/framework/pull/36193), [048ac6d](https://github.com/laravel/framework/commit/048ac6d49f2f7b2d64eb1695848df4590c38be98)) + +### Changed +- Update CallQueuedClosure to catch Throwable/Error ([#36159](https://github.com/laravel/framework/pull/36159)) +- Allow components to use custom attribute bag ([#36186](https://github.com/laravel/framework/pull/36186)) + +### Fixed +- Set process timeout to null for load mysql schema into database ([#36126](https://github.com/laravel/framework/pull/36126)) +- Don't pluralise string if string ends with none alphanumeric character ([#36137](https://github.com/laravel/framework/pull/36137)) +- Add query log methods to the DB facade ([#36177](https://github.com/laravel/framework/pull/36177)) +- Add commonmark as recommended package for `Illuminate\Support` ([#36171](https://github.com/laravel/framework/pull/36171)) +- Fix Eager loading partially nullable morphTo relations ([#36129](https://github.com/laravel/framework/pull/36129)) +- Make height of image working with yahoo ([#36201](https://github.com/laravel/framework/pull/36201)) +- Make `sole()` relationship friendly ([#36200](https://github.com/laravel/framework/pull/36200)) +- Make layout in mail responsive in Gmail app ([#36198](https://github.com/laravel/framework/pull/36198)) +- Fixes parallel testing when a database is configured using URLs ([#36204](https://github.com/laravel/framework/pull/36204)) ## [v8.26.1 (2021-02-02)](https://github.com/laravel/framework/compare/v8.26.0...v8.26.1) From 3c66f6cda2ac4ee2844a67fc98e676cb170ff4b1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Feb 2021 10:16:56 -0600 Subject: [PATCH 240/443] support closures in sequences --- src/Illuminate/Database/Eloquent/Factories/Sequence.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/Sequence.php b/src/Illuminate/Database/Eloquent/Factories/Sequence.php index 20c0f3357c68..545a248f6362 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Sequence.php +++ b/src/Illuminate/Database/Eloquent/Factories/Sequence.php @@ -48,7 +48,7 @@ public function __invoke() $this->index = 0; } - return tap($this->sequence[$this->index], function () { + return tap(value($this->sequence[$this->index]), function () { $this->index = $this->index + 1; }); } From e7207b86a573b3f63bc838fed8545f910feb1617 Mon Sep 17 00:00:00 2001 From: Max Shaian Date: Fri, 19 Feb 2021 21:21:34 +0700 Subject: [PATCH 241/443] Added path() method to Storage Facade (#36317) path() method is described, but not implemented into the facade: https://laravel.com/docs/8.x/filesystem#file-paths --- src/Illuminate/Support/Facades/Storage.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Storage.php b/src/Illuminate/Support/Facades/Storage.php index 66fa1303000e..1111faf81479 100644 --- a/src/Illuminate/Support/Facades/Storage.php +++ b/src/Illuminate/Support/Facades/Storage.php @@ -21,6 +21,7 @@ * @method static \Illuminate\Filesystem\FilesystemManager extend(string $driver, \Closure $callback) * @method static bool makeDirectory(string $path) * @method static bool move(string $from, string $to) + * @method static string path(string $path) * @method static bool prepend(string $path, string $data) * @method static bool put(string $path, string|resource $contents, mixed $options = []) * @method static string|false putFile(string $path, \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $file, mixed $options = []) From 0c6f5f75bf0ba4d3307145c9d92ae022f60414be Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 19 Feb 2021 11:54:32 -0600 Subject: [PATCH 242/443] add gate evaluation event --- .../Auth/Access/Events/GateEvaluated.php | 51 +++++++++++++++++++ src/Illuminate/Auth/Access/Gate.php | 27 ++++++++-- .../Auth/GatePolicyResolutionTest.php | 11 ++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Auth/Access/Events/GateEvaluated.php diff --git a/src/Illuminate/Auth/Access/Events/GateEvaluated.php b/src/Illuminate/Auth/Access/Events/GateEvaluated.php new file mode 100644 index 000000000000..6876b01fa725 --- /dev/null +++ b/src/Illuminate/Auth/Access/Events/GateEvaluated.php @@ -0,0 +1,51 @@ +user = $user; + $this->ability = $ability; + $this->result = $result; + $this->arguments = $arguments; + } +} diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 7fc5d90717a8..826bf9f49703 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Contracts\Auth\Access\Gate as GateContract; use Illuminate\Contracts\Container\Container; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; @@ -86,7 +87,7 @@ class Gate implements GateContract */ public function __construct(Container $container, callable $userResolver, array $abilities = [], array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [], - callable $guessPolicyNamesUsingCallback = null) + callable $guessPolicyNamesUsingCallback = null) { $this->policies = $policies; $this->container = $container; @@ -374,9 +375,11 @@ public function raw($ability, $arguments = []) // After calling the authorization callback, we will call the "after" callbacks // that are registered with the Gate, which allows a developer to do logging // if that is required for this application. Then we'll return the result. - return $this->callAfterCallbacks( + return tap($this->callAfterCallbacks( $user, $ability, $arguments, $result - ); + ), function ($result) use ($user, $ability, $arguments) { + $this->dispatchGateEvaluatedEvent($user, $ability, $arguments, $result); + }); } /** @@ -519,6 +522,24 @@ protected function callAfterCallbacks($user, $ability, array $arguments, $result return $result; } + /** + * Dispatch a gate evaluation event. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $ability + * @param array $arguments + * @param bool $result + * @return void + */ + protected function dispatchGateEvaluatedEvent($user, $ability, array $arguments, $result) + { + if ($this->container->bound(Dispatcher::class)) { + $this->container->make(Dispatcher::class)->dispatch( + new Events\GateEvaluated($user, $ability, $result, $arguments) + ); + } + } + /** * Resolve the callable for the given ability and arguments. * diff --git a/tests/Integration/Auth/GatePolicyResolutionTest.php b/tests/Integration/Auth/GatePolicyResolutionTest.php index 9781d59c8a7c..349bd9f89022 100644 --- a/tests/Integration/Auth/GatePolicyResolutionTest.php +++ b/tests/Integration/Auth/GatePolicyResolutionTest.php @@ -2,6 +2,8 @@ namespace Illuminate\Tests\Integration\Auth; +use Illuminate\Auth\Access\Events\GateEvaluated; +use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Gate; use Illuminate\Tests\Integration\Auth\Fixtures\AuthenticationTestUser; use Illuminate\Tests\Integration\Auth\Fixtures\Policies\AuthenticationTestUserPolicy; @@ -12,6 +14,15 @@ */ class GatePolicyResolutionTest extends TestCase { + public function testGateEvaluationEventIsFired() + { + Event::fake(); + + Gate::check('foo'); + + Event::assertDispatched(GateEvaluated::class); + } + public function testPolicyCanBeGuessedUsingClassConventions() { $this->assertInstanceOf( From ef3080d16cf8f9b2da33d8553d84786a5672202d Mon Sep 17 00:00:00 2001 From: Will Browning Date: Sun, 21 Feb 2021 10:32:36 +0000 Subject: [PATCH 243/443] Fix retry command for encrypted jobs --- src/Illuminate/Queue/Console/RetryCommand.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index ad090f6fa5d0..a713e6fb3a99 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -4,7 +4,10 @@ use DateTimeInterface; use Illuminate\Console\Command; +use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Support\Arr; +use Illuminate\Support\Str; +use RuntimeException; class RetryCommand extends Command { @@ -94,7 +97,8 @@ protected function getJobIdsByRanges(array $ranges) protected function retryJob($job) { $this->laravel['queue']->connection($job->connection)->pushRaw( - $this->refreshRetryUntil($this->resetAttempts($job->payload)), $job->queue + $this->refreshRetryUntil($this->resetAttempts($job->payload)), + $job->queue ); } @@ -131,7 +135,17 @@ protected function refreshRetryUntil($payload) return json_encode($payload); } - $instance = unserialize($payload['data']['command']); + if (Str::startsWith($payload['data']['command'], 'O:')) { + $instance = unserialize($payload['data']['command']); + } + + if (app()->bound(Encrypter::class)) { + $instance = unserialize(app()->make(Encrypter::class)->decrypt($payload['data']['command'])); + } + + if (! isset($instance)) { + throw new RuntimeException('Unable to extract job payload.'); + } if (is_object($instance) && method_exists($instance, 'retryUntil')) { $retryUntil = $instance->retryUntil(); From 0e136df21cba335361127856c76746eef9c3db0c Mon Sep 17 00:00:00 2001 From: Will Browning Date: Sun, 21 Feb 2021 10:41:19 +0000 Subject: [PATCH 244/443] Fix formatting --- src/Illuminate/Queue/Console/RetryCommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index a713e6fb3a99..508180ccba65 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -97,8 +97,7 @@ protected function getJobIdsByRanges(array $ranges) protected function retryJob($job) { $this->laravel['queue']->connection($job->connection)->pushRaw( - $this->refreshRetryUntil($this->resetAttempts($job->payload)), - $job->queue + $this->refreshRetryUntil($this->resetAttempts($job->payload)), $job->queue ); } From a78aa12c497b9c689ec2f83cf4afd8aed271d8d4 Mon Sep 17 00:00:00 2001 From: Will Browning Date: Sun, 21 Feb 2021 11:01:36 +0000 Subject: [PATCH 245/443] Fix case when command not encrypted --- src/Illuminate/Queue/Console/RetryCommand.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index 508180ccba65..eaebeab05dc1 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -136,9 +136,7 @@ protected function refreshRetryUntil($payload) if (Str::startsWith($payload['data']['command'], 'O:')) { $instance = unserialize($payload['data']['command']); - } - - if (app()->bound(Encrypter::class)) { + } else if (app()->bound(Encrypter::class)) { $instance = unserialize(app()->make(Encrypter::class)->decrypt($payload['data']['command'])); } From 0dc9d840ab17aee6e751d4c4cfc87ef8ab86216c Mon Sep 17 00:00:00 2001 From: Will Browning Date: Sun, 21 Feb 2021 13:12:50 +0000 Subject: [PATCH 246/443] Fix style --- src/Illuminate/Queue/Console/RetryCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index eaebeab05dc1..e7c48fc52af6 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -136,7 +136,7 @@ protected function refreshRetryUntil($payload) if (Str::startsWith($payload['data']['command'], 'O:')) { $instance = unserialize($payload['data']['command']); - } else if (app()->bound(Encrypter::class)) { + } elseif (app()->bound(Encrypter::class)) { $instance = unserialize(app()->make(Encrypter::class)->decrypt($payload['data']['command'])); } From e4927c1ec1930f7543500379ca485d0b7051bac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sun, 21 Feb 2021 16:57:40 +0100 Subject: [PATCH 247/443] [8.x] Make sure trait_uses_recursive returns an array (#36335) * Make sure trait_uses_recursive returns an array `class_uses` returns false on error. https://www.php.net/manual/en/function.class-uses.php#refsect1-function.class-uses-returnvalues * Fix typo * Update helpers.php Co-authored-by: Taylor Otwell --- src/Illuminate/Support/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 57bdcc294d8f..8795e276d07b 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -325,7 +325,7 @@ function throw_unless($condition, $exception = 'RuntimeException', ...$parameter */ function trait_uses_recursive($trait) { - $traits = class_uses($trait); + $traits = class_uses($trait) ?: []; foreach ($traits as $trait) { $traits += trait_uses_recursive($trait); From 2fb5e444ef55a764ba2363a10320e75f3c830504 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 21 Feb 2021 10:01:08 -0600 Subject: [PATCH 248/443] formatting --- src/Illuminate/Queue/Console/RetryCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index e7c48fc52af6..2f651b60d098 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -136,8 +136,8 @@ protected function refreshRetryUntil($payload) if (Str::startsWith($payload['data']['command'], 'O:')) { $instance = unserialize($payload['data']['command']); - } elseif (app()->bound(Encrypter::class)) { - $instance = unserialize(app()->make(Encrypter::class)->decrypt($payload['data']['command'])); + } elseif ($this->laravel->bound(Encrypter::class)) { + $instance = unserialize($this->laravel->make(Encrypter::class)->decrypt($payload['data']['command'])); } if (! isset($instance)) { From bb9078a8ae0db7eff39805f808888758f3bd01c4 Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Sun, 21 Feb 2021 16:08:38 +0000 Subject: [PATCH 249/443] [8.x] Adds a `collect` method to the HTTP Client response. (#36331) * Adds a `collect` method to the HTTP client response. * Formatting change * Allows passing a key to the `collect` method that will return a subset of the json response before wrapping it in the collection. * Update Response.php * Update Response.php Co-authored-by: Taylor Otwell --- src/Illuminate/Http/Client/Response.php | 12 ++++++++++++ tests/Http/HttpClientTest.php | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Illuminate/Http/Client/Response.php b/src/Illuminate/Http/Client/Response.php index f65a8d5ca1ba..ccbd631c7cb8 100644 --- a/src/Illuminate/Http/Client/Response.php +++ b/src/Illuminate/Http/Client/Response.php @@ -3,6 +3,7 @@ namespace Illuminate\Http\Client; use ArrayAccess; +use Illuminate\Support\Collection; use Illuminate\Support\Traits\Macroable; use LogicException; @@ -77,6 +78,17 @@ public function object() return json_decode($this->body(), false); } + /** + * Get the JSON decoded body of the response as a collection. + * + * @param string|null $key + * @return \Illuminate\Support\Collection + */ + public function collect($key = null) + { + return Collection::make($this->json($key)); + } + /** * Get a header from the response. * diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 12722b52b020..b407d6fb3f0e 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -7,6 +7,7 @@ use Illuminate\Http\Client\Request; use Illuminate\Http\Client\RequestException; use Illuminate\Http\Client\Response; +use Illuminate\Support\Collection; use Illuminate\Support\Str; use OutOfBoundsException; use PHPUnit\Framework\TestCase; @@ -54,6 +55,21 @@ public function testResponseBodyCasting() $this->assertSame('bar', $response->object()->result->foo); } + public function testResponseCanBeReturnedAsCollection() + { + $this->factory->fake([ + '*' => ['result' => ['foo' => 'bar']], + ]); + + $response = $this->factory->get('http://foo.com/api'); + + $this->assertInstanceOf(Collection::class, $response->collect()); + $this->assertEquals(collect(['result' => ['foo' => 'bar']]), $response->collect()); + $this->assertEquals(collect(['foo' => 'bar']), $response->collect('result')); + $this->assertEquals(collect(['bar']), $response->collect('result.foo')); + $this->assertEquals(collect(), $response->collect('missing_key')); + } + public function testUrlsCanBeStubbedByPath() { $this->factory->fake([ From ed3a8dbc826f49cf240d9db3f5e0a1ddb7ce35ef Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Sun, 21 Feb 2021 16:09:39 +0000 Subject: [PATCH 250/443] [8.x] Added the whereInstanceOfAny() method for collections (#36328) * Added the whereInstanceOfAny() method for collections. * Moved whereInstanceOfAny logic into whereInstanceOf method. * Added tests for using whereInstanceOf with an array. --- src/Illuminate/Collections/Enumerable.php | 4 ++-- .../Collections/Traits/EnumeratesValues.php | 14 ++++++++++++-- tests/Support/SupportCollectionTest.php | 4 +++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 297ee2f08df5..4bda35476905 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -415,9 +415,9 @@ public function whereNotIn($key, $values, $strict = false); public function whereNotInStrict($key, $values); /** - * Filter the items, removing any items that don't match the given type. + * Filter the items, removing any items that don't match the given type(s). * - * @param string $type + * @param string|string[] $type * @return static */ public function whereInstanceOf($type); diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 0c0c7ce3c3ab..865d0047cdd5 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -669,14 +669,24 @@ public function whereNotInStrict($key, $values) } /** - * Filter the items, removing any items that don't match the given type. + * Filter the items, removing any items that don't match the given type(s). * - * @param string $type + * @param string|string[] $type * @return static */ public function whereInstanceOf($type) { return $this->filter(function ($value) use ($type) { + if (is_array($type)) { + foreach ($type as $classType) { + if ($value instanceof $classType) { + return true; + } + } + + return false; + } + return $value instanceof $type; }); } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index a72fc66949aa..0cfd0598d26f 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -766,8 +766,10 @@ public function testWhereStrict($collection) */ public function testWhereInstanceOf($collection) { - $c = new $collection([new stdClass, new stdClass, new $collection, new stdClass]); + $c = new $collection([new stdClass, new stdClass, new $collection, new stdClass, new Str]); $this->assertCount(3, $c->whereInstanceOf(stdClass::class)); + + $this->assertCount(4, $c->whereInstanceOf([stdClass::class, Str::class])); } /** From 75b1e9ea2d9157d65fc3d3d8cb20840aa2887c5b Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 22 Feb 2021 18:00:32 +0100 Subject: [PATCH 251/443] Fix GateEvaluated event DocBlocks (#36347) --- src/Illuminate/Auth/Access/Events/GateEvaluated.php | 4 ++-- src/Illuminate/Auth/Access/Gate.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Auth/Access/Events/GateEvaluated.php b/src/Illuminate/Auth/Access/Events/GateEvaluated.php index 6876b01fa725..f77a9c84c51b 100644 --- a/src/Illuminate/Auth/Access/Events/GateEvaluated.php +++ b/src/Illuminate/Auth/Access/Events/GateEvaluated.php @@ -7,7 +7,7 @@ class GateEvaluated /** * The authenticatable model. * - * @var \Illuminate\Contracts\Auth\Authenticatable + * @var \Illuminate\Contracts\Auth\Authenticatable|null */ public $user; @@ -35,7 +35,7 @@ class GateEvaluated /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param string $ability * @param bool|null $result * @param array $arguments diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 826bf9f49703..0497a8e344b8 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -87,7 +87,7 @@ class Gate implements GateContract */ public function __construct(Container $container, callable $userResolver, array $abilities = [], array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [], - callable $guessPolicyNamesUsingCallback = null) + callable $guessPolicyNamesUsingCallback = null) { $this->policies = $policies; $this->container = $container; @@ -525,10 +525,10 @@ protected function callAfterCallbacks($user, $ability, array $arguments, $result /** * Dispatch a gate evaluation event. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param string $ability * @param array $arguments - * @param bool $result + * @param bool|null $result * @return void */ protected function dispatchGateEvaluatedEvent($user, $ability, array $arguments, $result) From 4e40d4efb433e6027d9569964ede91c781e61484 Mon Sep 17 00:00:00 2001 From: Sergey Pashkevich Date: Mon, 22 Feb 2021 20:10:38 +0300 Subject: [PATCH 252/443] correct docblock type-hint and return value for __unserialize method (#36342) --- src/Illuminate/Queue/SerializesModels.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Queue/SerializesModels.php b/src/Illuminate/Queue/SerializesModels.php index 52c0f405d831..d60479d20708 100644 --- a/src/Illuminate/Queue/SerializesModels.php +++ b/src/Illuminate/Queue/SerializesModels.php @@ -91,7 +91,7 @@ public function __serialize() * Restore the model after serialization. * * @param array $values - * @return array + * @return void */ public function __unserialize(array $values) { @@ -122,8 +122,6 @@ public function __unserialize(array $values) $this, $this->getRestoredPropertyValue($values[$name]) ); } - - return $values; } /** From 3404185fbe36139dfbe6d0d9595811b41ee53068 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 22 Feb 2021 14:04:20 -0600 Subject: [PATCH 253/443] update pusher deps and update broadcasting --- composer.json | 2 +- .../Broadcasters/PusherBroadcaster.php | 47 ++++++++++++++----- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index df3e46d1e1ae..401a6e952839 100644 --- a/composer.json +++ b/composer.json @@ -144,7 +144,7 @@ "phpunit/phpunit": "Required to use assertions and run tests (^8.5.8|^9.3.3).", "predis/predis": "Required to use the predis connector (^1.1.2).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0).", "symfony/cache": "Required to PSR-6 cache bridge (^5.1.4).", "symfony/filesystem": "Required to enable support for relative symbolic links (^5.1.4).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index f55cf02b86d4..15695e114e6f 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -5,6 +5,7 @@ use Illuminate\Broadcasting\BroadcastException; use Illuminate\Support\Arr; use Illuminate\Support\Str; +use Pusher\ApiErrorException; use Pusher\Pusher; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -110,20 +111,44 @@ public function broadcast(array $channels, $event, array $payload = []) { $socket = Arr::pull($payload, 'socket'); - $response = $this->pusher->trigger( - $this->formatChannels($channels), $event, $payload, $socket, true - ); + if ($this->pusherServerIsVersionFiveOrGreater()) { + $parameters = $socket !== null ? ['socket_id' => $socket] : []; + + try { + $this->pusher->trigger( + $this->formatChannels($channels), $event, $payload, $parameters + ); + } catch (ApiErrorException $e) { + throw new BroadcastException( + sprintf('Pusher error: %s.', $e->getMessage()) + ); + } + } else { + $response = $this->pusher->trigger( + $this->formatChannels($channels), $event, $payload, $socket, true + ); + + if ((is_array($response) && $response['status'] >= 200 && $response['status'] <= 299) + || $response === true) { + return; + } - if ((is_array($response) && $response['status'] >= 200 && $response['status'] <= 299) - || $response === true) { - return; + throw new BroadcastException( + ! empty($response['body']) + ? sprintf('Pusher error: %s.', $response['body']) + : 'Failed to connect to Pusher.' + ); } + } - throw new BroadcastException( - ! empty($response['body']) - ? sprintf('Pusher error: %s.', $response['body']) - : 'Failed to connect to Pusher.' - ); + /** + * Determine if the Pusher PHP server is version 5.0 or greater. + * + * @return bool + */ + protected function pusherServerIsVersionFiveOrGreater() + { + return class_exists(ApiErrorException::class); } /** From 952be1c2c98de93fc4a3d12f1c39c9723d725910 Mon Sep 17 00:00:00 2001 From: Craig Anderson Date: Mon, 22 Feb 2021 15:46:37 -0500 Subject: [PATCH 254/443] Add minute argument to perMinute method for RateLimiting This PR allows the `perMinute` method accept an optional argument to specify the number of decay minutes. This allows the `perMinute` method to function in the same way that the `perHour` and `perDay` methods function. --- src/Illuminate/Cache/RateLimiting/Limit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/RateLimiting/Limit.php b/src/Illuminate/Cache/RateLimiting/Limit.php index ab3463f51830..ce0c924aa98f 100644 --- a/src/Illuminate/Cache/RateLimiting/Limit.php +++ b/src/Illuminate/Cache/RateLimiting/Limit.php @@ -53,9 +53,9 @@ public function __construct($key = '', int $maxAttempts = 60, int $decayMinutes * @param int $maxAttempts * @return static */ - public static function perMinute($maxAttempts) + public static function perMinute($maxAttempts, $decayMinutes = 1) { - return new static('', $maxAttempts); + return new static('', $maxAttempts, $decayMinutes); } /** From 663f7e7c675e2edf06f2d8c1af29083b39f4acf3 Mon Sep 17 00:00:00 2001 From: Marko Dupor Date: Tue, 23 Feb 2021 14:33:04 +0100 Subject: [PATCH 255/443] Just a tad cleaner (#36359) * Just a tad cleaner * spacing --- src/Illuminate/Filesystem/FilesystemManager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index 5575439418fc..49768690dc24 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -125,11 +125,11 @@ protected function resolve($name) $driverMethod = 'create'.ucfirst($name).'Driver'; - if (method_exists($this, $driverMethod)) { - return $this->{$driverMethod}($config); - } else { + if (! method_exists($this, $driverMethod)) { throw new InvalidArgumentException("Driver [{$name}] is not supported."); } + + return $this->{$driverMethod}($config); } /** From 11d7c7e990db60b1934a2cbcdbcc2328a3c355fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Crnkovi=C4=87?= Date: Tue, 23 Feb 2021 14:38:35 +0100 Subject: [PATCH 256/443] wip (#36356) --- .../Compilers/Concerns/CompilesInjections.php | 6 ++-- tests/View/Blade/BladeInjectTest.php | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/View/Blade/BladeInjectTest.php diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesInjections.php b/src/Illuminate/View/Compilers/Concerns/CompilesInjections.php index c295bcd448c5..a0d1ccf5ea31 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesInjections.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesInjections.php @@ -12,12 +12,12 @@ trait CompilesInjections */ protected function compileInject($expression) { - $segments = explode(',', preg_replace("/[\(\)\\\"\']/", '', $expression)); + $segments = explode(',', preg_replace("/[\(\)]/", '', $expression)); - $variable = trim($segments[0]); + $variable = trim($segments[0], " '\""); $service = trim($segments[1]); - return ""; + return ""; } } diff --git a/tests/View/Blade/BladeInjectTest.php b/tests/View/Blade/BladeInjectTest.php new file mode 100644 index 000000000000..07ffd19f0e3f --- /dev/null +++ b/tests/View/Blade/BladeInjectTest.php @@ -0,0 +1,34 @@ + bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testDependenciesInjectedAsStringsAreCompiledWhenInjectedWithDoubleQuotes() + { + $string = 'Foo @inject("baz", "SomeNamespace\SomeClass") bar'; + $expected = 'Foo bar'; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testDependenciesAreCompiled() + { + $string = "Foo @inject('baz', SomeNamespace\SomeClass::class) bar"; + $expected = "Foo bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } + + public function testDependenciesAreCompiledWithDoubleQuotes() + { + $string = 'Foo @inject("baz", SomeNamespace\SomeClass::class) bar'; + $expected = "Foo bar"; + $this->assertEquals($expected, $this->compiler->compileString($string)); + } +} From d2eba352b3b3a3c515b18c5726b373fe5026733e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 23 Feb 2021 08:27:41 -0600 Subject: [PATCH 257/443] version --- 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 e1a302521061..2c4926abc16d 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.28.1'; + const VERSION = '8.29.0'; /** * The base path for the Laravel installation. From 07a5f8af69f2af89eb8020dee3715bfc94509bcf Mon Sep 17 00:00:00 2001 From: Craig Anderson Date: Tue, 23 Feb 2021 09:50:10 -0500 Subject: [PATCH 258/443] Update phpdoc --- src/Illuminate/Cache/RateLimiting/Limit.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Cache/RateLimiting/Limit.php b/src/Illuminate/Cache/RateLimiting/Limit.php index ce0c924aa98f..56f3f6c80f47 100644 --- a/src/Illuminate/Cache/RateLimiting/Limit.php +++ b/src/Illuminate/Cache/RateLimiting/Limit.php @@ -51,6 +51,7 @@ public function __construct($key = '', int $maxAttempts = 60, int $decayMinutes * Create a new rate limit. * * @param int $maxAttempts + * @param int $decayMinutes * @return static */ public static function perMinute($maxAttempts, $decayMinutes = 1) From 7f9441c1f990f513b40102bef5172b1d3c0eccf0 Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Tue, 23 Feb 2021 18:36:56 +0100 Subject: [PATCH 259/443] Update Http.php (#36366) --- src/Illuminate/Support/Facades/Http.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index 9a81b017d7f3..c6a26b2108cd 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -18,6 +18,7 @@ * @method static \Illuminate\Http\Client\PendingRequest bodyFormat(string $format) * @method static \Illuminate\Http\Client\PendingRequest contentType(string $contentType) * @method static \Illuminate\Http\Client\PendingRequest retry(int $times, int $sleep = 0) + * @method static \Illuminate\Http\Client\PendingRequest sink($to) * @method static \Illuminate\Http\Client\PendingRequest stub(callable $callback) * @method static \Illuminate\Http\Client\PendingRequest timeout(int $seconds) * @method static \Illuminate\Http\Client\PendingRequest withBasicAuth(string $username, string $password) From cb54f2227cea72fb2d643c4f4dc588c56a38dfde Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 23 Feb 2021 20:25:36 +0200 Subject: [PATCH 260/443] [8.x] update changelog --- CHANGELOG-8.x.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 8e03e4d36aa9..4d383e7fc191 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,29 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.28.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.29.0...8.x) + + +## [v8.29.0 (2021-02-23)](https://github.com/laravel/framework/compare/v8.28.1...v8.29.0) + +### Added +- Support username parameter for predis ([#36299](https://github.com/laravel/framework/pull/36299)) +- Adds "setUpTestDatabase" support to Parallel Testing ([#36301](https://github.com/laravel/framework/pull/36301)) +- Added support closures in sequences ([3c66f6c](https://github.com/laravel/framework/commit/3c66f6cda2ac4ee2844a67fc98e676cb170ff4b1)) +- Added gate evaluation event ([0c6f5f7](https://github.com/laravel/framework/commit/0c6f5f75bf0ba4d3307145c9d92ae022f60414be)) +- Added a `collect` method to the HTTP Client response ([#36331](https://github.com/laravel/framework/pull/36331)) +- Allow Blade's service injection to inject services typed using class name resolution ([#36356](https://github.com/laravel/framework/pull/36356)) + +### Fixed +- Fixed: Using withoutMiddleware() and a closure-based middleware on PHP8 throws an exception ([#36293](https://github.com/laravel/framework/pull/36293)) +- Fixed: The label for page number in pagination links should always be a string ([#36292](https://github.com/laravel/framework/pull/36292)) +- Clean up custom Queue payload between tests ([#36295](https://github.com/laravel/framework/pull/36295)) +- Fixed flushDb (cache:clear) for redis clusters ([#36281](https://github.com/laravel/framework/pull/36281)) +- Fixed retry command for encrypted jobs ([#36334](https://github.com/laravel/framework/pull/36334), [2fb5e44](https://github.com/laravel/framework/commit/2fb5e444ef55a764ba2363a10320e75f3c830504)) +- Make sure `trait_uses_recursive` returns an array ([#36335](https://github.com/laravel/framework/pull/36335)) + +### Changed +- Make use of specified ownerKey in MorphTo::associate() ([#36303](https://github.com/laravel/framework/pull/36303)) +- Update pusher deps and update broadcasting ([3404185](https://github.com/laravel/framework/commit/3404185fbe36139dfbe6d0d9595811b41ee53068)) ## [v8.28.1 (2021-02-16)](https://github.com/laravel/framework/compare/v8.28.0...v8.28.1) From b69db31d47342f41878c20cbdce35edc8ea56147 Mon Sep 17 00:00:00 2001 From: Tom Irons Date: Tue, 23 Feb 2021 16:02:28 -0500 Subject: [PATCH 261/443] add missing method doc (#36367) --- src/Illuminate/Support/Facades/ParallelTesting.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/ParallelTesting.php b/src/Illuminate/Support/Facades/ParallelTesting.php index 641f9fe90eae..2fe785e56816 100644 --- a/src/Illuminate/Support/Facades/ParallelTesting.php +++ b/src/Illuminate/Support/Facades/ParallelTesting.php @@ -5,6 +5,7 @@ /** * @method static void setUpProcess(callable $callback) * @method static void setUpTestCase(callable $callback) + * @method static void setupTestDatabase(callable $callback) * @method static void tearDownProcess(callable $callback) * @method static void tearDownTestCase(callable $callback) * @method static int|false token() From 55d10a8138dbb86850b82614f34497d30403db1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rihards=20=C5=A0=C4=8Deredins?= Date: Wed, 24 Feb 2021 15:50:12 +0200 Subject: [PATCH 262/443] When using managed PostgreSQL instances on DigitalOcean every now and then this pops out. After seeing #35744, #35790 and others decided to fix this. (#36373) PDOException: SQLSTATE[08006] [7] could not translate host name "private-xxx-do-user-0.a.db.ondigitalocean.com" to address: Temporary failure in name resolution --- 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 07630c590d5c..1ecfc96140f4 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -49,6 +49,7 @@ protected function causedByLostConnection(Throwable $e) 'SQLSTATE[HY000] [2002] Connection timed out', 'SSL: Connection timed out', 'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.', + 'Temporary failure in name resolution', ]); } } From e83d250e262fcfcb228d707cfb41126530a09f3a Mon Sep 17 00:00:00 2001 From: Craig Anderson Date: Wed, 24 Feb 2021 12:05:26 -0500 Subject: [PATCH 263/443] Create new rate limit method perMinutes --- src/Illuminate/Cache/RateLimiting/Limit.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/RateLimiting/Limit.php b/src/Illuminate/Cache/RateLimiting/Limit.php index 56f3f6c80f47..3e8956cad2ad 100644 --- a/src/Illuminate/Cache/RateLimiting/Limit.php +++ b/src/Illuminate/Cache/RateLimiting/Limit.php @@ -51,10 +51,21 @@ public function __construct($key = '', int $maxAttempts = 60, int $decayMinutes * Create a new rate limit. * * @param int $maxAttempts + * @return static + */ + public static function perMinute($maxAttempts) + { + return new static('', $maxAttempts); + } + + /** + * Create a new rate limit using minutes as decay time. + * + * @param int $maxAttempts * @param int $decayMinutes * @return static */ - public static function perMinute($maxAttempts, $decayMinutes = 1) + public static function perMinutes($maxAttempts, $decayMinutes = 1) { return new static('', $maxAttempts, $decayMinutes); } From 3eedc68019e6292a3d5c6dec1b636e668b339e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Wed, 24 Feb 2021 18:06:16 +0100 Subject: [PATCH 264/443] Add missing parameter to facade doc blocks (#36377) --- 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 1903af244d78..4ff371f9cece 100755 --- a/src/Illuminate/Support/Facades/Password.php +++ b/src/Illuminate/Support/Facades/Password.php @@ -6,7 +6,7 @@ /** * @method static mixed reset(array $credentials, \Closure $callback) - * @method static string sendResetLink(array $credentials) + * @method static string sendResetLink(array $credentials, \Closure $callback = null) * @method static \Illuminate\Contracts\Auth\CanResetPassword getUser(array $credentials) * @method static string createToken(\Illuminate\Contracts\Auth\CanResetPassword $user) * @method static void deleteToken(\Illuminate\Contracts\Auth\CanResetPassword $user) From 1529702f94ae51a5eb2191ee6849849967b8606c Mon Sep 17 00:00:00 2001 From: Haider Ali <47752310+haider00125@users.noreply.github.com> Date: Thu, 25 Feb 2021 19:20:09 +0500 Subject: [PATCH 265/443] Fix typo in broadcast channel constructor docblock. (#36386) Co-authored-by: Haider Ali --- src/Illuminate/Notifications/Channels/BroadcastChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Notifications/Channels/BroadcastChannel.php b/src/Illuminate/Notifications/Channels/BroadcastChannel.php index d281b9b13831..1389f49c6ac8 100644 --- a/src/Illuminate/Notifications/Channels/BroadcastChannel.php +++ b/src/Illuminate/Notifications/Channels/BroadcastChannel.php @@ -18,7 +18,7 @@ class BroadcastChannel protected $events; /** - * Create a new database channel. + * Create a new broadcast channel. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void From a456e2f17c0422133ac7d6c4b5a957c1eb2e80f1 Mon Sep 17 00:00:00 2001 From: Johan van Helden Date: Thu, 25 Feb 2021 15:21:55 +0100 Subject: [PATCH 266/443] Add setUpTestDatabase method to ParallelTesting facade (#36383) --- src/Illuminate/Support/Facades/ParallelTesting.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/ParallelTesting.php b/src/Illuminate/Support/Facades/ParallelTesting.php index 2fe785e56816..c3976113501f 100644 --- a/src/Illuminate/Support/Facades/ParallelTesting.php +++ b/src/Illuminate/Support/Facades/ParallelTesting.php @@ -5,7 +5,7 @@ /** * @method static void setUpProcess(callable $callback) * @method static void setUpTestCase(callable $callback) - * @method static void setupTestDatabase(callable $callback) + * @method static void setUpTestDatabase(callable $callback) * @method static void tearDownProcess(callable $callback) * @method static void tearDownTestCase(callable $callback) * @method static int|false token() From aa19ecd0ceef93b6e8a96764cdb07d7c878871b0 Mon Sep 17 00:00:00 2001 From: Chris Gmyr Date: Thu, 25 Feb 2021 09:24:33 -0500 Subject: [PATCH 267/443] add macroable trait to database factory (#36380) --- src/Illuminate/Database/Eloquent/Factories/Factory.php | 9 ++++++++- tests/Database/DatabaseEloquentFactoryTest.php | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index abf9d91748ee..6a890646c623 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -11,11 +11,14 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; +use Illuminate\Support\Traits\Macroable; use Throwable; abstract class Factory { - use ForwardsCalls; + use ForwardsCalls, Macroable { + __call as macroCall; + } /** * The name of the factory's corresponding model. @@ -747,6 +750,10 @@ protected static function appNamespace() */ public function __call($method, $parameters) { + if (static::hasMacro($method)) { + return $this->macroCall($method, $parameters); + } + if (! Str::startsWith($method, ['for', 'has'])) { static::throwBadMethodCallException($method); } diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index 47ac43c548aa..fd402edfdf2c 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -473,6 +473,16 @@ public function test_dynamic_has_and_for_methods() $this->assertCount(2, $post->comments); } + public function test_can_be_macroable() + { + $factory = FactoryTestUserFactory::new(); + $factory->macro('getFoo', function () { + return 'Hello World'; + }); + + $this->assertEquals('Hello World', $factory->getFoo()); + } + /** * Get a database connection instance. * From 8c5292eb96d9cf104b9b3bcdd471bde59a117de1 Mon Sep 17 00:00:00 2001 From: Erik Gaal Date: Thu, 25 Feb 2021 15:51:55 +0100 Subject: [PATCH 268/443] [8.x] Respect custom route key with explicit route model binding (#36375) * feat: respect route custom key for explicit route model bindings * tests: close mockery after test * style: changes from StyleCI --- src/Illuminate/Routing/RouteBinding.php | 8 +++---- src/Illuminate/Routing/Router.php | 2 +- tests/Routing/RoutingRouteTest.php | 31 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Routing/RouteBinding.php b/src/Illuminate/Routing/RouteBinding.php index 133a84a40b07..45b2e8ec8d05 100644 --- a/src/Illuminate/Routing/RouteBinding.php +++ b/src/Illuminate/Routing/RouteBinding.php @@ -33,7 +33,7 @@ public static function forCallback($container, $binder) */ protected static function createClassBinding($container, $binding) { - return function ($value, $route) use ($container, $binding) { + return function ($value, $route, $key) use ($container, $binding) { // If the binding has an @ sign, we will assume it's being used to delimit // the class name from the bind method name. This allows for bindings // to run multiple bind methods in a single class for convenience. @@ -41,7 +41,7 @@ protected static function createClassBinding($container, $binding) $callable = [$container->make($class), $method]; - return $callable($value, $route); + return $callable($value, $route, $key); }; } @@ -57,7 +57,7 @@ protected static function createClassBinding($container, $binding) */ public static function forModel($container, $class, $callback = null) { - return function ($value) use ($container, $class, $callback) { + return function ($value, $route, $key) use ($container, $class, $callback) { if (is_null($value)) { return; } @@ -67,7 +67,7 @@ public static function forModel($container, $class, $callback = null) // throw a not found exception otherwise we will return the instance. $instance = $container->make($class); - if ($model = $instance->resolveRouteBinding($value)) { + if ($model = $instance->resolveRouteBinding($value, $route->bindingFieldFor($key))) { return $model; } diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index dfdb7ae7332e..4e57ffc6ec9d 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -840,7 +840,7 @@ public function substituteImplicitBindings($route) */ protected function performBinding($key, $value, $route) { - return call_user_func($this->binders[$key], $value, $route); + return call_user_func($this->binders[$key], $value, $route, $key); } /** diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index a0d4548dc06e..f4244a3bbb3e 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -29,6 +29,7 @@ use Illuminate\Routing\UrlGenerator; use Illuminate\Support\Str; use LogicException; +use Mockery; use PHPUnit\Framework\TestCase; use stdClass; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; @@ -938,6 +939,36 @@ public function testModelBinding() $this->assertSame('TAYLOR', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent()); } + public function testModelBindingWithCustomKey() + { + // Create the router. + $container = new Container(); + $router = new Router(new Dispatcher(), $container); + $container->singleton(Registrar::class, function () use ($router) { + return $router; + }); + + $router->get('foo/{bar:custom}', ['middleware' => SubstituteBindings::class, 'uses' => function ($name) { + return $name; + }]); + $router->model('bar', RouteModelBindingStub::class); + + // Mock the stub so we can verify that the method is called with custom key. + $mock = $container->instance( + RouteModelBindingStub::class, + Mockery::mock(RouteModelBindingStub::class), + ); + + $mock->shouldReceive('resolveRouteBinding') + ->with('taylor', 'custom') + ->once() + ->andReturn('TAYLOR'); + + $this->assertSame('TAYLOR', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent()); + + Mockery::close(); + } + public function testModelBindingWithNullReturn() { $this->expectException(ModelNotFoundException::class); From 86d0a5c733b3f22ae2353df538e07605963c3052 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 25 Feb 2021 09:10:53 -0600 Subject: [PATCH 269/443] formatting --- src/Illuminate/Cache/RateLimiting/Limit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/RateLimiting/Limit.php b/src/Illuminate/Cache/RateLimiting/Limit.php index 3e8956cad2ad..330cab39bba1 100644 --- a/src/Illuminate/Cache/RateLimiting/Limit.php +++ b/src/Illuminate/Cache/RateLimiting/Limit.php @@ -61,11 +61,11 @@ public static function perMinute($maxAttempts) /** * Create a new rate limit using minutes as decay time. * - * @param int $maxAttempts * @param int $decayMinutes + * @param int $maxAttempts * @return static */ - public static function perMinutes($maxAttempts, $decayMinutes = 1) + public static function perMinutes($decayMinutes, $maxAttempts) { return new static('', $maxAttempts, $decayMinutes); } From aa7a8f1eb2cf26d5d6cd685bef8fc237bdcd3922 Mon Sep 17 00:00:00 2001 From: Zlatoslav Desyatnikov Date: Fri, 26 Feb 2021 16:17:03 +0300 Subject: [PATCH 270/443] Fix Event Dispatcher listen phpdoc: add array to $listener (#36399) --- src/Illuminate/Contracts/Events/Dispatcher.php | 2 +- src/Illuminate/Events/Dispatcher.php | 2 +- src/Illuminate/Events/NullDispatcher.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Contracts/Events/Dispatcher.php b/src/Illuminate/Contracts/Events/Dispatcher.php index 21be95da0ff9..638610698e68 100644 --- a/src/Illuminate/Contracts/Events/Dispatcher.php +++ b/src/Illuminate/Contracts/Events/Dispatcher.php @@ -8,7 +8,7 @@ interface Dispatcher * Register an event listener with the dispatcher. * * @param \Closure|string|array $events - * @param \Closure|string|null $listener + * @param \Closure|string|array|null $listener * @return void */ public function listen($events, $listener = null); diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index d1e5da9e47f2..96f08f01b514 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -71,7 +71,7 @@ public function __construct(ContainerContract $container = null) * Register an event listener with the dispatcher. * * @param \Closure|string|array $events - * @param \Closure|string|null $listener + * @param \Closure|string|array|null $listener * @return void */ public function listen($events, $listener = null) diff --git a/src/Illuminate/Events/NullDispatcher.php b/src/Illuminate/Events/NullDispatcher.php index dcfdc95f9e94..5c020cfdd732 100644 --- a/src/Illuminate/Events/NullDispatcher.php +++ b/src/Illuminate/Events/NullDispatcher.php @@ -65,7 +65,7 @@ public function until($event, $payload = []) * Register an event listener with the dispatcher. * * @param \Closure|string|array $events - * @param \Closure|string|null $listener + * @param \Closure|string|array|null $listener * @return void */ public function listen($events, $listener = null) From 50b4a944aa9067fbd157a97b1d2cd6d2550979b7 Mon Sep 17 00:00:00 2001 From: foremtehan <53290883+foremtehan@users.noreply.github.com> Date: Fri, 26 Feb 2021 16:47:27 +0330 Subject: [PATCH 271/443] [8.x] Added make method to App Facade (#36402) --- src/Illuminate/Support/Facades/App.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index 63d8709143d7..935c1fc6ad9d 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -7,6 +7,7 @@ * @method static \Illuminate\Support\ServiceProvider register(\Illuminate\Support\ServiceProvider|string $provider, bool $force = false) * @method static \Illuminate\Support\ServiceProvider resolveProvider(string $provider) * @method static array getProviders(\Illuminate\Support\ServiceProvider|string $provider) + * @method static mixed make($abstract, array $parameters = []) * @method static bool configurationIsCached() * @method static bool hasBeenBootstrapped() * @method static bool isDownForMaintenance() From 8a1445396617408e98cdf306296bd9440f25e5be Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 26 Feb 2021 08:19:51 -0600 Subject: [PATCH 272/443] Add Buffered Console Output (#36404) * add buffered console output * Apply fixes from StyleCI (#36403) * change visibility --- src/Illuminate/Console/Application.php | 3 +- .../Console/BufferedConsoleOutput.php | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/Illuminate/Console/BufferedConsoleOutput.php diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 7066c8485425..345ab941116e 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -19,7 +19,6 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\BufferedOutput; -use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\PhpExecutableFinder; @@ -86,7 +85,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null $this->events->dispatch( new CommandStarting( - $commandName, $input, $output = $output ?: new ConsoleOutput + $commandName, $input, $output = $output ?: new BufferedConsoleOutput ) ); diff --git a/src/Illuminate/Console/BufferedConsoleOutput.php b/src/Illuminate/Console/BufferedConsoleOutput.php new file mode 100644 index 000000000000..4bb5ca228541 --- /dev/null +++ b/src/Illuminate/Console/BufferedConsoleOutput.php @@ -0,0 +1,41 @@ +buffer, function () { + $this->buffer = ''; + }); + } + + /** + * {@inheritdoc} + */ + protected function doWrite(string $message, bool $newline) + { + $this->buffer .= $message; + + if ($newline) { + $this->buffer .= \PHP_EOL; + } + + return parent::doWrite($message, $newline); + } +} From 39e1f84a48fec024859d4e80948aca9bd7878658 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 27 Feb 2021 11:21:08 -0600 Subject: [PATCH 273/443] stop on first failure support --- .../Foundation/Http/FormRequest.php | 9 ++++- src/Illuminate/Validation/Validator.php | 24 +++++++++++++ tests/Validation/ValidationValidatorTest.php | 36 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 96169f3ce40a..8c2da9699600 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -58,6 +58,13 @@ class FormRequest extends Request implements ValidatesWhenResolved */ protected $errorBag = 'default'; + /** + * Indicates whether validation should stop after the first rule failure. + * + * @var bool + */ + protected $stopOnFirstFailure = false; + /** * The validator instance. * @@ -104,7 +111,7 @@ protected function createDefaultValidator(ValidationFactory $factory) return $factory->make( $this->validationData(), $this->container->call([$this, 'rules']), $this->messages(), $this->attributes() - ); + )->stopOnFirstFailure($this->stopOnFirstFailure); } /** diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index a3c7ea80c4bd..dcb17d290714 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -146,6 +146,13 @@ class Validator implements ValidatorContract */ public $customValues = []; + /** + * Indicates if the validator should stop on the first rule failure. + * + * @var bool + */ + protected $stopOnFirstFailure = false; + /** * All of the custom validator extensions. * @@ -373,6 +380,10 @@ public function passes() continue; } + if ($this->stopOnFirstFailure && $this->messages->isNotEmpty()) { + break; + } + foreach ($rules as $rule) { $this->validateAttribute($attribute, $rule); @@ -1074,6 +1085,19 @@ public function sometimes($attribute, $rules, callable $callback) return $this; } + /** + * Instruct the validator to stop validating after the first rule failure. + * + * @param bool $stopOnFirstFailure + * @return $this + */ + public function stopOnFirstFailure($stopOnFirstFailure = true) + { + $this->stopOnFirstFailure = $stopOnFirstFailure; + + return $this; + } + /** * Register an array of custom validator extensions. * diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 48f9edcef0f8..a60b93b9abf4 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -5719,6 +5719,42 @@ public function testValidateFailsWithAsterisksAsDataKeys() $this->assertSame(['data.1.date' => ['validation.date'], 'data.*.date' => ['validation.date']], $validator->messages()->toArray()); } + public function testFailOnFirstError() + { + $trans = $this->getIlluminateArrayTranslator(); + $data = [ + 'foo' => 'bar', + 'age' => 30, + ]; + $rules = [ + 'foo' => ['required', 'string'], + 'baz' => ['required'], + 'age' => ['required', 'min:31'], + ]; + + $expectedFailOnFirstErrorDisableResult = [ + 'baz' => [ + 'validation.required', + ], + 'age' => [ + 'validation.min.string', + ], + ]; + $failOnFirstErrorDisable = new Validator($trans, $data, $rules); + $this->assertFalse($failOnFirstErrorDisable->passes()); + $this->assertEquals($expectedFailOnFirstErrorDisableResult, $failOnFirstErrorDisable->getMessageBag()->getMessages()); + + $expectedFailOnFirstErrorEnableResult = [ + 'baz' => [ + 'validation.required', + ], + ]; + $failOnFirstErrorEnable = new Validator($trans, $data, $rules, [], []); + $failOnFirstErrorEnable->stopOnFirstFailure(); + $this->assertFalse($failOnFirstErrorEnable->passes()); + $this->assertEquals($expectedFailOnFirstErrorEnableResult, $failOnFirstErrorEnable->getMessageBag()->getMessages()); + } + protected function getTranslator() { return m::mock(TranslatorContract::class); From f330a094db465c5e07d8234a3ff1c10b2a1b4d99 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 27 Feb 2021 11:21:49 -0600 Subject: [PATCH 274/443] Apply fixes from StyleCI (#36413) --- 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 dcb17d290714..48d9946386d6 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -381,8 +381,8 @@ public function passes() } if ($this->stopOnFirstFailure && $this->messages->isNotEmpty()) { - break; - } + break; + } foreach ($rules as $rule) { $this->validateAttribute($attribute, $rule); From 0038ef28eb07db1078688e1e384980cc60f6047e Mon Sep 17 00:00:00 2001 From: Petr Levtonov Date: Sat, 27 Feb 2021 16:59:00 +0100 Subject: [PATCH 275/443] laravel/framework#36337: Respect serialization and compression of phpredis during locking - Support phpredis serialization when locking (none, php, json, igbinary, msgpack). - Support phpredis compression when locking (none, lzf, zstd, lz4). --- src/Illuminate/Cache/PhpRedisLock.php | 89 +++++ src/Illuminate/Cache/RedisStore.php | 10 +- .../Cache/PhpRedisCacheLockTest.php | 306 ++++++++++++++++++ 3 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 src/Illuminate/Cache/PhpRedisLock.php create mode 100644 tests/Integration/Cache/PhpRedisCacheLockTest.php diff --git a/src/Illuminate/Cache/PhpRedisLock.php b/src/Illuminate/Cache/PhpRedisLock.php new file mode 100644 index 000000000000..8d0670a167fd --- /dev/null +++ b/src/Illuminate/Cache/PhpRedisLock.php @@ -0,0 +1,89 @@ +redis->eval( + LuaScripts::releaseLock(), + 1, + $this->name, + $this->serializedAndCompressedOwner() + ); + } + + protected function serializedAndCompressedOwner(): string + { + $client = $this->redis->client(); + + /* If a serialization mode such as "php" or "igbinary" and/or a + * compression mode such as "lzf" or "zstd" is enabled, the owner + * must be serialized and/or compressed by us, because phpredis does + * not do this for the eval command. + * + * Name must not be modified! + */ + $owner = $client->_serialize($this->owner); + + /* Once the phpredis extension exposes a compress function like the + * above `_serialize()` function, we should switch to it to guarantee + * consistency in the way the extension serializes and compresses to + * avoid the need to check each compression option ourselves. + * + * @see https://github.com/phpredis/phpredis/issues/1938 + */ + if ($this->compressed()) { + if ($this->lzfCompressed()) { + $owner = \lzf_compress($owner); + } elseif ($this->zstdCompressed()) { + $owner = \zstd_compress($owner, $client->getOption(Redis::OPT_COMPRESSION_LEVEL)); + } elseif ($this->lz4Compressed()) { + $owner = \lz4_compress($owner, $client->getOption(Redis::OPT_COMPRESSION_LEVEL)); + } else { + throw new UnexpectedValueException(sprintf( + 'Unknown phpredis compression in use (%d). Unable to release lock.', + $client->getOption(Redis::OPT_COMPRESSION) + )); + } + } + + return $owner; + } + + protected function compressed(): bool + { + return $this->redis->client()->getOption(Redis::OPT_COMPRESSION) !== Redis::COMPRESSION_NONE; + } + + protected function lzfCompressed(): bool + { + return defined('Redis::COMPRESSION_LZF') && + $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_LZF; + } + + protected function zstdCompressed(): bool + { + return defined('Redis::COMPRESSION_ZSTD') && + $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_ZSTD; + } + + protected function lz4Compressed(): bool + { + return defined('Redis::COMPRESSION_LZ4') && + $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_LZ4; + } +} diff --git a/src/Illuminate/Cache/RedisStore.php b/src/Illuminate/Cache/RedisStore.php index cdf1c8fca094..e698bab375d4 100755 --- a/src/Illuminate/Cache/RedisStore.php +++ b/src/Illuminate/Cache/RedisStore.php @@ -4,6 +4,7 @@ use Illuminate\Contracts\Cache\LockProvider; use Illuminate\Contracts\Redis\Factory as Redis; +use Illuminate\Redis\Connections\PhpRedisConnection; class RedisStore extends TaggableStore implements LockProvider { @@ -188,7 +189,14 @@ public function forever($key, $value) */ public function lock($name, $seconds = 0, $owner = null) { - return new RedisLock($this->lockConnection(), $this->prefix.$name, $seconds, $owner); + $lockName = $this->prefix.$name; + $lockConnection = $this->lockConnection(); + + if ($lockConnection instanceof PhpRedisConnection) { + return new PhpRedisLock($lockConnection, $lockName, $seconds, $owner); + } + + return new RedisLock($lockConnection, $lockName, $seconds, $owner); } /** diff --git a/tests/Integration/Cache/PhpRedisCacheLockTest.php b/tests/Integration/Cache/PhpRedisCacheLockTest.php new file mode 100644 index 000000000000..de1048eb30c4 --- /dev/null +++ b/tests/Integration/Cache/PhpRedisCacheLockTest.php @@ -0,0 +1,306 @@ +setUpRedis(); + } + + protected function tearDown(): void + { + parent::tearDown(); + + $this->tearDownRedis(); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithoutSerializationAndCompression() + { + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithPhpSerialization() + { + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithJsonSerialization() + { + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_JSON); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithIgbinarySerialization() + { + if (! defined('Redis::SERIALIZER_IGBINARY')) { + $this->markTestSkipped('Redis extension is not configured to support the igbinary serializer.'); + } + + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_IGBINARY); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithMsgpackSerialization() + { + if (! defined('Redis::SERIALIZER_MSGPACK')) { + $this->markTestSkipped('Redis extension is not configured to support the msgpack serializer.'); + } + + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_MSGPACK); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithLzfCompression() + { + if (! defined('Redis::COMPRESSION_LZF')) { + $this->markTestSkipped('Redis extension is not configured to support the lzf compression.'); + } + + if (! extension_loaded('lzf')) { + $this->markTestSkipped('Lzf extension is not installed.'); + } + + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_LZF); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithZstdCompression() + { + if (! defined('Redis::COMPRESSION_ZSTD')) { + $this->markTestSkipped('Redis extension is not configured to support the zstd compression.'); + } + + if (! extension_loaded('zstd')) { + $this->markTestSkipped('Zstd extension is not installed.'); + } + + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_ZSTD); + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, Redis::COMPRESSION_ZSTD_DEFAULT); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, Redis::COMPRESSION_ZSTD_MIN); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, Redis::COMPRESSION_ZSTD_MAX); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithLz4Compression() + { + if (! defined('Redis::COMPRESSION_LZ4')) { + $this->markTestSkipped('Redis extension is not configured to support the lz4 compression.'); + } + + if (! extension_loaded('lz4')) { + $this->markTestSkipped('Lz4 extension is not installed.'); + } + + $this->markTestIncomplete( + 'phpredis extension does not compress consistently with the php '. + 'extension lz4. See: https://github.com/phpredis/phpredis/issues/1939' + ); + + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_LZ4); + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, 1); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, 3); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + + $client->setOption(Redis::OPT_COMPRESSION_LEVEL, 12); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } + + public function testRedisLockCanBeAcquiredAndReleasedWithSerializationAndCompression() + { + if (! defined('Redis::COMPRESSION_LZF')) { + $this->markTestSkipped('Redis extension is not configured to support the lzf compression.'); + } + + if (! extension_loaded('lzf')) { + $this->markTestSkipped('Lzf extension is not installed.'); + } + + $this->app['config']->set('database.redis.client', 'phpredis'); + $this->app['config']->set('cache.stores.redis.connection', 'default'); + $this->app['config']->set('cache.stores.redis.lock_connection', 'default'); + + /** @var \Illuminate\Cache\RedisStore $store */ + $store = Cache::store('redis'); + /** @var \Redis $client */ + $client = $store->lockConnection()->client(); + + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_LZF); + $store->lock('foo')->forceRelease(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + $lock = $store->lock('foo', 10); + $this->assertTrue($lock->get()); + $this->assertFalse($store->lock('foo', 10)->get()); + $lock->release(); + $this->assertNull($store->lockConnection()->get($store->getPrefix().'foo')); + } +} From bc7d4b7fb1a444c1646d7d47a75185b72e78537d Mon Sep 17 00:00:00 2001 From: "iAm[i]nE" Date: Sun, 28 Feb 2021 19:34:24 +0100 Subject: [PATCH 276/443] Don't flash 'current_password' input #5541 (#36415) --- src/Illuminate/Foundation/Exceptions/Handler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 61a775a92a2d..bd8016329e6f 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -103,6 +103,7 @@ class Handler implements ExceptionHandlerContract * @var string[] */ protected $dontFlash = [ + 'current_password', 'password', 'password_confirmation', ]; From 4a6bdbb2b0d2fc6afbf68fe7c7058445953b6662 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Mon, 1 Mar 2021 14:46:06 +0100 Subject: [PATCH 277/443] Rename rules to rule in ValidationRuleParser::parse() (#36414) This matches the two callsites as well as the description. --- .../Validation/ValidationRuleParser.php | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Validation/ValidationRuleParser.php b/src/Illuminate/Validation/ValidationRuleParser.php index 9438fb11f7b7..3fea4005aa28 100644 --- a/src/Illuminate/Validation/ValidationRuleParser.php +++ b/src/Illuminate/Validation/ValidationRuleParser.php @@ -186,57 +186,57 @@ protected function mergeRulesForAttribute($results, $attribute, $rules) /** * Extract the rule name and parameters from a rule. * - * @param array|string $rules + * @param array|string $rule * @return array */ - public static function parse($rules) + public static function parse($rule) { - if ($rules instanceof RuleContract) { - return [$rules, []]; + if ($rule instanceof RuleContract) { + return [$rule, []]; } - if (is_array($rules)) { - $rules = static::parseArrayRule($rules); + if (is_array($rule)) { + $rule = static::parseArrayRule($rule); } else { - $rules = static::parseStringRule($rules); + $rule = static::parseStringRule($rule); } - $rules[0] = static::normalizeRule($rules[0]); + $rule[0] = static::normalizeRule($rule[0]); - return $rules; + return $rule; } /** * Parse an array based rule. * - * @param array $rules + * @param array $rule * @return array */ - protected static function parseArrayRule(array $rules) + protected static function parseArrayRule(array $rule) { - return [Str::studly(trim(Arr::get($rules, 0))), array_slice($rules, 1)]; + return [Str::studly(trim(Arr::get($rule, 0))), array_slice($rule, 1)]; } /** * Parse a string based rule. * - * @param string $rules + * @param string $rule * @return array */ - protected static function parseStringRule($rules) + protected static function parseStringRule($rule) { $parameters = []; // The format for specifying validation rules and parameters follows an // easy {rule}:{parameters} formatting convention. For instance the // rule "Max:3" states that the value may only be three letters. - if (strpos($rules, ':') !== false) { - [$rules, $parameter] = explode(':', $rules, 2); + if (strpos($rule, ':') !== false) { + [$rule, $parameter] = explode(':', $rule, 2); - $parameters = static::parseParameters($rules, $parameter); + $parameters = static::parseParameters($rule, $parameter); } - return [Str::studly(trim($rules)), $parameters]; + return [Str::studly(trim($rule)), $parameters]; } /** From b72178dbe9d8971c9f8bd1823cb1aa344bcb9637 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Mon, 1 Mar 2021 21:59:05 -0500 Subject: [PATCH 278/443] Add Collection@isSingle method --- src/Illuminate/Collections/Collection.php | 10 ++++++++++ src/Illuminate/Collections/LazyCollection.php | 10 ++++++++++ tests/Support/SupportCollectionTest.php | 10 ++++++++++ tests/Support/SupportLazyCollectionIsLazyTest.php | 7 +++++++ 4 files changed, 37 insertions(+) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 8645ac2cb6f4..fc3ab697be6b 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -553,6 +553,16 @@ public function isEmpty() return empty($this->items); } + /** + * Determine if the collection contains a single element. + * + * @return bool + */ + public function isSingle() + { + return $this->count() === 1; + } + /** * Join all items from the collection using a string. The final items can use a separate glue string. * diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index df186d864399..a7203588ef3b 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -556,6 +556,16 @@ public function isEmpty() return ! $this->getIterator()->valid(); } + /** + * Determine if the collection contains a single element. + * + * @return bool + */ + public function isSingle() + { + return $this->take(2)->count() === 1; + } + /** * Join all items from the collection using a string. The final items can use a separate glue string. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 0cfd0598d26f..27ad32d01e00 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -541,6 +541,16 @@ public function testCountableByWithCallback($collection) })->all()); } + /** + * @dataProvider collectionClassProvider + */ + public function testIsSingle($collection) + { + $this->assertFalse((new $collection([]))->isSingle()); + $this->assertTrue((new $collection([1]))->isSingle()); + $this->assertFalse((new $collection([1, 2]))->isSingle()); + } + public function testIterable() { $c = new Collection(['foo']); diff --git a/tests/Support/SupportLazyCollectionIsLazyTest.php b/tests/Support/SupportLazyCollectionIsLazyTest.php index b61df7a6b632..1db864ab44f4 100644 --- a/tests/Support/SupportLazyCollectionIsLazyTest.php +++ b/tests/Support/SupportLazyCollectionIsLazyTest.php @@ -484,6 +484,13 @@ public function testIsNotEmptyIsLazy() }); } + public function testIsSingleIsLazy() + { + $this->assertEnumerates(2, function ($collection) { + $collection->isSingle(); + }); + } + public function testJoinIsLazy() { $this->assertEnumeratesOnce(function ($collection) { From bdd082d6039d3e1c0be1f8b56f9538372a8d8b28 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 2 Mar 2021 13:27:16 +0000 Subject: [PATCH 279/443] Updated forgotten suggest (#36426) --- src/Illuminate/Broadcasting/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index 3a7fe618a450..45c30271c084 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -34,7 +34,7 @@ } }, "suggest": { - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0)." + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0)." }, "config": { "sort-packages": true From bbd6e02fe20b6fee756fbabb6b5c39552c4a5388 Mon Sep 17 00:00:00 2001 From: Avraham Appel <33736292+avrahamappel@users.noreply.github.com> Date: Tue, 2 Mar 2021 08:27:43 -0500 Subject: [PATCH 280/443] Check for context method (#36424) --- .../Foundation/Exceptions/Handler.php | 4 ++++ .../FoundationExceptionsHandlerTest.php | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index bd8016329e6f..38c29a3996c7 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -278,6 +278,10 @@ protected function shouldntReport(Throwable $e) */ protected function exceptionContext(Throwable $e) { + if (method_exists($e, 'context')) { + return $e->context(); + } + return []; } diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index f7175dc58db5..55b2d54982a5 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -76,6 +76,15 @@ public function testHandlerReportsExceptionAsContext() $this->handler->report(new RuntimeException('Exception message')); } + public function testHandlerCallsContextMethodIfPresent() + { + $logger = m::mock(LoggerInterface::class); + $this->container->instance(LoggerInterface::class, $logger); + $logger->shouldReceive('error')->withArgs(['Exception message', m::subset(['foo' => 'bar'])])->once(); + + $this->handler->report(new ContextProvidingException('Exception message')); + } + public function testHandlerReportsExceptionWhenUnReportable() { $logger = m::mock(LoggerInterface::class); @@ -283,6 +292,16 @@ public function report() } } +class ContextProvidingException extends Exception +{ + public function context() + { + return [ + 'foo' => 'bar', + ]; + } +} + interface ReportingService { public function send($message); From 5b7ffc2b54dec803bd12541ab9c3d6bf3d4666ca Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Mar 2021 07:34:56 -0600 Subject: [PATCH 281/443] rename method --- src/Illuminate/Collections/Collection.php | 4 ++-- src/Illuminate/Collections/LazyCollection.php | 4 ++-- tests/Support/SupportCollectionTest.php | 8 ++++---- tests/Support/SupportLazyCollectionIsLazyTest.php | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index fc3ab697be6b..68fb3cecc100 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -554,11 +554,11 @@ public function isEmpty() } /** - * Determine if the collection contains a single element. + * Determine if the collection contains a single item. * * @return bool */ - public function isSingle() + public function containsOneItem() { return $this->count() === 1; } diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index a7203588ef3b..9b90792925b4 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -557,11 +557,11 @@ public function isEmpty() } /** - * Determine if the collection contains a single element. + * Determine if the collection contains a single item. * * @return bool */ - public function isSingle() + public function containsOneItem() { return $this->take(2)->count() === 1; } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 27ad32d01e00..8c562d572d48 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -544,11 +544,11 @@ public function testCountableByWithCallback($collection) /** * @dataProvider collectionClassProvider */ - public function testIsSingle($collection) + public function testContainsOneItem($collection) { - $this->assertFalse((new $collection([]))->isSingle()); - $this->assertTrue((new $collection([1]))->isSingle()); - $this->assertFalse((new $collection([1, 2]))->isSingle()); + $this->assertFalse((new $collection([]))->containsOneItem()); + $this->assertTrue((new $collection([1]))->containsOneItem()); + $this->assertFalse((new $collection([1, 2]))->containsOneItem()); } public function testIterable() diff --git a/tests/Support/SupportLazyCollectionIsLazyTest.php b/tests/Support/SupportLazyCollectionIsLazyTest.php index 1db864ab44f4..f6f16803e073 100644 --- a/tests/Support/SupportLazyCollectionIsLazyTest.php +++ b/tests/Support/SupportLazyCollectionIsLazyTest.php @@ -484,10 +484,10 @@ public function testIsNotEmptyIsLazy() }); } - public function testIsSingleIsLazy() + public function testContainsOneItemIsLazy() { $this->assertEnumerates(2, function ($collection) { - $collection->isSingle(); + $collection->containsOneItem(); }); } From d0e4731e92ca88f4a78fe9e0c2c426a3e8c063c8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Mar 2021 08:28:26 -0600 Subject: [PATCH 282/443] patch 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 236cd15d06f3..264e0deba796 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.16'; + const VERSION = '6.20.17'; /** * The base path for the Laravel installation. From 81ef9850cc388f2f92b868fb35ffb76f0c9a0f46 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Mar 2021 08:28:44 -0600 Subject: [PATCH 283/443] 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 2c4926abc16d..b61e3db92acf 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.29.0'; + const VERSION = '8.30.0'; /** * The base path for the Laravel installation. From e3f48f74b0ff6436f47261882649ad072936f79a Mon Sep 17 00:00:00 2001 From: Lloric Mayuga Garcia Date: Wed, 3 Mar 2021 22:15:52 +0800 Subject: [PATCH 284/443] [8.x] Fix formatWheres in DatabaseRule (#36441) * Fix formatWheres in DatabaseRule * Update DatabaseRule.php * Update DatabaseRule.php * Fix styleci --- src/Illuminate/Validation/Rules/DatabaseRule.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Rules/DatabaseRule.php b/src/Illuminate/Validation/Rules/DatabaseRule.php index b8113b2afadb..88b4d27cd941 100644 --- a/src/Illuminate/Validation/Rules/DatabaseRule.php +++ b/src/Illuminate/Validation/Rules/DatabaseRule.php @@ -196,7 +196,11 @@ public function queryCallbacks() protected function formatWheres() { return collect($this->wheres)->map(function ($where) { - return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; + if (is_bool($where['value'])) { + return $where['column'].','.($where['value'] ? 'true' : 'false'); + } else { + return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; + } })->implode(','); } } From 70f2f019f2f8513c3e775a0d7d0d292c22ebf18c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 3 Mar 2021 08:54:27 -0600 Subject: [PATCH 285/443] Revert "[8.x] Respect custom route key with explicit route model binding (#36375)" (#36449) This reverts commit 8c5292eb96d9cf104b9b3bcdd471bde59a117de1. --- src/Illuminate/Routing/RouteBinding.php | 8 +++---- src/Illuminate/Routing/Router.php | 2 +- tests/Routing/RoutingRouteTest.php | 31 ------------------------- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/src/Illuminate/Routing/RouteBinding.php b/src/Illuminate/Routing/RouteBinding.php index 45b2e8ec8d05..133a84a40b07 100644 --- a/src/Illuminate/Routing/RouteBinding.php +++ b/src/Illuminate/Routing/RouteBinding.php @@ -33,7 +33,7 @@ public static function forCallback($container, $binder) */ protected static function createClassBinding($container, $binding) { - return function ($value, $route, $key) use ($container, $binding) { + return function ($value, $route) use ($container, $binding) { // If the binding has an @ sign, we will assume it's being used to delimit // the class name from the bind method name. This allows for bindings // to run multiple bind methods in a single class for convenience. @@ -41,7 +41,7 @@ protected static function createClassBinding($container, $binding) $callable = [$container->make($class), $method]; - return $callable($value, $route, $key); + return $callable($value, $route); }; } @@ -57,7 +57,7 @@ protected static function createClassBinding($container, $binding) */ public static function forModel($container, $class, $callback = null) { - return function ($value, $route, $key) use ($container, $class, $callback) { + return function ($value) use ($container, $class, $callback) { if (is_null($value)) { return; } @@ -67,7 +67,7 @@ public static function forModel($container, $class, $callback = null) // throw a not found exception otherwise we will return the instance. $instance = $container->make($class); - if ($model = $instance->resolveRouteBinding($value, $route->bindingFieldFor($key))) { + if ($model = $instance->resolveRouteBinding($value)) { return $model; } diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 4e57ffc6ec9d..dfdb7ae7332e 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -840,7 +840,7 @@ public function substituteImplicitBindings($route) */ protected function performBinding($key, $value, $route) { - return call_user_func($this->binders[$key], $value, $route, $key); + return call_user_func($this->binders[$key], $value, $route); } /** diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index f4244a3bbb3e..a0d4548dc06e 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -29,7 +29,6 @@ use Illuminate\Routing\UrlGenerator; use Illuminate\Support\Str; use LogicException; -use Mockery; use PHPUnit\Framework\TestCase; use stdClass; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; @@ -939,36 +938,6 @@ public function testModelBinding() $this->assertSame('TAYLOR', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent()); } - public function testModelBindingWithCustomKey() - { - // Create the router. - $container = new Container(); - $router = new Router(new Dispatcher(), $container); - $container->singleton(Registrar::class, function () use ($router) { - return $router; - }); - - $router->get('foo/{bar:custom}', ['middleware' => SubstituteBindings::class, 'uses' => function ($name) { - return $name; - }]); - $router->model('bar', RouteModelBindingStub::class); - - // Mock the stub so we can verify that the method is called with custom key. - $mock = $container->instance( - RouteModelBindingStub::class, - Mockery::mock(RouteModelBindingStub::class), - ); - - $mock->shouldReceive('resolveRouteBinding') - ->with('taylor', 'custom') - ->once() - ->andReturn('TAYLOR'); - - $this->assertSame('TAYLOR', $router->dispatch(Request::create('foo/taylor', 'GET'))->getContent()); - - Mockery::close(); - } - public function testModelBindingWithNullReturn() { $this->expectException(ModelNotFoundException::class); From ab7e1c19ee0403e15fc59983b7ccb86d85db45e6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 3 Mar 2021 08:59:13 -0600 Subject: [PATCH 286/443] patch --- 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 b61e3db92acf..1e35f20d4f46 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.30.0'; + const VERSION = '8.30.1'; /** * The base path for the Laravel installation. From f927dc74e959457e939393de2768d72847098e17 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 3 Mar 2021 11:29:19 -0600 Subject: [PATCH 287/443] Revert "[8.x] Fix formatWheres in DatabaseRule (#36441)" (#36452) This reverts commit e3f48f74b0ff6436f47261882649ad072936f79a. --- src/Illuminate/Validation/Rules/DatabaseRule.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/Rules/DatabaseRule.php b/src/Illuminate/Validation/Rules/DatabaseRule.php index 88b4d27cd941..b8113b2afadb 100644 --- a/src/Illuminate/Validation/Rules/DatabaseRule.php +++ b/src/Illuminate/Validation/Rules/DatabaseRule.php @@ -196,11 +196,7 @@ public function queryCallbacks() protected function formatWheres() { return collect($this->wheres)->map(function ($where) { - if (is_bool($where['value'])) { - return $where['column'].','.($where['value'] ? 'true' : 'false'); - } else { - return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; - } + return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; })->implode(','); } } From 018314829ccb70ec20a6fc25fa4bd382d09d6cc0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 3 Mar 2021 12:04:44 -0600 Subject: [PATCH 288/443] Revert "Revert "[8.x] Fix formatWheres in DatabaseRule (#36441)" (#36452)" (#36453) This reverts commit f927dc74e959457e939393de2768d72847098e17. --- src/Illuminate/Validation/Rules/DatabaseRule.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Rules/DatabaseRule.php b/src/Illuminate/Validation/Rules/DatabaseRule.php index b8113b2afadb..88b4d27cd941 100644 --- a/src/Illuminate/Validation/Rules/DatabaseRule.php +++ b/src/Illuminate/Validation/Rules/DatabaseRule.php @@ -196,7 +196,11 @@ public function queryCallbacks() protected function formatWheres() { return collect($this->wheres)->map(function ($where) { - return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; + if (is_bool($where['value'])) { + return $where['column'].','.($where['value'] ? 'true' : 'false'); + } else { + return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; + } })->implode(','); } } From add249472cd192cabcb4f113ff7915f667394141 Mon Sep 17 00:00:00 2001 From: Claudio Dekker <1752195+claudiodekker@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:07:50 +0100 Subject: [PATCH 289/443] Implement Fluent JSON Assertions --- src/Illuminate/Testing/Fluent/Assert.php | 76 ++ .../Testing/Fluent/Concerns/Debugging.php | 20 + .../Testing/Fluent/Concerns/Has.php | 100 +++ .../Testing/Fluent/Concerns/Interaction.php | 41 ++ .../Testing/Fluent/Concerns/Matching.php | 70 ++ src/Illuminate/Testing/TestResponse.php | 20 +- tests/Testing/Fluent/AssertTest.php | 688 ++++++++++++++++++ tests/Testing/Stubs/ArrayableStubObject.php | 25 + tests/Testing/TestResponseTest.php | 22 + 9 files changed, 1059 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Testing/Fluent/Assert.php create mode 100644 src/Illuminate/Testing/Fluent/Concerns/Debugging.php create mode 100644 src/Illuminate/Testing/Fluent/Concerns/Has.php create mode 100644 src/Illuminate/Testing/Fluent/Concerns/Interaction.php create mode 100644 src/Illuminate/Testing/Fluent/Concerns/Matching.php create mode 100644 tests/Testing/Fluent/AssertTest.php create mode 100644 tests/Testing/Stubs/ArrayableStubObject.php diff --git a/src/Illuminate/Testing/Fluent/Assert.php b/src/Illuminate/Testing/Fluent/Assert.php new file mode 100644 index 000000000000..a5e89e83294c --- /dev/null +++ b/src/Illuminate/Testing/Fluent/Assert.php @@ -0,0 +1,76 @@ +path = $path; + $this->props = $props; + } + + protected function dotPath($key): string + { + if (is_null($this->path)) { + return $key; + } + + return implode('.', [$this->path, $key]); + } + + protected function prop(string $key = null) + { + return Arr::get($this->props, $key); + } + + protected function scope($key, Closure $callback): self + { + $props = $this->prop($key); + $path = $this->dotPath($key); + + PHPUnit::assertIsArray($props, sprintf('Property [%s] is not scopeable.', $path)); + + $scope = new self($props, $path); + $callback($scope); + $scope->interacted(); + + return $this; + } + + public static function fromArray(array $data): self + { + return new self($data); + } + + public static function fromAssertableJsonString(AssertableJsonString $json): self + { + return self::fromArray($json->json()); + } + + public function toArray() + { + return $this->props; + } +} diff --git a/src/Illuminate/Testing/Fluent/Concerns/Debugging.php b/src/Illuminate/Testing/Fluent/Concerns/Debugging.php new file mode 100644 index 000000000000..d604f0e0b21d --- /dev/null +++ b/src/Illuminate/Testing/Fluent/Concerns/Debugging.php @@ -0,0 +1,20 @@ +prop($prop)); + + return $this; + } + + public function dd(string $prop = null): void + { + dd($this->prop($prop)); + } + + abstract protected function prop(string $key = null); +} diff --git a/src/Illuminate/Testing/Fluent/Concerns/Has.php b/src/Illuminate/Testing/Fluent/Concerns/Has.php new file mode 100644 index 000000000000..28955a742493 --- /dev/null +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -0,0 +1,100 @@ +prop($key), + sprintf('Property [%s] does not have the expected size.', $this->dotPath($key)) + ); + + return $this; + } + + public function hasAll($key): self + { + $keys = is_array($key) ? $key : func_get_args(); + + foreach ($keys as $prop => $count) { + if (is_int($prop)) { + $this->has($count); + } else { + $this->has($prop, $count); + } + } + + return $this; + } + + public function has(string $key, $value = null, Closure $scope = null): self + { + $prop = $this->prop(); + + PHPUnit::assertTrue( + Arr::has($prop, $key), + sprintf('Property [%s] does not exist.', $this->dotPath($key)) + ); + + $this->interactsWith($key); + + // When all three arguments are provided, this indicates a short-hand + // expression that combines both a `count`-assertion, followed by + // directly creating a `scope` on the first element. + if (is_int($value) && ! is_null($scope)) { + $prop = $this->prop($key); + $path = $this->dotPath($key); + + PHPUnit::assertTrue($value > 0, sprintf('Cannot scope directly onto the first entry of property [%s] when asserting that it has a size of 0.', $path)); + PHPUnit::assertIsArray($prop, sprintf('Direct scoping is unsupported for non-array like properties such as [%s].', $path)); + + $this->count($key, $value); + + return $this->scope($key.'.'.array_keys($prop)[0], $scope); + } + + if (is_callable($value)) { + $this->scope($key, $value); + } elseif (! is_null($value)) { + $this->count($key, $value); + } + + return $this; + } + + public function missingAll($key): self + { + $keys = is_array($key) ? $key : func_get_args(); + + foreach ($keys as $prop) { + $this->missing($prop); + } + + return $this; + } + + public function missing(string $key): self + { + PHPUnit::assertNotTrue( + Arr::has($this->prop(), $key), + sprintf('Property [%s] was found while it was expected to be missing.', $this->dotPath($key)) + ); + + return $this; + } + + abstract protected function prop(string $key = null); + + abstract protected function dotPath($key): string; + + abstract protected function interactsWith(string $key): void; + + abstract protected function scope($key, Closure $callback); +} diff --git a/src/Illuminate/Testing/Fluent/Concerns/Interaction.php b/src/Illuminate/Testing/Fluent/Concerns/Interaction.php new file mode 100644 index 000000000000..d938438a618c --- /dev/null +++ b/src/Illuminate/Testing/Fluent/Concerns/Interaction.php @@ -0,0 +1,41 @@ +interacted, true)) { + $this->interacted[] = $prop; + } + } + + public function interacted(): void + { + PHPUnit::assertSame( + [], + array_diff(array_keys($this->prop()), $this->interacted), + $this->path + ? sprintf('Unexpected properties were found in scope [%s].', $this->path) + : 'Unexpected properties were found on the root level.' + ); + } + + public function etc(): self + { + $this->interacted = array_keys($this->prop()); + + return $this; + } + + abstract protected function prop(string $key = null); +} diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php new file mode 100644 index 000000000000..3edce127d362 --- /dev/null +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -0,0 +1,70 @@ + $value) { + $this->where($key, $value); + } + + return $this; + } + + public function where($key, $expected): self + { + $this->has($key); + + $actual = $this->prop($key); + + if ($expected instanceof Closure) { + PHPUnit::assertTrue( + $expected(is_array($actual) ? Collection::make($actual) : $actual), + sprintf('Property [%s] was marked as invalid using a closure.', $this->dotPath($key)) + ); + + return $this; + } + + if ($expected instanceof Arrayable) { + $expected = $expected->toArray(); + } + + $this->ensureSorted($expected); + $this->ensureSorted($actual); + + PHPUnit::assertSame( + $expected, + $actual, + sprintf('Property [%s] does not match the expected value.', $this->dotPath($key)) + ); + + return $this; + } + + protected function ensureSorted(&$value): void + { + if (! is_array($value)) { + return; + } + + foreach ($value as &$arg) { + $this->ensureSorted($arg); + } + + ksort($value); + } + + abstract protected function dotPath($key): string; + + abstract protected function prop(string $key = null); + + abstract public function has(string $key, $value = null, Closure $scope = null); +} diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 1bfc75285518..b900418caf79 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -14,6 +14,7 @@ use Illuminate\Support\Traits\Tappable; use Illuminate\Testing\Assert as PHPUnit; use Illuminate\Testing\Constraints\SeeInOrder; +use Illuminate\Testing\Fluent\Assert as FluentAssert; use LogicException; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -507,13 +508,26 @@ public function assertDontSeeText($value, $escape = true) /** * Assert that the response is a superset of the given JSON. * - * @param array $data + * @param array|callable $value * @param bool $strict * @return $this */ - public function assertJson(array $data, $strict = false) + public function assertJson($value, $strict = false) { - $this->decodeResponseJson()->assertSubset($data, $strict); + $json = $this->decodeResponseJson(); + + if (is_array($value)) { + $json->assertSubset($value, $strict); + } else { + $assert = FluentAssert::fromAssertableJsonString($json); + + $value($assert); + + if ($strict) { + $assert->interacted(); + } + } + return $this; } diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php new file mode 100644 index 000000000000..f02e366f40a0 --- /dev/null +++ b/tests/Testing/Fluent/AssertTest.php @@ -0,0 +1,688 @@ + 'value', + ]); + + $assert->has('prop'); + } + + public function testAssertHasFailsWhenPropMissing() + { + $assert = Assert::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [prop] does not exist.'); + + $assert->has('prop'); + } + + public function testAssertHasNestedProp() + { + $assert = Assert::fromArray([ + 'example' => [ + 'nested' => 'nested-value', + ], + ]); + + $assert->has('example.nested'); + } + + public function testAssertHasFailsWhenNestedPropMissing() + { + $assert = Assert::fromArray([ + 'example' => [ + 'nested' => 'nested-value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [example.another] does not exist.'); + + $assert->has('example.another'); + } + + public function testAssertCountItemsInProp() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $assert->has('bar', 2); + } + + public function testAssertCountFailsWhenAmountOfItemsDoesNotMatch() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] does not have the expected size.'); + + $assert->has('bar', 1); + } + + public function testAssertCountFailsWhenPropMissing() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->has('baz', 1); + } + + public function testAssertHasFailsWhenSecondArgumentUnsupportedType() + { + $assert = Assert::fromArray([ + 'bar' => 'baz', + ]); + + $this->expectException(TypeError::class); + + $assert->has('bar', 'invalid'); + } + + public function testAssertMissing() + { + $assert = Assert::fromArray([ + 'foo' => [ + 'bar' => true, + ], + ]); + + $assert->missing('foo.baz'); + } + + public function testAssertMissingFailsWhenPropExists() + { + $assert = Assert::fromArray([ + 'prop' => 'value', + 'foo' => [ + 'bar' => true, + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo.bar] was found while it was expected to be missing.'); + + $assert->missing('foo.bar'); + } + + public function testAssertMissingAll() + { + $assert = Assert::fromArray([ + 'baz' => 'foo', + ]); + + $assert->missingAll([ + 'foo', + 'bar', + ]); + } + + public function testAssertMissingAllFailsWhenAtLeastOnePropExists() + { + $assert = Assert::fromArray([ + 'baz' => 'foo', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] was found while it was expected to be missing.'); + + $assert->missingAll([ + 'bar', + 'baz', + ]); + } + + public function testAssertMissingAllAcceptsMultipleArgumentsInsteadOfArray() + { + $assert = Assert::fromArray([ + 'baz' => 'foo', + ]); + + $assert->missingAll('foo', 'bar'); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] was found while it was expected to be missing.'); + + $assert->missingAll('bar', 'baz'); + } + + public function testAssertWhereMatchesValue() + { + $assert = Assert::fromArray([ + 'bar' => 'value', + ]); + + $assert->where('bar', 'value'); + } + + public function testAssertWhereFailsWhenDoesNotMatchValue() + { + $assert = Assert::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] does not match the expected value.'); + + $assert->where('bar', 'invalid'); + } + + public function testAssertWhereFailsWhenMissing() + { + $assert = Assert::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->where('baz', 'invalid'); + } + + public function testAssertWhereFailsWhenMachingLoosely() + { + $assert = Assert::fromArray([ + 'bar' => 1, + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] does not match the expected value.'); + + $assert->where('bar', true); + } + + public function testAssertWhereUsingClosure() + { + $assert = Assert::fromArray([ + 'bar' => 'baz', + ]); + + $assert->where('bar', function ($value) { + return $value === 'baz'; + }); + } + + public function testAssertWhereFailsWhenDoesNotMatchValueUsingClosure() + { + $assert = Assert::fromArray([ + 'bar' => 'baz', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] was marked as invalid using a closure.'); + + $assert->where('bar', function ($value) { + return $value === 'invalid'; + }); + } + + public function testAssertWhereClosureArrayValuesAreAutomaticallyCastedToCollections() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'foo', + 'example' => 'value', + ], + ]); + + $assert->where('bar', function ($value) { + $this->assertInstanceOf(Collection::class, $value); + + return $value->count() === 2; + }); + } + + public function testAssertWhereMatchesValueUsingArrayable() + { + $stub = ArrayableStubObject::make(['foo' => 'bar']); + + $assert = Assert::fromArray([ + 'bar' => $stub->toArray(), + ]); + + $assert->where('bar', $stub); + } + + public function testAssertWhereMatchesValueUsingArrayableWhenSortedDifferently() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'foo', + 'example' => 'value', + ], + ]); + + $assert->where('bar', function ($value) { + $this->assertInstanceOf(Collection::class, $value); + + return $value->count() === 2; + }); + } + + public function testAssertWhereFailsWhenDoesNotMatchValueUsingArrayable() + { + $assert = Assert::fromArray([ + 'bar' => ['id' => 1, 'name' => 'Example'], + 'baz' => [ + 'id' => 1, + 'name' => 'Taylor Otwell', + 'email' => 'taylor@laravel.com', + 'email_verified_at' => '2021-01-22T10:34:42.000000Z', + 'created_at' => '2021-01-22T10:34:42.000000Z', + 'updated_at' => '2021-01-22T10:34:42.000000Z', + ], + ]); + + $assert + ->where('bar', ArrayableStubObject::make(['name' => 'Example', 'id' => 1])) + ->where('baz', [ + 'name' => 'Taylor Otwell', + 'email' => 'taylor@laravel.com', + 'id' => 1, + 'email_verified_at' => '2021-01-22T10:34:42.000000Z', + 'updated_at' => '2021-01-22T10:34:42.000000Z', + 'created_at' => '2021-01-22T10:34:42.000000Z', + ]); + } + + public function testAssertNestedWhereMatchesValue() + { + $assert = Assert::fromArray([ + 'example' => [ + 'nested' => 'nested-value', + ], + ]); + + $assert->where('example.nested', 'nested-value'); + } + + public function testAssertNestedWhereFailsWhenDoesNotMatchValue() + { + $assert = Assert::fromArray([ + 'example' => [ + 'nested' => 'nested-value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [example.nested] does not match the expected value.'); + + $assert->where('example.nested', 'another-value'); + } + + public function testScope() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $called = false; + $assert->has('bar', function (Assert $assert) use (&$called) { + $called = true; + $assert + ->where('baz', 'example') + ->where('prop', 'value'); + }); + + $this->assertTrue($called, 'The scoped query was never actually called.'); + } + + public function testScopeFailsWhenPropMissing() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->has('baz', function (Assert $item) { + $item->where('baz', 'example'); + }); + } + + public function testScopeFailsWhenPropSingleValue() + { + $assert = Assert::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] is not scopeable.'); + + $assert->has('bar', function (Assert $item) { + // + }); + } + + public function testScopeShorthand() + { + $assert = Assert::fromArray([ + 'bar' => [ + ['key' => 'first'], + ['key' => 'second'], + ], + ]); + + $called = false; + $assert->has('bar', 2, function (Assert $item) use (&$called) { + $item->where('key', 'first'); + $called = true; + }); + + $this->assertTrue($called, 'The scoped query was never actually called.'); + } + + public function testScopeShorthandFailsWhenAssertingZeroItems() + { + $assert = Assert::fromArray([ + 'bar' => [ + ['key' => 'first'], + ['key' => 'second'], + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Cannot scope directly onto the first entry of property [bar] when asserting that it has a size of 0.'); + + $assert->has('bar', 0, function (Assert $item) { + $item->where('key', 'first'); + }); + } + + public function testScopeShorthandFailsWhenAmountOfItemsDoesNotMatch() + { + $assert = Assert::fromArray([ + 'bar' => [ + ['key' => 'first'], + ['key' => 'second'], + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] does not have the expected size.'); + + $assert->has('bar', 1, function (Assert $item) { + $item->where('key', 'first'); + }); + } + + public function testFailsWhenNotInteractingWithAllPropsInScope() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Unexpected properties were found in scope [bar].'); + + $assert->has('bar', function (Assert $item) { + $item->where('baz', 'example'); + }); + } + + public function testDisableInteractionCheckForCurrentScope() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $assert->has('bar', function (Assert $item) { + $item->etc(); + }); + } + + public function testCannotDisableInteractionCheckForDifferentScopes() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => [ + 'foo' => 'bar', + 'example' => 'value', + ], + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Unexpected properties were found in scope [bar.baz].'); + + $assert->has('bar', function (Assert $item) { + $item + ->etc() + ->has('baz', function (Assert $item) { + // + }); + }); + } + + public function testTopLevelPropInteractionDisabledByDefault() + { + $assert = Assert::fromArray([ + 'foo' => 'bar', + 'bar' => 'baz', + ]); + + $assert->has('foo'); + } + + public function testTopLevelInteractionEnabledWhenInteractedFlagSet() + { + $assert = Assert::fromArray([ + 'foo' => 'bar', + 'bar' => 'baz', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Unexpected properties were found on the root level.'); + + $assert + ->has('foo') + ->interacted(); + } + + public function testAssertWhereAllMatchesValues() + { + $assert = Assert::fromArray([ + 'foo' => [ + 'bar' => 'value', + 'example' => ['hello' => 'world'], + ], + 'baz' => 'another', + ]); + + $assert->whereAll([ + 'foo.bar' => 'value', + 'foo.example' => ArrayableStubObject::make(['hello' => 'world']), + 'baz' => function ($value) { + return $value === 'another'; + }, + ]); + } + + public function testAssertWhereAllFailsWhenAtLeastOnePropDoesNotMatchValue() + { + $assert = Assert::fromArray([ + 'foo' => 'bar', + 'baz' => 'example', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] was marked as invalid using a closure.'); + + $assert->whereAll([ + 'foo' => 'bar', + 'baz' => function ($value) { + return $value === 'foo'; + }, + ]); + } + + public function testAssertHasAll() + { + $assert = Assert::fromArray([ + 'foo' => [ + 'bar' => 'value', + 'example' => ['hello' => 'world'], + ], + 'baz' => 'another', + ]); + + $assert->hasAll([ + 'foo.bar', + 'foo.example', + 'baz', + ]); + } + + public function testAssertHasAllFailsWhenAtLeastOnePropMissing() + { + $assert = Assert::fromArray([ + 'foo' => [ + 'bar' => 'value', + 'example' => ['hello' => 'world'], + ], + 'baz' => 'another', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo.baz] does not exist.'); + + $assert->hasAll([ + 'foo.bar', + 'foo.baz', + 'baz', + ]); + } + + public function testAssertHasAllAcceptsMultipleArgumentsInsteadOfArray() + { + $assert = Assert::fromArray([ + 'foo' => [ + 'bar' => 'value', + 'example' => ['hello' => 'world'], + ], + 'baz' => 'another', + ]); + + $assert->hasAll('foo.bar', 'foo.example', 'baz'); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo.baz] does not exist.'); + + $assert->hasAll('foo.bar', 'foo.baz', 'baz'); + } + + public function testAssertCountMultipleProps() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'key' => 'value', + 'prop' => 'example', + ], + 'baz' => [ + 'another' => 'value', + ], + ]); + + $assert->hasAll([ + 'bar' => 2, + 'baz' => 1, + ]); + } + + public function testAssertCountMultiplePropsFailsWhenPropMissing() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'key' => 'value', + 'prop' => 'example', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->hasAll([ + 'bar' => 2, + 'baz' => 1, + ]); + } + + public function testMacroable() + { + Assert::macro('myCustomMacro', function () { + throw new RuntimeException('My Custom Macro was called!'); + }); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('My Custom Macro was called!'); + + $assert = Assert::fromArray(['foo' => 'bar']); + $assert->myCustomMacro(); + } + + public function testTappable() + { + $assert = Assert::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $called = false; + $assert->has('bar', function (Assert $assert) use (&$called) { + $assert->etc(); + $assert->tap(function (Assert $assert) use (&$called) { + $called = true; + }); + }); + + $this->assertTrue($called, 'The scoped query was never actually called.'); + } +} diff --git a/tests/Testing/Stubs/ArrayableStubObject.php b/tests/Testing/Stubs/ArrayableStubObject.php new file mode 100644 index 000000000000..021440e0b287 --- /dev/null +++ b/tests/Testing/Stubs/ArrayableStubObject.php @@ -0,0 +1,25 @@ +data = $data; + } + + public static function make($data = []) + { + return new self($data); + } + + public function toArray() + { + return $this->data; + } +} diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 42d16e72d3fa..055519925cb9 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -9,6 +9,7 @@ use Illuminate\Encryption\Encrypter; use Illuminate\Filesystem\Filesystem; use Illuminate\Http\Response; +use Illuminate\Testing\Fluent\Assert; use Illuminate\Testing\TestResponse; use JsonSerializable; use Mockery as m; @@ -577,6 +578,27 @@ public function testAssertJsonWithNull() $response->assertJson($resource->jsonSerialize()); } + public function testAssertJsonWithFluent() + { + $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableSingleResourceStub)); + + $response->assertJson(function (Assert $json) { + $json->where('0.foo', 'foo 0'); + }); + } + + public function testAssertJsonWithFluentStrict() + { + $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableSingleResourceStub)); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Unexpected properties were found on the root level.'); + + $response->assertJson(function (Assert $json) { + $json->where('0.foo', 'foo 0'); + }, true); + } + public function testAssertSimilarJsonWithMixed() { $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableMixedResourcesStub)); From 3b1fa1ae2ccd64547d27236945dfe454ee9a23e2 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 3 Mar 2021 21:15:47 +0200 Subject: [PATCH 290/443] [6.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index ee1b7ced29b4..5fd976698b85 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.16...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.17...6.x) + + +## [v6.20.17 (2021-03-02)](https://github.com/laravel/framework/compare/v6.20.16...v6.20.17) + +### Added +- Added new line to `DetectsLostConnections` ([#36373](https://github.com/laravel/framework/pull/36373)) ## [v6.20.16 (2021-02-02)](https://github.com/laravel/framework/compare/v6.20.15...v6.20.16) From f31557f76ac5a790d66b717e074537031c48085e Mon Sep 17 00:00:00 2001 From: Claudio Dekker <1752195+claudiodekker@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:20:34 +0100 Subject: [PATCH 291/443] Apply fixes from StyleCI --- src/Illuminate/Testing/TestResponse.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index b900418caf79..eb983f464a6d 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -528,7 +528,6 @@ public function assertJson($value, $strict = false) } } - return $this; } From 44b63329ce9d260b7f9e60f03389c943082721f6 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 3 Mar 2021 21:38:46 +0200 Subject: [PATCH 292/443] [8.x] update changelog --- CHANGELOG-8.x.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 4d383e7fc191..e132fceadef8 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,22 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.29.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.30.0...8.x) + + +## [v8.30.0 (2021-03-02)](https://github.com/laravel/framework/compare/v8.29.0...v8.30.0) + +### Added +- Added new line to `DetectsLostConnections` ([#36373](https://github.com/laravel/framework/pull/36373)) +- Added `Illuminate\Cache\RateLimiting\Limit::perMinutes()` ([#36352](https://github.com/laravel/framework/pull/36352), [86d0a5c](https://github.com/laravel/framework/commit/86d0a5c733b3f22ae2353df538e07605963c3052)) +- Make Database Factory macroable ([#36380](https://github.com/laravel/framework/pull/36380)) +- Added stop on first failure for Validators ([39e1f84](https://github.com/laravel/framework/commit/39e1f84a48fec024859d4e80948aca9bd7878658)) +- Added `containsOneItem()` method to Collections ([#36428](https://github.com/laravel/framework/pull/36428), [5b7ffc2](https://github.com/laravel/framework/commit/5b7ffc2b54dec803bd12541ab9c3d6bf3d4666ca)) + +### Changed +- Respect custom route key with explicit route model binding ([#36375](https://github.com/laravel/framework/pull/36375)) +- Add Buffered Console Output ([#36404](https://github.com/laravel/framework/pull/36404)) +- Don't flash 'current_password' input ([#36415](https://github.com/laravel/framework/pull/36415)) +- Check for context method in Exception Handler ([#36424](https://github.com/laravel/framework/pull/36424)) ## [v8.29.0 (2021-02-23)](https://github.com/laravel/framework/compare/v8.28.1...v8.29.0) From e5963219867edb43c98a1232f45735e14f85d46c Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 3 Mar 2021 21:42:08 +0200 Subject: [PATCH 293/443] [8.x] update changelog --- CHANGELOG-8.x.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index e132fceadef8..28603d11124f 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,15 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.30.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.30.1...8.x) + + +## [v8.30.1 (2021-03-03)](https://github.com/laravel/framework/compare/v8.30.0...v8.30.1) + +### Reverted +- Reverted [Respect custom route key with explicit route model binding](https://github.com/laravel/framework/pull/36375) ([#36449](https://github.com/laravel/framework/pull/36449)) + +### Fixed +- Fixed `formatWheres()` methods in `DatabaseRule` ([#36441](https://github.com/laravel/framework/pull/36441)) ## [v8.30.0 (2021-03-02)](https://github.com/laravel/framework/compare/v8.29.0...v8.30.0) From 448662c91540e237b846507fdf4cf22c7f8d59b5 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 4 Mar 2021 13:51:23 +0100 Subject: [PATCH 294/443] Use ubuntu-18.04 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 476648be81cc..c7b91b6fe781 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: jobs: linux_tests: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 services: memcached: From cada3d21c7f127ba01bb949b2fa045b7faaedbca Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 4 Mar 2021 14:07:30 +0100 Subject: [PATCH 295/443] Apply fixes from StyleCI (#36461) --- src/Illuminate/View/Engines/CompilerEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/View/Engines/CompilerEngine.php b/src/Illuminate/View/Engines/CompilerEngine.php index 1d38d310144c..afcba767fa88 100755 --- a/src/Illuminate/View/Engines/CompilerEngine.php +++ b/src/Illuminate/View/Engines/CompilerEngine.php @@ -3,8 +3,8 @@ namespace Illuminate\View\Engines; use Illuminate\View\Compilers\CompilerInterface; -use Throwable; use Illuminate\View\ViewException; +use Throwable; class CompilerEngine extends PhpEngine { From 6cbe0eb0ea43ba4c512ba9ce2519fa2c09a62a94 Mon Sep 17 00:00:00 2001 From: Ryan Chandler Date: Thu, 4 Mar 2021 14:06:39 +0000 Subject: [PATCH 296/443] [8.x] Add new `VendorTagPublished` event (#36458) * feature: add new VendorTagPublished event * fix: only fire event when something was published * refactor: fire event before erroring in console * revert: move event dispatch into else arm * chore: update comment on $paths * chore: publish to publishable * chore: add missing comment * Update VendorPublishCommand.php * Update VendorTagPublished.php Co-authored-by: Taylor Otwell --- .../Console/VendorPublishCommand.php | 7 +++- .../Foundation/Events/VendorTagPublished.php | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/Illuminate/Foundation/Events/VendorTagPublished.php diff --git a/src/Illuminate/Foundation/Console/VendorPublishCommand.php b/src/Illuminate/Foundation/Console/VendorPublishCommand.php index 17a459e72834..501142f0d63c 100644 --- a/src/Illuminate/Foundation/Console/VendorPublishCommand.php +++ b/src/Illuminate/Foundation/Console/VendorPublishCommand.php @@ -4,6 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; +use Illuminate\Foundation\Events\VendorTagPublished; use Illuminate\Support\Arr; use Illuminate\Support\ServiceProvider; use League\Flysystem\Adapter\Local as LocalAdapter; @@ -159,7 +160,9 @@ protected function publishTag($tag) { $published = false; - foreach ($this->pathsToPublish($tag) as $from => $to) { + $pathsToPublish = $this->pathsToPublish($tag); + + foreach ($pathsToPublish as $from => $to) { $this->publishItem($from, $to); $published = true; @@ -167,6 +170,8 @@ protected function publishTag($tag) if ($published === false) { $this->error('Unable to locate publishable resources.'); + } else { + $this->laravel['events']->dispatch(new VendorTagPublished($tag, $pathsToPublish)); } } diff --git a/src/Illuminate/Foundation/Events/VendorTagPublished.php b/src/Illuminate/Foundation/Events/VendorTagPublished.php new file mode 100644 index 000000000000..084c1293fcfd --- /dev/null +++ b/src/Illuminate/Foundation/Events/VendorTagPublished.php @@ -0,0 +1,33 @@ +tag = $tag; + $this->paths = $paths; + } +} From 34418f340f29d7602be2663a761f4911ecf4c5d0 Mon Sep 17 00:00:00 2001 From: Ryan Chandler Date: Thu, 4 Mar 2021 14:09:31 +0000 Subject: [PATCH 297/443] [8.x] Add new `Stringable::test` method (#36462) * feature: add new Stringable::matches method * tests: new Stringable::matches method * refactor: use match instead of matchAll * chore: rename method from matches to test --- src/Illuminate/Support/Stringable.php | 11 +++++++++++ tests/Support/SupportStringableTest.php | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index ff5f44c5fded..0d544a3987cf 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -365,6 +365,17 @@ public function matchAll($pattern) return collect($matches[1] ?? $matches[0]); } + /** + * Determine if the string matches the given pattern. + * + * @param string $pattern + * @return bool + */ + public function test($pattern) + { + return $this->match($pattern)->isNotEmpty(); + } + /** * Pad both sides of the string with another. * diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 15ab04726cb1..d6c010fd20fd 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -62,6 +62,14 @@ public function testMatch() $this->assertTrue($stringable->matchAll('/nothing/')->isEmpty()); } + public function testTest() + { + $stringable = $this->stringable('foo bar'); + + $this->assertTrue($stringable->test('/bar/')); + $this->assertTrue($stringable->test('/foo (.*)/')); + } + public function testTrim() { $this->assertSame('foo', (string) $this->stringable(' foo ')->trim()); From ddb0c5e68ec8037ed31738bbfed4ededa3cd39da Mon Sep 17 00:00:00 2001 From: LuttaMustache <45479378+LuttaMustache@users.noreply.github.com> Date: Thu, 4 Mar 2021 21:10:57 +0600 Subject: [PATCH 298/443] multiplatform newline check (#36464) --- src/Illuminate/Foundation/Console/PolicyMakeCommand.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php index 0fe6964d5940..78873de065ee 100644 --- a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php +++ b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php @@ -131,8 +131,13 @@ protected function replaceModel($stub, $model) array_keys($replace), array_values($replace), $stub ); - return str_replace( - "use {$namespacedModel};\nuse {$namespacedModel};", "use {$namespacedModel};", $stub + return preg_replace( + vsprintf('/use %s;[\r\n]+use %s;/', [ + preg_quote($namespacedModel, '/'), + preg_quote($namespacedModel, '/'), + ]), + "use {$namespacedModel};", + $stub ); } From 5434332367c23230be01391b500005879bd6fa93 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Fri, 5 Mar 2021 01:11:56 +1000 Subject: [PATCH 299/443] Add test for dumping requests --- tests/Http/HttpClientTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index b407d6fb3f0e..95f08521babb 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -11,6 +11,7 @@ use Illuminate\Support\Str; use OutOfBoundsException; use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\VarDumper; class HttpClientTest extends TestCase { @@ -781,4 +782,23 @@ function (Request $request) { $this->factory->assertSentInOrder($executionOrder); } + + public function testCanDump() + { + $dumped = []; + + VarDumper::setHandler(function ($value) use (&$dumped) { + $dumped[] = $value; + }); + + $this->factory->fake()->dump(1, 2, 3)->withOptions(['delay' => 1000])->get('http://foo.com'); + + $this->assertSame(1, $dumped[0]); + $this->assertSame(2, $dumped[1]); + $this->assertSame(3, $dumped[2]); + $this->assertInstanceOf(Request::class, $dumped[3]); + $this->assertSame(1000, $dumped[4]['delay']); + + VarDumper::setHandler(null); + } } From 6699a47565146cd318a22435f99104d54a90c2c1 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Fri, 5 Mar 2021 01:12:44 +1000 Subject: [PATCH 300/443] Implement dump() and dd() methods --- src/Illuminate/Http/Client/PendingRequest.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 836e8b39fe50..41ad5e983840 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -9,6 +9,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; +use Symfony\Component\VarDumper\VarDumper; class PendingRequest { @@ -452,6 +453,40 @@ public function beforeSending($callback) }); } + /** + * Dump the request. + * + * @return $this + */ + public function dump() + { + $values = func_get_args(); + + return $this->beforeSending(function (Request $request, array $options) use ($values) { + foreach (array_merge($values, [$request, $options]) as $value) { + VarDumper::dump($value); + } + }); + } + + /** + * Dump the request and end the script. + * + * @return $this + */ + public function dd() + { + $values = func_get_args(); + + return $this->beforeSending(function (Request $request, array $options) use ($values) { + foreach (array_merge($values, [$request, $options]) as $value) { + VarDumper::dump($value); + } + + exit(1); + }); + } + /** * Issue a GET request to the given URL. * From b1d76be077a96bc28321e5e289c4f0de324cd0ff Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Fri, 5 Mar 2021 01:13:13 +1000 Subject: [PATCH 301/443] Add docblocks for dumping methods --- src/Illuminate/Http/Client/Factory.php | 2 ++ src/Illuminate/Support/Facades/Http.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 0f182b6a65cb..4db3e1fa98a0 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -32,6 +32,8 @@ * @method \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer') * @method \Illuminate\Http\Client\PendingRequest withoutRedirecting() * @method \Illuminate\Http\Client\PendingRequest withoutVerifying() + * @method \Illuminate\Http\Client\PendingRequest dump() + * @method \Illuminate\Http\Client\PendingRequest dd() * @method \Illuminate\Http\Client\Response delete(string $url, array $data = []) * @method \Illuminate\Http\Client\Response get(string $url, array $query = []) * @method \Illuminate\Http\Client\Response head(string $url, array $query = []) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index c6a26b2108cd..426d574789c5 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -30,6 +30,8 @@ * @method static \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer') * @method static \Illuminate\Http\Client\PendingRequest withoutRedirecting() * @method static \Illuminate\Http\Client\PendingRequest withoutVerifying() + * @method static \Illuminate\Http\Client\PendingRequest dump() + * @method static \Illuminate\Http\Client\PendingRequest dd() * @method static \Illuminate\Http\Client\Response delete(string $url, array $data = []) * @method static \Illuminate\Http\Client\Response get(string $url, array $query = []) * @method static \Illuminate\Http\Client\Response head(string $url, array $query = []) From 26fe23fc6819c20495791e791c97405c38ce4de0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Mar 2021 09:19:57 -0600 Subject: [PATCH 302/443] Revert "Revert "Revert "[8.x] Fix formatWheres in DatabaseRule (#36441)" (#36452)" (#36453)" (#36465) This reverts commit 018314829ccb70ec20a6fc25fa4bd382d09d6cc0. --- src/Illuminate/Validation/Rules/DatabaseRule.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/Rules/DatabaseRule.php b/src/Illuminate/Validation/Rules/DatabaseRule.php index 88b4d27cd941..b8113b2afadb 100644 --- a/src/Illuminate/Validation/Rules/DatabaseRule.php +++ b/src/Illuminate/Validation/Rules/DatabaseRule.php @@ -196,11 +196,7 @@ public function queryCallbacks() protected function formatWheres() { return collect($this->wheres)->map(function ($where) { - if (is_bool($where['value'])) { - return $where['column'].','.($where['value'] ? 'true' : 'false'); - } else { - return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; - } + return $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"'; })->implode(','); } } From 2aa5c2488d25178ebc097052c7897a0e463ddc35 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Mar 2021 09:22:36 -0600 Subject: [PATCH 303/443] version --- 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 1e35f20d4f46..45be0dd0b96e 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.30.1'; + const VERSION = '8.31.0'; /** * The base path for the Laravel installation. From 91bd93f92c26cc58c25849f1a1ac6d7ee6d55411 Mon Sep 17 00:00:00 2001 From: Claudio Dekker <1752195+claudiodekker@users.noreply.github.com> Date: Thu, 4 Mar 2021 17:29:43 +0100 Subject: [PATCH 304/443] Add docblocks & minor cleanup --- src/Illuminate/Testing/Fluent/Assert.php | 58 +++++++++- .../Testing/Fluent/Concerns/Debugging.php | 18 ++++ .../Testing/Fluent/Concerns/Has.php | 100 ++++++++++++++---- .../Testing/Fluent/Concerns/Interaction.php | 28 ++++- .../Testing/Fluent/Concerns/Matching.php | 65 +++++++++--- 5 files changed, 230 insertions(+), 39 deletions(-) diff --git a/src/Illuminate/Testing/Fluent/Assert.php b/src/Illuminate/Testing/Fluent/Assert.php index a5e89e83294c..926ef09656ac 100644 --- a/src/Illuminate/Testing/Fluent/Assert.php +++ b/src/Illuminate/Testing/Fluent/Assert.php @@ -19,19 +19,39 @@ class Assert implements Arrayable Macroable, Tappable; - /** @var array */ + /** + * The properties in the current scope. + * + * @var array + */ private $props; - /** @var string */ + /** + * The "dot" path to the current scope. + * + * @var string|null + */ private $path; + /** + * Create a new Assert instance. + * + * @param array $props + * @param string|null $path + */ protected function __construct(array $props, string $path = null) { $this->path = $path; $this->props = $props; } - protected function dotPath($key): string + /** + * Compose the absolute "dot" path to the given key. + * + * @param string $key + * @return string + */ + protected function dotPath(string $key): string { if (is_null($this->path)) { return $key; @@ -40,12 +60,25 @@ protected function dotPath($key): string return implode('.', [$this->path, $key]); } + /** + * Retrieve a prop within the current scope using "dot" notation. + * + * @param string|null $key + * @return mixed + */ protected function prop(string $key = null) { return Arr::get($this->props, $key); } - protected function scope($key, Closure $callback): self + /** + * Instantiate a new "scope" at the path of the given key. + * + * @param string $key + * @param Closure $callback + * @return $this + */ + protected function scope(string $key, Closure $callback): self { $props = $this->prop($key); $path = $this->dotPath($key); @@ -59,16 +92,33 @@ protected function scope($key, Closure $callback): self return $this; } + /** + * Create a new instance from an array. + * + * @param array $data + * @return static + */ public static function fromArray(array $data): self { return new self($data); } + /** + * Create a new instance from a AssertableJsonString. + * + * @param AssertableJsonString $json + * @return static + */ public static function fromAssertableJsonString(AssertableJsonString $json): self { return self::fromArray($json->json()); } + /** + * Get the instance as an array. + * + * @return array + */ public function toArray() { return $this->props; diff --git a/src/Illuminate/Testing/Fluent/Concerns/Debugging.php b/src/Illuminate/Testing/Fluent/Concerns/Debugging.php index d604f0e0b21d..f51d119074ae 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Debugging.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Debugging.php @@ -4,6 +4,12 @@ trait Debugging { + /** + * Dumps the given props. + * + * @param string|null $prop + * @return $this + */ public function dump(string $prop = null): self { dump($this->prop($prop)); @@ -11,10 +17,22 @@ public function dump(string $prop = null): self return $this; } + /** + * Dumps the given props and exits. + * + * @param string|null $prop + * @return void + */ public function dd(string $prop = null): void { dd($this->prop($prop)); } + /** + * Retrieve a prop within the current scope using "dot" notation. + * + * @param string|null $key + * @return mixed + */ abstract protected function prop(string $key = null); } diff --git a/src/Illuminate/Testing/Fluent/Concerns/Has.php b/src/Illuminate/Testing/Fluent/Concerns/Has.php index 28955a742493..746fa49b60f1 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Has.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -8,7 +8,14 @@ trait Has { - protected function count(string $key, $length): self + /** + * Assert that the prop is of the expected size. + * + * @param string $key + * @param int $length + * @return $this + */ + protected function count(string $key, int $length): self { PHPUnit::assertCount( $length, @@ -19,21 +26,14 @@ protected function count(string $key, $length): self return $this; } - public function hasAll($key): self - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $prop => $count) { - if (is_int($prop)) { - $this->has($count); - } else { - $this->has($prop, $count); - } - } - - return $this; - } - + /** + * Ensure that the given prop exists. + * + * @param string $key + * @param null $value + * @param Closure|null $scope + * @return $this + */ public function has(string $key, $value = null, Closure $scope = null): self { $prop = $this->prop(); @@ -69,6 +69,33 @@ public function has(string $key, $value = null, Closure $scope = null): self return $this; } + /** + * Assert that all of the given props exist. + * + * @param array|string $key + * @return $this + */ + public function hasAll($key): self + { + $keys = is_array($key) ? $key : func_get_args(); + + foreach ($keys as $prop => $count) { + if (is_int($prop)) { + $this->has($count); + } else { + $this->has($prop, $count); + } + } + + return $this; + } + + /** + * Assert that none of the given props exist. + * + * @param array|string $key + * @return $this + */ public function missingAll($key): self { $keys = is_array($key) ? $key : func_get_args(); @@ -80,6 +107,12 @@ public function missingAll($key): self return $this; } + /** + * Assert that the given prop does not exist. + * + * @param string $key + * @return $this + */ public function missing(string $key): self { PHPUnit::assertNotTrue( @@ -90,11 +123,36 @@ public function missing(string $key): self return $this; } - abstract protected function prop(string $key = null); - - abstract protected function dotPath($key): string; - + /** + * Compose the absolute "dot" path to the given key. + * + * @param string $key + * @return string + */ + abstract protected function dotPath(string $key): string; + + /** + * Marks the property as interacted. + * + * @param string $key + * @return void + */ abstract protected function interactsWith(string $key): void; - abstract protected function scope($key, Closure $callback); + /** + * Retrieve a prop within the current scope using "dot" notation. + * + * @param string|null $key + * @return mixed + */ + abstract protected function prop(string $key = null); + + /** + * Instantiate a new "scope" at the path of the given key. + * + * @param string $key + * @param Closure $callback + * @return $this + */ + abstract protected function scope(string $key, Closure $callback); } diff --git a/src/Illuminate/Testing/Fluent/Concerns/Interaction.php b/src/Illuminate/Testing/Fluent/Concerns/Interaction.php index d938438a618c..15e7e9508f55 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Interaction.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Interaction.php @@ -7,9 +7,19 @@ trait Interaction { - /** @var array */ + /** + * The list of interacted properties. + * + * @var array + */ protected $interacted = []; + /** + * Marks the property as interacted. + * + * @param string $key + * @return void + */ protected function interactsWith(string $key): void { $prop = Str::before($key, '.'); @@ -19,6 +29,11 @@ protected function interactsWith(string $key): void } } + /** + * Asserts that all properties have been interacted with. + * + * @return void + */ public function interacted(): void { PHPUnit::assertSame( @@ -30,6 +45,11 @@ public function interacted(): void ); } + /** + * Disables the interaction check. + * + * @return $this + */ public function etc(): self { $this->interacted = array_keys($this->prop()); @@ -37,5 +57,11 @@ public function etc(): self return $this; } + /** + * Retrieve a prop within the current scope using "dot" notation. + * + * @param string|null $key + * @return mixed + */ abstract protected function prop(string $key = null); } diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php index 3edce127d362..052b2d49ab2f 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -9,16 +9,14 @@ trait Matching { - public function whereAll(array $bindings): self - { - foreach ($bindings as $key => $value) { - $this->where($key, $value); - } - - return $this; - } - - public function where($key, $expected): self + /** + * Asserts that the property matches the expected value. + * + * @param string $key + * @param mixed|callable $expected + * @return $this + */ + public function where(string $key, $expected): self { $this->has($key); @@ -49,6 +47,27 @@ public function where($key, $expected): self return $this; } + /** + * Asserts that all properties match their expected values. + * + * @param array $bindings + * @return $this + */ + public function whereAll(array $bindings): self + { + foreach ($bindings as $key => $value) { + $this->where($key, $value); + } + + return $this; + } + + /** + * Ensures that all properties are sorted the same way, recursively. + * + * @param mixed $value + * @return void + */ protected function ensureSorted(&$value): void { if (! is_array($value)) { @@ -62,9 +81,29 @@ protected function ensureSorted(&$value): void ksort($value); } - abstract protected function dotPath($key): string; + /** + * Compose the absolute "dot" path to the given key. + * + * @param string $key + * @return string + */ + abstract protected function dotPath(string $key): string; + + /** + * Ensure that the given prop exists. + * + * @param string $key + * @param null $value + * @param Closure|null $scope + * @return $this + */ + abstract public function has(string $key, $value = null, Closure $scope = null); + /** + * Retrieve a prop within the current scope using "dot" notation. + * + * @param string|null $key + * @return mixed + */ abstract protected function prop(string $key = null); - - abstract public function has(string $key, $value = null, Closure $scope = null); } From c5eadc4d9de5a2597dc0c4b64f0d009e287c25a6 Mon Sep 17 00:00:00 2001 From: Claudio Dekker <1752195+claudiodekker@users.noreply.github.com> Date: Thu, 4 Mar 2021 18:11:49 +0100 Subject: [PATCH 305/443] Use FQN in DocBlocks --- src/Illuminate/Testing/Fluent/Assert.php | 4 ++-- src/Illuminate/Testing/Fluent/Concerns/Has.php | 4 ++-- src/Illuminate/Testing/Fluent/Concerns/Matching.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Testing/Fluent/Assert.php b/src/Illuminate/Testing/Fluent/Assert.php index 926ef09656ac..bde937a0bf23 100644 --- a/src/Illuminate/Testing/Fluent/Assert.php +++ b/src/Illuminate/Testing/Fluent/Assert.php @@ -75,7 +75,7 @@ protected function prop(string $key = null) * Instantiate a new "scope" at the path of the given key. * * @param string $key - * @param Closure $callback + * @param \Closure $callback * @return $this */ protected function scope(string $key, Closure $callback): self @@ -106,7 +106,7 @@ public static function fromArray(array $data): self /** * Create a new instance from a AssertableJsonString. * - * @param AssertableJsonString $json + * @param \Illuminate\Testing\AssertableJsonString $json * @return static */ public static function fromAssertableJsonString(AssertableJsonString $json): self diff --git a/src/Illuminate/Testing/Fluent/Concerns/Has.php b/src/Illuminate/Testing/Fluent/Concerns/Has.php index 746fa49b60f1..19b9ad9915ca 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Has.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -31,7 +31,7 @@ protected function count(string $key, int $length): self * * @param string $key * @param null $value - * @param Closure|null $scope + * @param \Closure|null $scope * @return $this */ public function has(string $key, $value = null, Closure $scope = null): self @@ -151,7 +151,7 @@ abstract protected function prop(string $key = null); * Instantiate a new "scope" at the path of the given key. * * @param string $key - * @param Closure $callback + * @param \Closure $callback * @return $this */ abstract protected function scope(string $key, Closure $callback); diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php index 052b2d49ab2f..3cf1f82c471c 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -13,7 +13,7 @@ trait Matching * Asserts that the property matches the expected value. * * @param string $key - * @param mixed|callable $expected + * @param mixed|\Closure $expected * @return $this */ public function where(string $key, $expected): self @@ -94,7 +94,7 @@ abstract protected function dotPath(string $key): string; * * @param string $key * @param null $value - * @param Closure|null $scope + * @param \Closure|null $scope * @return $this */ abstract public function has(string $key, $value = null, Closure $scope = null); From 0ddc7ab7e94003be1eec3080fce6aea3382912e6 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 5 Mar 2021 03:06:47 +0530 Subject: [PATCH 306/443] Add circuit breaker job middleware --- .../Queue/Middleware/CircuitBreaker.php | 129 ++++++++++++++++ .../Integration/Queue/CircuitBreakerTest.php | 144 ++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 src/Illuminate/Queue/Middleware/CircuitBreaker.php create mode 100644 tests/Integration/Queue/CircuitBreakerTest.php diff --git a/src/Illuminate/Queue/Middleware/CircuitBreaker.php b/src/Illuminate/Queue/Middleware/CircuitBreaker.php new file mode 100644 index 000000000000..eb764a957561 --- /dev/null +++ b/src/Illuminate/Queue/Middleware/CircuitBreaker.php @@ -0,0 +1,129 @@ +maxAttempts = $maxAttempts; + $this->decayMinutes = $decayMinutes; + $this->retryAfterMinutes = $retryAfterMinutes; + $this->key = $key; + } + + /** + * Process the job. + * + * @param mixed $job + * @param callable $next + * @return mixed + */ + public function handle($job, $next) + { + $this->limiter = Container::getInstance()->make(RateLimiter::class); + + if ($this->limiter->tooManyAttempts($jobKey = $this->getKey($job), $this->maxAttempts)) { + return $job->release($this->getTimeUntilNextRetry($jobKey)); + } + + try { + $next($job); + + $this->limiter->clear($jobKey); + } catch (Throwable $throwable) { + $this->limiter->hit($jobKey, $this->decayMinutes * 60); + + return $job->release($this->retryAfterMinutes * 60); + } + } + + /** + * Set the prefix of the rate limiter key. + * + * @param string $prefix + * @return $this + */ + public function withPrefix(string $prefix) + { + $this->prefix = $prefix; + + return $this; + } + + /** + * Get the number of seconds that should elapse before the job is retried. + * + * @param string $key + * @return int + */ + protected function getTimeUntilNextRetry($key) + { + return $this->limiter->availableIn($key) + 3; + } + + /** + * Get the cache key associated for the rate limiter. + * + * @param mixed $job + * @return string + */ + protected function getKey($job) + { + return md5($this->prefix.(empty($this->key) ? get_class($job) : $this->key)); + } +} diff --git a/tests/Integration/Queue/CircuitBreakerTest.php b/tests/Integration/Queue/CircuitBreakerTest.php new file mode 100644 index 000000000000..977a00a76c0f --- /dev/null +++ b/tests/Integration/Queue/CircuitBreakerTest.php @@ -0,0 +1,144 @@ +assertJobWasReleasedImmediately(CircuitBreakerTestJob::class); + $this->assertJobWasReleasedImmediately(CircuitBreakerTestJob::class); + $this->assertJobWasReleasedWithDelay(CircuitBreakerTestJob::class); + } + + public function testCircuitStaysClosedForSuccessfulJobs() + { + $this->assertJobRanSuccessfully(CircuitBreakerSuccessfulJob::class); + $this->assertJobRanSuccessfully(CircuitBreakerSuccessfulJob::class); + $this->assertJobRanSuccessfully(CircuitBreakerSuccessfulJob::class); + } + + public function testCircuitResetsAfterSuccess() + { + $this->assertJobWasReleasedImmediately(CircuitBreakerTestJob::class); + $this->assertJobRanSuccessfully(CircuitBreakerSuccessfulJob::class); + $this->assertJobWasReleasedImmediately(CircuitBreakerTestJob::class); + $this->assertJobWasReleasedImmediately(CircuitBreakerTestJob::class); + $this->assertJobWasReleasedWithDelay(CircuitBreakerTestJob::class); + } + + protected function assertJobWasReleasedImmediately($class) + { + $class::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + + $job->shouldReceive('hasFailed')->once()->andReturn(false); + $job->shouldReceive('release')->with(0)->once(); + $job->shouldReceive('isReleased')->andReturn(true); + $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(true); + + $instance->call($job, [ + 'command' => serialize($command = new $class), + ]); + + $this->assertTrue($class::$handled); + } + + protected function assertJobWasReleasedWithDelay($class) + { + $class::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + + $job->shouldReceive('hasFailed')->once()->andReturn(false); + $job->shouldReceive('release')->withArgs(function ($delay) { + return $delay >= 600; + })->once(); + $job->shouldReceive('isReleased')->andReturn(true); + $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(true); + + $instance->call($job, [ + 'command' => serialize($command = new $class), + ]); + + $this->assertFalse($class::$handled); + } + + protected function assertJobRanSuccessfully($class) + { + $class::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + + $job->shouldReceive('hasFailed')->once()->andReturn(false); + $job->shouldReceive('isReleased')->andReturn(false); + $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(false); + $job->shouldReceive('delete')->once(); + + $instance->call($job, [ + 'command' => serialize($command = new $class), + ]); + + $this->assertTrue($class::$handled); + } +} + +class CircuitBreakerTestJob +{ + use InteractsWithQueue, Queueable; + + public static $handled = false; + + public function handle() + { + static::$handled = true; + + throw new Exception; + } + + public function middleware() + { + return [new CircuitBreaker(2, 10, 0, 'test')]; + } +} + +class CircuitBreakerSuccessfulJob +{ + use InteractsWithQueue, Queueable; + + public static $handled = false; + + public function handle() + { + static::$handled = true; + } + + public function middleware() + { + return [new CircuitBreaker(2, 10, 0, 'test')]; + } +} From 18daf4619de068cf106ef49c947087d2b655d67c Mon Sep 17 00:00:00 2001 From: Pat Gagnon-Renaud Date: Fri, 5 Mar 2021 09:40:56 -0500 Subject: [PATCH 307/443] Delete existing links that are broken (#36470) When a link exists but is broken, `file_exists($link)` return false. And when `symlink($link, $target)` is called on a broken link, a PHP Warning is returned and the link is not updated. To fix this, we add an additional check using `is_link($link)` (which return true, even if the link is broken) to detect and delete broken links. --- src/Illuminate/Foundation/Console/StorageLinkCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Foundation/Console/StorageLinkCommand.php b/src/Illuminate/Foundation/Console/StorageLinkCommand.php index 11e5c148c1ce..82b461598338 100644 --- a/src/Illuminate/Foundation/Console/StorageLinkCommand.php +++ b/src/Illuminate/Foundation/Console/StorageLinkCommand.php @@ -31,6 +31,10 @@ public function handle() return $this->error('The "public/storage" directory already exists.'); } + if (is_link(public_path('storage'))) { + $this->laravel->make('files')->delete(public_path('storage')); + } + $this->laravel->make('files')->link( storage_path('app/public'), public_path('storage') ); From 1e19a5668751f3a19b65d551e9253dd8f46a3c48 Mon Sep 17 00:00:00 2001 From: Pat Gagnon-Renaud Date: Fri, 5 Mar 2021 09:41:10 -0500 Subject: [PATCH 308/443] Delete existing links that are broken (#36469) When a link exists but is broken, `file_exists($link)` return false. And when `symlink($link, $target)` is called on a broken link, a PHP Warning is returned and the link is not updated. To fix this, we add an additional check using `is_link($link)` (which return true, even if the link is broken) to detect and delete broken links. --- src/Illuminate/Foundation/Console/StorageLinkCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Foundation/Console/StorageLinkCommand.php b/src/Illuminate/Foundation/Console/StorageLinkCommand.php index a0419bf6c077..0d47ddae7294 100644 --- a/src/Illuminate/Foundation/Console/StorageLinkCommand.php +++ b/src/Illuminate/Foundation/Console/StorageLinkCommand.php @@ -35,6 +35,10 @@ public function handle() continue; } + if (is_link($link)) { + $this->laravel->make('files')->delete($link); + } + if ($relative) { $this->laravel->make('files')->relativeLink($target, $link); } else { From 10f1a935205340ba8954e7075c1d9b67943db27d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 5 Mar 2021 09:17:09 -0600 Subject: [PATCH 309/443] formatting --- src/Illuminate/Cache/PhpRedisLock.php | 57 ++++++++++++++++++--------- src/Illuminate/Cache/RedisStore.php | 1 + 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Cache/PhpRedisLock.php b/src/Illuminate/Cache/PhpRedisLock.php index 8d0670a167fd..f315ae64acb2 100644 --- a/src/Illuminate/Cache/PhpRedisLock.php +++ b/src/Illuminate/Cache/PhpRedisLock.php @@ -8,6 +8,15 @@ class PhpRedisLock extends RedisLock { + /** + * Create a new phpredis lock instance. + * + * @param \Illuminate\Redis\Connections\PhpRedisConnection $redis + * @param string $name + * @param int $seconds + * @param string|null $owner + * @return void + */ public function __construct(PhpRedisConnection $redis, string $name, int $seconds, ?string $owner = null) { parent::__construct($redis, $name, $seconds, $owner); @@ -26,26 +35,18 @@ public function release() ); } + /** + * Get the owner key, serialized and compressed. + * + * @return string + */ protected function serializedAndCompressedOwner(): string { $client = $this->redis->client(); - /* If a serialization mode such as "php" or "igbinary" and/or a - * compression mode such as "lzf" or "zstd" is enabled, the owner - * must be serialized and/or compressed by us, because phpredis does - * not do this for the eval command. - * - * Name must not be modified! - */ $owner = $client->_serialize($this->owner); - /* Once the phpredis extension exposes a compress function like the - * above `_serialize()` function, we should switch to it to guarantee - * consistency in the way the extension serializes and compresses to - * avoid the need to check each compression option ourselves. - * - * @see https://github.com/phpredis/phpredis/issues/1938 - */ + // https://github.com/phpredis/phpredis/issues/1938 if ($this->compressed()) { if ($this->lzfCompressed()) { $owner = \lzf_compress($owner); @@ -55,7 +56,7 @@ protected function serializedAndCompressedOwner(): string $owner = \lz4_compress($owner, $client->getOption(Redis::OPT_COMPRESSION_LEVEL)); } else { throw new UnexpectedValueException(sprintf( - 'Unknown phpredis compression in use (%d). Unable to release lock.', + 'Unknown phpredis compression in use [%d]. Unable to release lock.', $client->getOption(Redis::OPT_COMPRESSION) )); } @@ -64,26 +65,46 @@ protected function serializedAndCompressedOwner(): string return $owner; } + /** + * Determine if compression is enabled. + * + * @return bool + */ protected function compressed(): bool { return $this->redis->client()->getOption(Redis::OPT_COMPRESSION) !== Redis::COMPRESSION_NONE; } + /** + * Determine if LZF compression is enabled. + * + * @return bool + */ protected function lzfCompressed(): bool { return defined('Redis::COMPRESSION_LZF') && - $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_LZF; + $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_LZF; } + /** + * Determine if ZSTD compression is enabled. + * + * @return bool + */ protected function zstdCompressed(): bool { return defined('Redis::COMPRESSION_ZSTD') && - $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_ZSTD; + $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_ZSTD; } + /** + * Determine if LZ4 compression is enabled. + * + * @return bool + */ protected function lz4Compressed(): bool { return defined('Redis::COMPRESSION_LZ4') && - $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_LZ4; + $this->redis->client()->getOption(Redis::OPT_COMPRESSION) === Redis::COMPRESSION_LZ4; } } diff --git a/src/Illuminate/Cache/RedisStore.php b/src/Illuminate/Cache/RedisStore.php index e698bab375d4..4896c9183d03 100755 --- a/src/Illuminate/Cache/RedisStore.php +++ b/src/Illuminate/Cache/RedisStore.php @@ -190,6 +190,7 @@ public function forever($key, $value) public function lock($name, $seconds = 0, $owner = null) { $lockName = $this->prefix.$name; + $lockConnection = $this->lockConnection(); if ($lockConnection instanceof PhpRedisConnection) { From d7a4280423518939eeefce1f75f84b6e6bf03ad3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 5 Mar 2021 09:17:42 -0600 Subject: [PATCH 310/443] Apply fixes from StyleCI (#36477) --- src/Illuminate/Cache/PhpRedisLock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/PhpRedisLock.php b/src/Illuminate/Cache/PhpRedisLock.php index f315ae64acb2..9d0215f37d6d 100644 --- a/src/Illuminate/Cache/PhpRedisLock.php +++ b/src/Illuminate/Cache/PhpRedisLock.php @@ -46,7 +46,7 @@ protected function serializedAndCompressedOwner(): string $owner = $client->_serialize($this->owner); - // https://github.com/phpredis/phpredis/issues/1938 + // https://github.com/phpredis/phpredis/issues/1938 if ($this->compressed()) { if ($this->lzfCompressed()) { $owner = \lzf_compress($owner); From d2106e6c55a8facc55aed654ffe14ebb1c8b14fa Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 5 Mar 2021 09:22:09 -0600 Subject: [PATCH 311/443] formatting --- 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 41ad5e983840..5801bc0b70f0 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -454,7 +454,7 @@ public function beforeSending($callback) } /** - * Dump the request. + * Dump the request before sending. * * @return $this */ @@ -470,7 +470,7 @@ public function dump() } /** - * Dump the request and end the script. + * Dump the request before sending and end the script. * * @return $this */ From 883713b084fab51f972503395b14f662297cbab4 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij Date: Fri, 5 Mar 2021 22:13:45 +0100 Subject: [PATCH 312/443] Use user defined url for AwsTemporaryUrl method --- .../Filesystem/FilesystemAdapter.php | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 896bfbd6f35a..f671c85a6a9c 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -23,6 +23,7 @@ use League\Flysystem\Sftp\SftpAdapter as Sftp; use PHPUnit\Framework\Assert as PHPUnit; use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriInterface; use RuntimeException; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -593,9 +594,18 @@ public function getAwsTemporaryUrl($adapter, $path, $expiration, $options) 'Key' => $adapter->getPathPrefix().$path, ], $options)); - return (string) $client->createPresignedRequest( + $uri = $client->createPresignedRequest( $command, $expiration )->getUri(); + + // If an explicit base URL has been set on the disk configuration then we will use + // it as the base URL instead of the default path. This allows the developer to + // have full control over the base path for this filesystem's generated URLs. + if (! is_null($url = $this->driver->getConfig()->get('url'))) { + $uri = $this->replaceBaseUrl($uri, $url); + } + + return (string) $uri; } /** @@ -610,6 +620,20 @@ protected function concatPathToUrl($url, $path) return rtrim($url, '/').'/'.ltrim($path, '/'); } + /** + * Replace base parts of UriInterface by values from URL. + * + * @param UriInterface $uri + * @param string $url + * @return UriInterface + */ + protected function replaceBaseUrl($uri, $url) + { + $parsed_url = parse_url($url); + + return $uri->withScheme($parsed_url['scheme'])->withHost($parsed_url['host']); + } + /** * Get an array of all files in a directory. * From 21fee7649e1b48a7701b8ba860218741c2c3bcef Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 5 Mar 2021 17:04:38 -0600 Subject: [PATCH 313/443] rename class --- ...uitBreaker.php => ThrottlesExceptions.php} | 48 ++++++++++++++----- ...erTest.php => ThrottlesExceptionsTest.php} | 8 ++-- 2 files changed, 40 insertions(+), 16 deletions(-) rename src/Illuminate/Queue/Middleware/{CircuitBreaker.php => ThrottlesExceptions.php} (78%) rename tests/Integration/Queue/{CircuitBreakerTest.php => ThrottlesExceptionsTest.php} (94%) diff --git a/src/Illuminate/Queue/Middleware/CircuitBreaker.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php similarity index 78% rename from src/Illuminate/Queue/Middleware/CircuitBreaker.php rename to src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index eb764a957561..edb3dd164d33 100644 --- a/src/Illuminate/Queue/Middleware/CircuitBreaker.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -6,10 +6,10 @@ use Illuminate\Container\Container; use Throwable; -class CircuitBreaker +class ThrottlesExceptions { /** - * The maximum number of attempts allowed before the circuit is opened. + * The maximum number of attempts allowed before rate limiting applies. * * @var int */ @@ -36,6 +36,13 @@ class CircuitBreaker */ protected $key; + /** + * The callback that determines if rate limiting should apply. + * + * @var callable + */ + protected $whenCallback; + /** * The prefix of the rate limiter key. * @@ -86,6 +93,10 @@ public function handle($job, $next) $this->limiter->clear($jobKey); } catch (Throwable $throwable) { + if ($this->whenCallback && ! call_user_func($this->whenCallback, $throwable)) { + throw $throwable; + } + $this->limiter->hit($jobKey, $this->decayMinutes * 60); return $job->release($this->retryAfterMinutes * 60); @@ -93,27 +104,29 @@ public function handle($job, $next) } /** - * Set the prefix of the rate limiter key. + * Specify a callback that should determine if rate limiting behavior should apply. * - * @param string $prefix + * @param callable $callback * @return $this */ - public function withPrefix(string $prefix) + public function when(callable $callback) { - $this->prefix = $prefix; + $this->whenCallback = $callback; return $this; } /** - * Get the number of seconds that should elapse before the job is retried. + * Set the prefix of the rate limiter key. * - * @param string $key - * @return int + * @param string $prefix + * @return $this */ - protected function getTimeUntilNextRetry($key) + public function withPrefix(string $prefix) { - return $this->limiter->availableIn($key) + 3; + $this->prefix = $prefix; + + return $this; } /** @@ -124,6 +137,17 @@ protected function getTimeUntilNextRetry($key) */ protected function getKey($job) { - return md5($this->prefix.(empty($this->key) ? get_class($job) : $this->key)); + return $this->prefix.md5(empty($this->key) ? get_class($job) : $this->key); + } + + /** + * Get the number of seconds that should elapse before the job is retried. + * + * @param string $key + * @return int + */ + protected function getTimeUntilNextRetry($key) + { + return $this->limiter->availableIn($key) + 3; } } diff --git a/tests/Integration/Queue/CircuitBreakerTest.php b/tests/Integration/Queue/ThrottlesExceptionsTest.php similarity index 94% rename from tests/Integration/Queue/CircuitBreakerTest.php rename to tests/Integration/Queue/ThrottlesExceptionsTest.php index 977a00a76c0f..b51190e41654 100644 --- a/tests/Integration/Queue/CircuitBreakerTest.php +++ b/tests/Integration/Queue/ThrottlesExceptionsTest.php @@ -8,14 +8,14 @@ use Illuminate\Contracts\Queue\Job; use Illuminate\Queue\CallQueuedHandler; use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\Middleware\CircuitBreaker; +use Illuminate\Queue\Middleware\ThrottlesExceptions; use Mockery as m; use Orchestra\Testbench\TestCase; /** * @group integration */ -class CircuitBreakerTest extends TestCase +class ThrottlesExceptionsTest extends TestCase { protected function tearDown(): void { @@ -122,7 +122,7 @@ public function handle() public function middleware() { - return [new CircuitBreaker(2, 10, 0, 'test')]; + return [new ThrottlesExceptions(2, 10, 0, 'test')]; } } @@ -139,6 +139,6 @@ public function handle() public function middleware() { - return [new CircuitBreaker(2, 10, 0, 'test')]; + return [new ThrottlesExceptions(2, 10, 0, 'test')]; } } From c5fa6935c731405f9e4edd531203ce094ea43e65 Mon Sep 17 00:00:00 2001 From: Oisin O'Neill Date: Sun, 7 Mar 2021 20:26:06 +0000 Subject: [PATCH 314/443] [6.x] Update changelog for v6.18.27 with upgrade info around cookies (#36490) * Update changelog for v6.18.27 with upgrade info around cookies After this this change any existing cookies will be invalid (which may have implications for some apps) * Update CHANGELOG-6.x.md * Update CHANGELOG-6.x.md Co-authored-by: Taylor Otwell --- CHANGELOG-6.x.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 5fd976698b85..860012f0bd0a 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -259,6 +259,8 @@ ### Changed - Improve cookie encryption ([#33662](https://github.com/laravel/framework/pull/33662)) +This change will invalidate all existing cookies. Please see [this security bulletin](https://blog.laravel.com/laravel-cookie-security-releases) for more information. + ## [v6.18.26 (2020-07-21)](https://github.com/laravel/framework/compare/v6.18.25...v6.18.26) From 466000e4b547d8e18065bcd47c7234745d3988e7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 7 Mar 2021 16:39:47 -0600 Subject: [PATCH 315/443] formatting --- src/Illuminate/Filesystem/FilesystemAdapter.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index f671c85a6a9c..5d6de6ed3321 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -621,17 +621,17 @@ protected function concatPathToUrl($url, $path) } /** - * Replace base parts of UriInterface by values from URL. + * Replace the scheme and host of the given UriInterface with values from the given URL. * - * @param UriInterface $uri + * @param \Psr\Http\Message\UriInterface $uri * @param string $url - * @return UriInterface + * @return \Psr\Http\Message\UriInterface */ protected function replaceBaseUrl($uri, $url) { - $parsed_url = parse_url($url); + $parsed = parse_url($url); - return $uri->withScheme($parsed_url['scheme'])->withHost($parsed_url['host']); + return $uri->withScheme($parsed['scheme'])->withHost($parsed['host']); } /** From f1b17a28d54c8c8446fc0c71f6c26a9223ad9fd2 Mon Sep 17 00:00:00 2001 From: Victor Dauchy <26772554+vdauchy@users.noreply.github.com> Date: Mon, 8 Mar 2021 08:46:59 -0500 Subject: [PATCH 316/443] Add support to Eloquent Collection on Model::destroy() (#36497) --- src/Illuminate/Database/Eloquent/Model.php | 5 +++++ tests/Database/DatabaseEloquentModelTest.php | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 575148909050..62fcd058e258 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -10,6 +10,7 @@ use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Database\ConnectionResolverInterface as Resolver; +use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; use Illuminate\Database\Eloquent\Relations\HasManyThrough; @@ -1061,6 +1062,10 @@ protected function insertAndSetId(Builder $query, $attributes) */ public static function destroy($ids) { + if ($ids instanceof EloquentCollection) { + $ids = $ids->modelKeys(); + } + if ($ids instanceof BaseCollection) { $ids = $ids->all(); } diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 42f3b6563927..b5049151adab 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -290,7 +290,16 @@ public function testDestroyMethodCallsQueryBuilderCorrectly() public function testDestroyMethodCallsQueryBuilderCorrectlyWithCollection() { - EloquentModelDestroyStub::destroy(new Collection([1, 2, 3])); + EloquentModelDestroyStub::destroy(new BaseCollection([1, 2, 3])); + } + + public function testDestroyMethodCallsQueryBuilderCorrectlyWithEloquentCollection() + { + EloquentModelDestroyStub::destroy(new Collection([ + new EloquentModelDestroyStub(['id' => 1]), + new EloquentModelDestroyStub(['id' => 2]), + new EloquentModelDestroyStub(['id' => 3]), + ])); } public function testDestroyMethodCallsQueryBuilderCorrectlyWithMultipleArgs() @@ -2383,6 +2392,10 @@ public function newQuery() class EloquentModelDestroyStub extends Model { + protected $fillable = [ + 'id', + ]; + public function newQuery() { $mock = m::mock(Builder::class); From 3f5af8d446564e685207c3296567d8b52dc2be51 Mon Sep 17 00:00:00 2001 From: Jess Archer Date: Mon, 8 Mar 2021 23:53:00 +1000 Subject: [PATCH 317/443] [6.x] Fix validator treating null as true for (required|exclude)_(if|unless) due to loose in_array() check (#36504) * Fix required_if treating true as null * Fix required_unless treating true as null * Fix exclude_if treating true as null * Fix exclude_unless treating true as null --- .../Concerns/ValidatesAttributes.php | 8 +-- tests/Validation/ValidationValidatorTest.php | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 84e0964ba147..13fe1a648108 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1422,7 +1422,7 @@ public function validateRequiredIf($attribute, $value, $parameters) [$values, $other] = $this->prepareValuesAndOther($parameters); - if (in_array($other, $values)) { + if (in_array($other, $values, is_bool($other))) { return $this->validateRequired($attribute, $value); } @@ -1443,7 +1443,7 @@ public function validateExcludeIf($attribute, $value, $parameters) [$values, $other] = $this->prepareValuesAndOther($parameters); - return ! in_array($other, $values); + return ! in_array($other, $values, is_bool($other)); } /** @@ -1460,7 +1460,7 @@ public function validateExcludeUnless($attribute, $value, $parameters) [$values, $other] = $this->prepareValuesAndOther($parameters); - return in_array($other, $values); + return in_array($other, $values, is_bool($other)); } /** @@ -1515,7 +1515,7 @@ public function validateRequiredUnless($attribute, $value, $parameters) [$values, $other] = $this->prepareValuesAndOther($parameters); - if (! in_array($other, $values)) { + if (! in_array($other, $values, is_bool($other))) { return $this->validateRequired($attribute, $value); } diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index a176ce42a055..4ac71213c984 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1056,10 +1056,34 @@ public function testRequiredIf() $v = new Validator($trans, ['foo' => true], ['bar' => 'required_if:foo,false']); $this->assertTrue($v->passes()); + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => true], ['bar' => 'required_if:foo,null']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => 0], ['bar' => 'required_if:foo,0']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => '0'], ['bar' => 'required_if:foo,0']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => 1], ['bar' => 'required_if:foo,1']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => '1'], ['bar' => 'required_if:foo,1']); + $this->assertTrue($v->fails()); + $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['foo' => true], ['bar' => 'required_if:foo,true']); $this->assertTrue($v->fails()); + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => false], ['bar' => 'required_if:foo,false']); + $this->assertTrue($v->fails()); + // error message when passed multiple values (required_if:foo,bar,baz) $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.required_if' => 'The :attribute field is required when :other is :value.'], 'en'); @@ -1098,6 +1122,26 @@ public function testRequiredUnless() $v = new Validator($trans, ['foo' => false], ['bar' => 'required_unless:foo,true']); $this->assertTrue($v->fails()); + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => true], ['bar' => 'required_unless:foo,null']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => '0'], ['bar' => 'required_unless:foo,0']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => 0], ['bar' => 'required_unless:foo,0']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => '1'], ['bar' => 'required_unless:foo,1']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => 1], ['bar' => 'required_unless:foo,1']); + $this->assertTrue($v->passes()); + // error message when passed multiple values (required_unless:foo,bar,baz) $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.required_unless' => 'The :attribute field is required unless :other is in :values.'], 'en'); @@ -5074,6 +5118,20 @@ public function providesPassingExcludeIfData() 'has_appointment' => false, ], ], + [ + [ + 'has_appointment' => ['nullable', 'bool'], + 'appointment_date' => ['exclude_if:has_appointment,null', 'required', 'date'], + ], + [ + 'has_appointment' => true, + 'appointment_date' => '2021-03-08', + ], + [ + 'has_appointment' => true, + 'appointment_date' => '2021-03-08', + ], + ], [ [ 'has_appointment' => ['required', 'bool'], @@ -5408,6 +5466,14 @@ public function testExcludeUnless() ); $this->assertTrue($validator->fails()); $this->assertSame(['mouse' => ['validation.required']], $validator->messages()->toArray()); + + $validator = new Validator( + $this->getIlluminateArrayTranslator(), + ['foo' => true, 'bar' => 'baz'], + ['foo' => 'nullable', 'bar' => 'exclude_unless:foo,null'] + ); + $this->assertTrue($validator->passes()); + $this->assertSame(['foo' => true], $validator->validated()); } public function testExcludeValuesAreReallyRemoved() From 92a1ce8a4dfaaaa9a7cf2335377cb2a2c037170f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 8 Mar 2021 08:01:48 -0600 Subject: [PATCH 318/443] rename method --- .../Validation/Concerns/ValidatesAttributes.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 46fcc8441a17..bba094dd61f6 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1425,7 +1425,7 @@ public function validateRequiredIf($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'required_if'); - [$values, $other] = $this->prepareValuesAndOther($parameters); + [$values, $other] = $this->parseDependentRuleParameters($parameters); if (in_array($other, $values)) { return $this->validateRequired($attribute, $value); @@ -1446,7 +1446,7 @@ public function validateExcludeIf($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'exclude_if'); - [$values, $other] = $this->prepareValuesAndOther($parameters); + [$values, $other] = $this->parseDependentRuleParameters($parameters); return ! in_array($other, $values); } @@ -1463,7 +1463,7 @@ public function validateExcludeUnless($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'exclude_unless'); - [$values, $other] = $this->prepareValuesAndOther($parameters); + [$values, $other] = $this->parseDependentRuleParameters($parameters); return in_array($other, $values); } @@ -1493,7 +1493,7 @@ public function validateExcludeWithout($attribute, $value, $parameters) * @param array $parameters * @return array */ - protected function prepareValuesAndOther($parameters) + public function parseDependentRuleParameters($parameters) { $other = Arr::get($this->data, $parameters[0]); @@ -1552,7 +1552,7 @@ public function validateRequiredUnless($attribute, $value, $parameters) { $this->requireParameterCount(2, $parameters, 'required_unless'); - [$values, $other] = $this->prepareValuesAndOther($parameters); + [$values, $other] = $this->parseDependentRuleParameters($parameters); if (! in_array($other, $values)) { return $this->validateRequired($attribute, $value); From a5d9b455af1dc91bf73aee95147029fd8b540f78 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Mon, 8 Mar 2021 17:22:22 +0000 Subject: [PATCH 319/443] [8.x] Support value callback arguments (#36506) * test * feature: support value function callback arguments --- src/Illuminate/Collections/helpers.php | 4 ++-- tests/Support/SupportHelpersTest.php | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Collections/helpers.php b/src/Illuminate/Collections/helpers.php index 6ae6dfe68a9b..67669e5ce1c6 100644 --- a/src/Illuminate/Collections/helpers.php +++ b/src/Illuminate/Collections/helpers.php @@ -179,8 +179,8 @@ function last($array) * @param mixed $value * @return mixed */ - function value($value) + function value($value, ...$args) { - return $value instanceof Closure ? $value() : $value; + return $value instanceof Closure ? $value(...$args) : $value; } } diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index af7de6b40f56..c286809fbe23 100755 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -40,6 +40,9 @@ public function testValue() $this->assertSame('foo', value(function () { return 'foo'; })); + $this->assertSame('foo', value(function ($arg) { + return $arg; + }, 'foo')); } public function testObjectGet() From 84f10d707df3c9a0517b5561bcbc60ccc912aee0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 8 Mar 2021 11:49:04 -0600 Subject: [PATCH 320/443] formatting --- .../Fluent/{Assert.php => AssertableJson.php} | 5 +- .../Testing/Fluent/Concerns/Has.php | 6 +- src/Illuminate/Testing/TestResponse.php | 4 +- tests/Testing/Fluent/AssertTest.php | 118 +++++++++--------- tests/Testing/TestResponseTest.php | 5 +- 5 files changed, 71 insertions(+), 67 deletions(-) rename src/Illuminate/Testing/Fluent/{Assert.php => AssertableJson.php} (95%) diff --git a/src/Illuminate/Testing/Fluent/Assert.php b/src/Illuminate/Testing/Fluent/AssertableJson.php similarity index 95% rename from src/Illuminate/Testing/Fluent/Assert.php rename to src/Illuminate/Testing/Fluent/AssertableJson.php index bde937a0bf23..07104e114990 100644 --- a/src/Illuminate/Testing/Fluent/Assert.php +++ b/src/Illuminate/Testing/Fluent/AssertableJson.php @@ -10,7 +10,7 @@ use Illuminate\Testing\AssertableJsonString; use PHPUnit\Framework\Assert as PHPUnit; -class Assert implements Arrayable +class AssertableJson implements Arrayable { use Concerns\Has, Concerns\Matching, @@ -34,10 +34,11 @@ class Assert implements Arrayable private $path; /** - * Create a new Assert instance. + * Create a new fluent, assertable JSON data instance. * * @param array $props * @param string|null $path + * @return void */ protected function __construct(array $props, string $path = null) { diff --git a/src/Illuminate/Testing/Fluent/Concerns/Has.php b/src/Illuminate/Testing/Fluent/Concerns/Has.php index 19b9ad9915ca..dd91ee618790 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Has.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -45,9 +45,9 @@ public function has(string $key, $value = null, Closure $scope = null): self $this->interactsWith($key); - // When all three arguments are provided, this indicates a short-hand - // expression that combines both a `count`-assertion, followed by - // directly creating a `scope` on the first element. + // When all three arguments are provided this indicates a short-hand expression + // that combines both a `count`-assertion, followed by directly creating the + // `scope` on the first element. We can simply handle this correctly here. if (is_int($value) && ! is_null($scope)) { $prop = $this->prop($key); $path = $this->dotPath($key); diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index eb983f464a6d..edc85e2a13df 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -15,6 +15,8 @@ use Illuminate\Testing\Assert as PHPUnit; use Illuminate\Testing\Constraints\SeeInOrder; use Illuminate\Testing\Fluent\Assert as FluentAssert; +use Illuminate\Testing\Fluent\AssertableJson; +use Illuminate\Testing\Fluent\FluentAssertableJson; use LogicException; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -519,7 +521,7 @@ public function assertJson($value, $strict = false) if (is_array($value)) { $json->assertSubset($value, $strict); } else { - $assert = FluentAssert::fromAssertableJsonString($json); + $assert = AssertableJson::fromAssertableJsonString($json); $value($assert); diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php index f02e366f40a0..acafd07589d2 100644 --- a/tests/Testing/Fluent/AssertTest.php +++ b/tests/Testing/Fluent/AssertTest.php @@ -3,7 +3,7 @@ namespace Illuminate\Tests\Testing\Fluent; use Illuminate\Support\Collection; -use Illuminate\Testing\Fluent\Assert; +use Illuminate\Testing\Fluent\AssertableJson; use Illuminate\Tests\Testing\Stubs\ArrayableStubObject; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; @@ -14,7 +14,7 @@ class AssertTest extends TestCase { public function testAssertHas() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'prop' => 'value', ]); @@ -23,7 +23,7 @@ public function testAssertHas() public function testAssertHasFailsWhenPropMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'value', ]); @@ -35,7 +35,7 @@ public function testAssertHasFailsWhenPropMissing() public function testAssertHasNestedProp() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'example' => [ 'nested' => 'nested-value', ], @@ -46,7 +46,7 @@ public function testAssertHasNestedProp() public function testAssertHasFailsWhenNestedPropMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'example' => [ 'nested' => 'nested-value', ], @@ -60,7 +60,7 @@ public function testAssertHasFailsWhenNestedPropMissing() public function testAssertCountItemsInProp() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -72,7 +72,7 @@ public function testAssertCountItemsInProp() public function testAssertCountFailsWhenAmountOfItemsDoesNotMatch() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -87,7 +87,7 @@ public function testAssertCountFailsWhenAmountOfItemsDoesNotMatch() public function testAssertCountFailsWhenPropMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -102,7 +102,7 @@ public function testAssertCountFailsWhenPropMissing() public function testAssertHasFailsWhenSecondArgumentUnsupportedType() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'baz', ]); @@ -113,7 +113,7 @@ public function testAssertHasFailsWhenSecondArgumentUnsupportedType() public function testAssertMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => [ 'bar' => true, ], @@ -124,7 +124,7 @@ public function testAssertMissing() public function testAssertMissingFailsWhenPropExists() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'prop' => 'value', 'foo' => [ 'bar' => true, @@ -139,7 +139,7 @@ public function testAssertMissingFailsWhenPropExists() public function testAssertMissingAll() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'baz' => 'foo', ]); @@ -151,7 +151,7 @@ public function testAssertMissingAll() public function testAssertMissingAllFailsWhenAtLeastOnePropExists() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'baz' => 'foo', ]); @@ -166,7 +166,7 @@ public function testAssertMissingAllFailsWhenAtLeastOnePropExists() public function testAssertMissingAllAcceptsMultipleArgumentsInsteadOfArray() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'baz' => 'foo', ]); @@ -180,7 +180,7 @@ public function testAssertMissingAllAcceptsMultipleArgumentsInsteadOfArray() public function testAssertWhereMatchesValue() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'value', ]); @@ -189,7 +189,7 @@ public function testAssertWhereMatchesValue() public function testAssertWhereFailsWhenDoesNotMatchValue() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'value', ]); @@ -201,7 +201,7 @@ public function testAssertWhereFailsWhenDoesNotMatchValue() public function testAssertWhereFailsWhenMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'value', ]); @@ -213,7 +213,7 @@ public function testAssertWhereFailsWhenMissing() public function testAssertWhereFailsWhenMachingLoosely() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 1, ]); @@ -225,7 +225,7 @@ public function testAssertWhereFailsWhenMachingLoosely() public function testAssertWhereUsingClosure() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'baz', ]); @@ -236,7 +236,7 @@ public function testAssertWhereUsingClosure() public function testAssertWhereFailsWhenDoesNotMatchValueUsingClosure() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'baz', ]); @@ -250,7 +250,7 @@ public function testAssertWhereFailsWhenDoesNotMatchValueUsingClosure() public function testAssertWhereClosureArrayValuesAreAutomaticallyCastedToCollections() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'foo', 'example' => 'value', @@ -268,7 +268,7 @@ public function testAssertWhereMatchesValueUsingArrayable() { $stub = ArrayableStubObject::make(['foo' => 'bar']); - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => $stub->toArray(), ]); @@ -277,7 +277,7 @@ public function testAssertWhereMatchesValueUsingArrayable() public function testAssertWhereMatchesValueUsingArrayableWhenSortedDifferently() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'foo', 'example' => 'value', @@ -293,7 +293,7 @@ public function testAssertWhereMatchesValueUsingArrayableWhenSortedDifferently() public function testAssertWhereFailsWhenDoesNotMatchValueUsingArrayable() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => ['id' => 1, 'name' => 'Example'], 'baz' => [ 'id' => 1, @@ -319,7 +319,7 @@ public function testAssertWhereFailsWhenDoesNotMatchValueUsingArrayable() public function testAssertNestedWhereMatchesValue() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'example' => [ 'nested' => 'nested-value', ], @@ -330,7 +330,7 @@ public function testAssertNestedWhereMatchesValue() public function testAssertNestedWhereFailsWhenDoesNotMatchValue() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'example' => [ 'nested' => 'nested-value', ], @@ -344,7 +344,7 @@ public function testAssertNestedWhereFailsWhenDoesNotMatchValue() public function testScope() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -352,7 +352,7 @@ public function testScope() ]); $called = false; - $assert->has('bar', function (Assert $assert) use (&$called) { + $assert->has('bar', function (AssertableJson $assert) use (&$called) { $called = true; $assert ->where('baz', 'example') @@ -364,7 +364,7 @@ public function testScope() public function testScopeFailsWhenPropMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -374,28 +374,28 @@ public function testScopeFailsWhenPropMissing() $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Property [baz] does not exist.'); - $assert->has('baz', function (Assert $item) { + $assert->has('baz', function (AssertableJson $item) { $item->where('baz', 'example'); }); } public function testScopeFailsWhenPropSingleValue() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => 'value', ]); $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Property [bar] is not scopeable.'); - $assert->has('bar', function (Assert $item) { + $assert->has('bar', function (AssertableJson $item) { // }); } public function testScopeShorthand() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ ['key' => 'first'], ['key' => 'second'], @@ -403,7 +403,7 @@ public function testScopeShorthand() ]); $called = false; - $assert->has('bar', 2, function (Assert $item) use (&$called) { + $assert->has('bar', 2, function (AssertableJson $item) use (&$called) { $item->where('key', 'first'); $called = true; }); @@ -413,7 +413,7 @@ public function testScopeShorthand() public function testScopeShorthandFailsWhenAssertingZeroItems() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ ['key' => 'first'], ['key' => 'second'], @@ -423,14 +423,14 @@ public function testScopeShorthandFailsWhenAssertingZeroItems() $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Cannot scope directly onto the first entry of property [bar] when asserting that it has a size of 0.'); - $assert->has('bar', 0, function (Assert $item) { + $assert->has('bar', 0, function (AssertableJson $item) { $item->where('key', 'first'); }); } public function testScopeShorthandFailsWhenAmountOfItemsDoesNotMatch() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ ['key' => 'first'], ['key' => 'second'], @@ -440,14 +440,14 @@ public function testScopeShorthandFailsWhenAmountOfItemsDoesNotMatch() $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Property [bar] does not have the expected size.'); - $assert->has('bar', 1, function (Assert $item) { + $assert->has('bar', 1, function (AssertableJson $item) { $item->where('key', 'first'); }); } public function testFailsWhenNotInteractingWithAllPropsInScope() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -457,28 +457,28 @@ public function testFailsWhenNotInteractingWithAllPropsInScope() $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Unexpected properties were found in scope [bar].'); - $assert->has('bar', function (Assert $item) { + $assert->has('bar', function (AssertableJson $item) { $item->where('baz', 'example'); }); } public function testDisableInteractionCheckForCurrentScope() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', ], ]); - $assert->has('bar', function (Assert $item) { + $assert->has('bar', function (AssertableJson $item) { $item->etc(); }); } public function testCannotDisableInteractionCheckForDifferentScopes() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => [ 'foo' => 'bar', @@ -491,10 +491,10 @@ public function testCannotDisableInteractionCheckForDifferentScopes() $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Unexpected properties were found in scope [bar.baz].'); - $assert->has('bar', function (Assert $item) { + $assert->has('bar', function (AssertableJson $item) { $item ->etc() - ->has('baz', function (Assert $item) { + ->has('baz', function (AssertableJson $item) { // }); }); @@ -502,7 +502,7 @@ public function testCannotDisableInteractionCheckForDifferentScopes() public function testTopLevelPropInteractionDisabledByDefault() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => 'bar', 'bar' => 'baz', ]); @@ -512,7 +512,7 @@ public function testTopLevelPropInteractionDisabledByDefault() public function testTopLevelInteractionEnabledWhenInteractedFlagSet() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => 'bar', 'bar' => 'baz', ]); @@ -527,7 +527,7 @@ public function testTopLevelInteractionEnabledWhenInteractedFlagSet() public function testAssertWhereAllMatchesValues() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => [ 'bar' => 'value', 'example' => ['hello' => 'world'], @@ -546,7 +546,7 @@ public function testAssertWhereAllMatchesValues() public function testAssertWhereAllFailsWhenAtLeastOnePropDoesNotMatchValue() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => 'bar', 'baz' => 'example', ]); @@ -564,7 +564,7 @@ public function testAssertWhereAllFailsWhenAtLeastOnePropDoesNotMatchValue() public function testAssertHasAll() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => [ 'bar' => 'value', 'example' => ['hello' => 'world'], @@ -581,7 +581,7 @@ public function testAssertHasAll() public function testAssertHasAllFailsWhenAtLeastOnePropMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => [ 'bar' => 'value', 'example' => ['hello' => 'world'], @@ -601,7 +601,7 @@ public function testAssertHasAllFailsWhenAtLeastOnePropMissing() public function testAssertHasAllAcceptsMultipleArgumentsInsteadOfArray() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'foo' => [ 'bar' => 'value', 'example' => ['hello' => 'world'], @@ -619,7 +619,7 @@ public function testAssertHasAllAcceptsMultipleArgumentsInsteadOfArray() public function testAssertCountMultipleProps() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'key' => 'value', 'prop' => 'example', @@ -637,7 +637,7 @@ public function testAssertCountMultipleProps() public function testAssertCountMultiplePropsFailsWhenPropMissing() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'key' => 'value', 'prop' => 'example', @@ -655,20 +655,20 @@ public function testAssertCountMultiplePropsFailsWhenPropMissing() public function testMacroable() { - Assert::macro('myCustomMacro', function () { + AssertableJson::macro('myCustomMacro', function () { throw new RuntimeException('My Custom Macro was called!'); }); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('My Custom Macro was called!'); - $assert = Assert::fromArray(['foo' => 'bar']); + $assert = AssertableJson::fromArray(['foo' => 'bar']); $assert->myCustomMacro(); } public function testTappable() { - $assert = Assert::fromArray([ + $assert = AssertableJson::fromArray([ 'bar' => [ 'baz' => 'example', 'prop' => 'value', @@ -676,9 +676,9 @@ public function testTappable() ]); $called = false; - $assert->has('bar', function (Assert $assert) use (&$called) { + $assert->has('bar', function (AssertableJson $assert) use (&$called) { $assert->etc(); - $assert->tap(function (Assert $assert) use (&$called) { + $assert->tap(function (AssertableJson $assert) use (&$called) { $called = true; }); }); diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 055519925cb9..1ac9ebba7373 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -10,6 +10,7 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Http\Response; use Illuminate\Testing\Fluent\Assert; +use Illuminate\Testing\Fluent\AssertableJson; use Illuminate\Testing\TestResponse; use JsonSerializable; use Mockery as m; @@ -582,7 +583,7 @@ public function testAssertJsonWithFluent() { $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableSingleResourceStub)); - $response->assertJson(function (Assert $json) { + $response->assertJson(function (AssertableJson $json) { $json->where('0.foo', 'foo 0'); }); } @@ -594,7 +595,7 @@ public function testAssertJsonWithFluentStrict() $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Unexpected properties were found on the root level.'); - $response->assertJson(function (Assert $json) { + $response->assertJson(function (AssertableJson $json) { $json->where('0.foo', 'foo 0'); }, true); } From 0798479b95fd241c829b0e36a1d6f8573a586738 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 8 Mar 2021 11:52:35 -0600 Subject: [PATCH 321/443] Apply fixes from StyleCI (#36508) --- src/Illuminate/Testing/TestResponse.php | 2 -- tests/Testing/TestResponseTest.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index edc85e2a13df..aeee4fe59c7e 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -14,9 +14,7 @@ use Illuminate\Support\Traits\Tappable; use Illuminate\Testing\Assert as PHPUnit; use Illuminate\Testing\Constraints\SeeInOrder; -use Illuminate\Testing\Fluent\Assert as FluentAssert; use Illuminate\Testing\Fluent\AssertableJson; -use Illuminate\Testing\Fluent\FluentAssertableJson; use LogicException; use Symfony\Component\HttpFoundation\StreamedResponse; diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index 1ac9ebba7373..b6a1e5531a54 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -9,7 +9,6 @@ use Illuminate\Encryption\Encrypter; use Illuminate\Filesystem\Filesystem; use Illuminate\Http\Response; -use Illuminate\Testing\Fluent\Assert; use Illuminate\Testing\Fluent\AssertableJson; use Illuminate\Testing\TestResponse; use JsonSerializable; From 35071ab6ec3c906c0f26d153e743770e8df86079 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Tue, 9 Mar 2021 12:50:29 +0530 Subject: [PATCH 322/443] Add ThrottlesExceptionsWithRedis job middleware --- .../ThrottlesExceptionsWithRedis.php | 62 +++++++ .../Redis/Limiters/DurationLimiter.php | 54 ++++++ .../ThrottlesExceptionsWithRedisTest.php | 167 ++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php create mode 100644 tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php new file mode 100644 index 000000000000..38790e353e2d --- /dev/null +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php @@ -0,0 +1,62 @@ +redis = Container::getInstance()->make(Redis::class); + + $this->limiter = new DurationLimiter( + $this->redis, $this->getKey($job), $this->maxAttempts, $this->decayMinutes * 60 + ); + + if ($this->limiter->tooManyAttempts()) { + return $job->release($this->limiter->decaysAt - $this->currentTime()); + } + + try { + $next($job); + + $this->limiter->clear(); + } catch (Throwable $throwable) { + if ($this->whenCallback && ! call_user_func($this->whenCallback, $throwable)) { + throw $throwable; + } + + $this->limiter->acquire(); + + return $job->release($this->retryAfterMinutes * 60); + } + } +} diff --git a/src/Illuminate/Redis/Limiters/DurationLimiter.php b/src/Illuminate/Redis/Limiters/DurationLimiter.php index 9aa594fb41f4..d4e503ada980 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiter.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiter.php @@ -111,6 +111,30 @@ public function acquire() return (bool) $results[0]; } + /** + * Determine if the key has been "accessed" too many times. + * + * @return bool + */ + public function tooManyAttempts() + { + [$this->decaysAt, $this->remaining] = $this->redis->eval( + $this->tooManyAttemptsScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks + ); + + return $this->remaining <= 0; + } + + /** + * Clear the limiter. + * + * @return void + */ + public function clear() + { + $this->redis->del($this->name); + } + /** * Get the Lua script for acquiring a lock. * @@ -143,6 +167,36 @@ protected function luaScript() end return {reset(), ARGV[2] + ARGV[3], ARGV[4] - 1} +LUA; + } + + /** + * Get the Lua script to determine if the key has been "accessed" too many times. + * + * KEYS[1] - The limiter name + * ARGV[1] - Current time in microseconds + * ARGV[2] - Current time in seconds + * ARGV[3] - Duration of the bucket + * ARGV[4] - Allowed number of tasks + * + * @return string + */ + protected function tooManyAttemptsScript() + { + return <<<'LUA' + +if redis.call('EXISTS', KEYS[1]) == 0 then + return {0, ARGV[2] + ARGV[3]} +end + +if ARGV[1] >= redis.call('HGET', KEYS[1], 'start') and ARGV[1] <= redis.call('HGET', KEYS[1], 'end') then + return { + redis.call('HGET', KEYS[1], 'end'), + ARGV[4] - redis.call('HGET', KEYS[1], 'count') + } +end + +return {0, ARGV[2] + ARGV[3]} LUA; } } diff --git a/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php b/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php new file mode 100644 index 000000000000..35d9255eb751 --- /dev/null +++ b/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php @@ -0,0 +1,167 @@ +setUpRedis(); + } + + protected function tearDown(): void + { + parent::tearDown(); + + $this->tearDownRedis(); + + m::close(); + } + + public function testCircuitIsOpenedForJobErrors() + { + $this->assertJobWasReleasedImmediately(CircuitBreakerWithRedisTestJob::class, $key = Str::random()); + $this->assertJobWasReleasedImmediately(CircuitBreakerWithRedisTestJob::class, $key); + $this->assertJobWasReleasedWithDelay(CircuitBreakerWithRedisTestJob::class, $key); + } + + public function testCircuitStaysClosedForSuccessfulJobs() + { + $this->assertJobRanSuccessfully(CircuitBreakerWithRedisSuccessfulJob::class, $key = Str::random()); + $this->assertJobRanSuccessfully(CircuitBreakerWithRedisSuccessfulJob::class, $key); + $this->assertJobRanSuccessfully(CircuitBreakerWithRedisSuccessfulJob::class, $key); + } + + public function testCircuitResetsAfterSuccess() + { + $this->assertJobWasReleasedImmediately(CircuitBreakerWithRedisTestJob::class, $key = Str::random()); + $this->assertJobRanSuccessfully(CircuitBreakerWithRedisSuccessfulJob::class, $key); + $this->assertJobWasReleasedImmediately(CircuitBreakerWithRedisTestJob::class, $key); + $this->assertJobWasReleasedImmediately(CircuitBreakerWithRedisTestJob::class, $key); + $this->assertJobWasReleasedWithDelay(CircuitBreakerWithRedisTestJob::class, $key); + } + + protected function assertJobWasReleasedImmediately($class, $key) + { + $class::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + + $job->shouldReceive('hasFailed')->once()->andReturn(false); + $job->shouldReceive('release')->with(0)->once(); + $job->shouldReceive('isReleased')->andReturn(true); + $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(true); + + $instance->call($job, [ + 'command' => serialize($command = new $class($key)), + ]); + + $this->assertTrue($class::$handled); + } + + protected function assertJobWasReleasedWithDelay($class, $key) + { + $class::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + + $job->shouldReceive('hasFailed')->once()->andReturn(false); + $job->shouldReceive('release')->withArgs(function ($delay) { + return $delay >= 600; + })->once(); + $job->shouldReceive('isReleased')->andReturn(true); + $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(true); + + $instance->call($job, [ + 'command' => serialize($command = new $class($key)), + ]); + + $this->assertFalse($class::$handled); + } + + protected function assertJobRanSuccessfully($class, $key) + { + $class::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + + $job->shouldReceive('hasFailed')->once()->andReturn(false); + $job->shouldReceive('isReleased')->andReturn(false); + $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(false); + $job->shouldReceive('delete')->once(); + + $instance->call($job, [ + 'command' => serialize($command = new $class($key)), + ]); + + $this->assertTrue($class::$handled); + } +} + +class CircuitBreakerWithRedisTestJob +{ + use InteractsWithQueue, Queueable; + + public static $handled = false; + + public function __construct($key) + { + $this->key = $key; + } + + public function handle() + { + static::$handled = true; + + throw new Exception; + } + + public function middleware() + { + return [new ThrottlesExceptionsWithRedis(2, 10, 0, $this->key)]; + } +} + +class CircuitBreakerWithRedisSuccessfulJob +{ + use InteractsWithQueue, Queueable; + + public static $handled = false; + + public function __construct($key) + { + $this->key = $key; + } + + public function handle() + { + static::$handled = true; + } + + public function middleware() + { + return [new ThrottlesExceptionsWithRedis(2, 10, 0, $this->key)]; + } +} From 55a14074115486b3f4a6e7f4b25dedd9981c5d6e Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 9 Mar 2021 13:43:43 +0200 Subject: [PATCH 323/443] ability to slow the workers down --- src/Illuminate/Queue/Console/WorkCommand.php | 4 +++- src/Illuminate/Queue/Worker.php | 2 ++ src/Illuminate/Queue/WorkerOptions.php | 11 ++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index ff092197f53a..da9176be4063 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -33,6 +33,7 @@ class WorkCommand extends Command {--force : Force the worker to run even in maintenance mode} {--memory=128 : The memory limit in megabytes} {--sleep=3 : Number of seconds to sleep when no job is available} + {--rest=0 : Number of seconds to rest between jobs} {--timeout=60 : The number of seconds a child process can run} {--tries=1 : Number of times to attempt a job before logging it failed}'; @@ -134,7 +135,8 @@ protected function gatherWorkerOptions() $this->option('force'), $this->option('stop-when-empty'), $this->option('max-jobs'), - $this->option('max-time') + $this->option('max-time'), + $this->option('rest') ); } diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index f2ba7b1a01ad..4fcacb26d009 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -156,6 +156,8 @@ public function daemon($connectionName, $queue, WorkerOptions $options) $jobsProcessed++; $this->runJob($job, $connectionName, $options); + + $this->sleep($options->rest); } else { $this->sleep($options->sleep); } diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 766f4676029a..7e99457e70d1 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -74,6 +74,13 @@ class WorkerOptions */ public $maxTime; + /** + * The number of seconds to rest between jobs. + * + * @var int + */ + public $rest; + /** * Create a new worker options instance. * @@ -87,10 +94,11 @@ class WorkerOptions * @param bool $stopWhenEmpty * @param int $maxJobs * @param int $maxTime + * @param int $rest * @return void */ public function __construct($name = 'default', $backoff = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 1, - $force = false, $stopWhenEmpty = false, $maxJobs = 0, $maxTime = 0) + $force = false, $stopWhenEmpty = false, $maxJobs = 0, $maxTime = 0, $rest = 0) { $this->name = $name; $this->backoff = $backoff; @@ -102,5 +110,6 @@ public function __construct($name = 'default', $backoff = 0, $memory = 128, $tim $this->stopWhenEmpty = $stopWhenEmpty; $this->maxJobs = $maxJobs; $this->maxTime = $maxTime; + $this->rest = $rest; } } From d9a33b1812c4c0269fd652fc0e534c140afc489e Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Tue, 9 Mar 2021 10:28:43 -0300 Subject: [PATCH 324/443] [8.x] Allow to override discover events base path (#36515) * Allow to override discover events base path * Update EventServiceProvider.php Co-authored-by: Taylor Otwell --- .../Support/Providers/EventServiceProvider.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 0573563cf5ac..70ea3086efe9 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -119,7 +119,7 @@ public function discoverEvents() ->reduce(function ($discovered, $directory) { return array_merge_recursive( $discovered, - DiscoverEvents::within($directory, base_path()) + DiscoverEvents::within($directory, $this->eventDiscoveryBasePath()) ); }, []); } @@ -135,4 +135,14 @@ protected function discoverEventsWithin() $this->app->path('Listeners'), ]; } + + /** + * Get the base path to be used during event discovery. + * + * @return string + */ + protected function eventDiscoveryBasePath() + { + return base_path(); + } } From a4678ce95cb9d4f10ec789843cee78df4acceb35 Mon Sep 17 00:00:00 2001 From: Jess Archer Date: Tue, 9 Mar 2021 23:29:22 +1000 Subject: [PATCH 325/443] Add prohibited_if and prohibited_unless validation rules (#36516) --- .../Concerns/ReplacesAttributes.php | 40 +++++++++++ .../Concerns/ValidatesAttributes.php | 42 +++++++++++ src/Illuminate/Validation/Validator.php | 2 + tests/Validation/ValidationValidatorTest.php | 72 +++++++++++++++++++ 4 files changed, 156 insertions(+) diff --git a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php index d645dbd6d5a6..d4a47af146c4 100644 --- a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php @@ -374,6 +374,46 @@ protected function replaceRequiredUnless($message, $attribute, $rule, $parameter return str_replace([':other', ':values'], [$other, implode(', ', $values)], $message); } + /** + * Replace all place-holders for the prohibited_if rule. + * + * @param string $message + * @param string $attribute + * @param string $rule + * @param array $parameters + * @return string + */ + protected function replaceProhibitedIf($message, $attribute, $rule, $parameters) + { + $parameters[1] = $this->getDisplayableValue($parameters[0], Arr::get($this->data, $parameters[0])); + + $parameters[0] = $this->getDisplayableAttribute($parameters[0]); + + return str_replace([':other', ':value'], $parameters, $message); + } + + /** + * Replace all place-holders for the prohibited_unless rule. + * + * @param string $message + * @param string $attribute + * @param string $rule + * @param array $parameters + * @return string + */ + protected function replaceProhibitedUnless($message, $attribute, $rule, $parameters) + { + $other = $this->getDisplayableAttribute($parameters[0]); + + $values = []; + + foreach (array_slice($parameters, 1) as $value) { + $values[] = $this->getDisplayableValue($parameters[0], $value); + } + + return str_replace([':other', ':values'], [$other, implode(', ', $values)], $message); + } + /** * Replace all place-holders for the same rule. * diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index bba094dd61f6..2f1dcf6a2157 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1434,6 +1434,48 @@ public function validateRequiredIf($attribute, $value, $parameters) return true; } + /** + * Validate that an attribute does not exist when another attribute has a given value. + * + * @param string $attribute + * @param mixed $value + * @param mixed $parameters + * @return bool + */ + public function validateProhibitedIf($attribute, $value, $parameters) + { + $this->requireParameterCount(2, $parameters, 'prohibited_if'); + + [$values, $other] = $this->parseDependentRuleParameters($parameters); + + if (in_array($other, $values, is_bool($other))) { + return ! $this->validateRequired($attribute, $value); + } + + return true; + } + + /** + * Validate that an attribute does not exist unless another attribute has a given value. + * + * @param string $attribute + * @param mixed $value + * @param mixed $parameters + * @return bool + */ + public function validateProhibitedUnless($attribute, $value, $parameters) + { + $this->requireParameterCount(2, $parameters, 'prohibited_unless'); + + [$values, $other] = $this->parseDependentRuleParameters($parameters); + + if (! in_array($other, $values, is_bool($other))) { + return ! $this->validateRequired($attribute, $value); + } + + return true; + } + /** * Indicate that an attribute should be excluded when another attribute has a given value. * diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 48d9946386d6..0aa44d6c197e 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -227,6 +227,8 @@ class Validator implements ValidatorContract 'RequiredWithAll', 'RequiredWithout', 'RequiredWithoutAll', + 'ProhibitedIf', + 'ProhibitedUnless', 'Same', 'Unique', ]; diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index a60b93b9abf4..7f21e4ba1688 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1146,6 +1146,78 @@ public function testRequiredUnless() $this->assertSame('The last field is required unless first is in taylor, sven.', $v->messages()->first('last')); } + public function testProhibitedIf() + { + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'taylor', 'last' => 'otwell'], ['last' => 'prohibited_if:first,taylor']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'taylor'], ['last' => 'prohibited_if:first,taylor']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'taylor', 'last' => 'otwell'], ['last' => 'prohibited_if:first,taylor,jess']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'taylor'], ['last' => 'prohibited_if:first,taylor,jess']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => true, 'bar' => 'baz'], ['bar' => 'prohibited_if:foo,false']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => true, 'bar' => 'baz'], ['bar' => 'prohibited_if:foo,true']); + $this->assertTrue($v->fails()); + + // error message when passed multiple values (prohibited_if:foo,bar,baz) + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines(['validation.prohibited_if' => 'The :attribute field is prohibited when :other is :value.'], 'en'); + $v = new Validator($trans, ['first' => 'jess', 'last' => 'archer'], ['last' => 'prohibited_if:first,taylor,jess']); + $this->assertFalse($v->passes()); + $this->assertSame('The last field is prohibited when first is jess.', $v->messages()->first('last')); + } + + public function testProhibitedUnless() + { + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'jess', 'last' => 'archer'], ['last' => 'prohibited_unless:first,taylor']); + $this->assertTrue($v->fails()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'taylor', 'last' => 'otwell'], ['last' => 'prohibited_unless:first,taylor']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'jess'], ['last' => 'prohibited_unless:first,taylor']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'taylor', 'last' => 'otwell'], ['last' => 'prohibited_unless:first,taylor,jess']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['first' => 'jess', 'last' => 'archer'], ['last' => 'prohibited_unless:first,taylor,jess']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => false, 'bar' => 'baz'], ['bar' => 'prohibited_unless:foo,false']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['foo' => false, 'bar' => 'baz'], ['bar' => 'prohibited_unless:foo,true']); + $this->assertTrue($v->fails()); + + // error message when passed multiple values (prohibited_unless:foo,bar,baz) + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines(['validation.prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.'], 'en'); + $v = new Validator($trans, ['first' => 'tim', 'last' => 'macdonald'], ['last' => 'prohibitedUnless:first,taylor,jess']); + $this->assertFalse($v->passes()); + $this->assertSame('The last field is prohibited unless first is in taylor, jess.', $v->messages()->first('last')); + } + public function testFailedFileUploads() { $trans = $this->getIlluminateArrayTranslator(); From 37e48ba864e2f463517429d41cefd94e88136c1c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Mar 2021 08:03:10 -0600 Subject: [PATCH 326/443] formatting and fix key usage --- .../Queue/Middleware/ThrottlesExceptions.php | 52 ++++++++++++++----- .../Queue/ThrottlesExceptionsTest.php | 7 ++- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index edb3dd164d33..3fff4e914b55 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -8,6 +8,13 @@ class ThrottlesExceptions { + /** + * The developer specified key that the rate limiter should use. + * + * @var string + */ + protected $key; + /** * The maximum number of attempts allowed before rate limiting applies. * @@ -27,14 +34,7 @@ class ThrottlesExceptions * * @var int */ - protected $retryAfterMinutes; - - /** - * The rate limiter key. - * - * @var string - */ - protected $key; + protected $retryAfterMinutes = 0; /** * The callback that determines if rate limiting should apply. @@ -48,7 +48,7 @@ class ThrottlesExceptions * * @var string */ - protected $prefix = 'circuit_breaker:'; + protected $prefix = 'laravel_throttles_exceptions:'; /** * The rate limiter instance. @@ -62,15 +62,13 @@ class ThrottlesExceptions * * @param int $maxAttempts * @param int $decayMinutes - * @param int $retryAfterMinutes * @param string $key + * @return void */ - public function __construct($maxAttempts = 10, $decayMinutes = 10, $retryAfterMinutes = 0, string $key = '') + public function __construct($maxAttempts = 10, $decayMinutes = 10) { $this->maxAttempts = $maxAttempts; $this->decayMinutes = $decayMinutes; - $this->retryAfterMinutes = $retryAfterMinutes; - $this->key = $key; } /** @@ -129,6 +127,19 @@ public function withPrefix(string $prefix) return $this; } + /** + * Specify the number of seconds a job should be delayed when it is released (before it has reached its max exceptions). + * + * @param int $backoff + * @return $this + */ + public function backoff($backoff) + { + $this->retryAfterMinutes = $backoff; + + return $this; + } + /** * Get the cache key associated for the rate limiter. * @@ -137,7 +148,20 @@ public function withPrefix(string $prefix) */ protected function getKey($job) { - return $this->prefix.md5(empty($this->key) ? get_class($job) : $this->key); + return $this->key ? $this->prefix.$this->key : $this->prefix.$job->job->uuid(); + } + + /** + * Set the value that the rate limiter should be keyed by. + * + * @param string $key + * @return $this + */ + public function by($key) + { + $this->key = $key; + + return $this; } /** diff --git a/tests/Integration/Queue/ThrottlesExceptionsTest.php b/tests/Integration/Queue/ThrottlesExceptionsTest.php index b51190e41654..002acc30c661 100644 --- a/tests/Integration/Queue/ThrottlesExceptionsTest.php +++ b/tests/Integration/Queue/ThrottlesExceptionsTest.php @@ -58,6 +58,7 @@ protected function assertJobWasReleasedImmediately($class) $job->shouldReceive('release')->with(0)->once(); $job->shouldReceive('isReleased')->andReturn(true); $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(true); + $job->shouldReceive('uuid')->andReturn('simple-test-uuid'); $instance->call($job, [ 'command' => serialize($command = new $class), @@ -79,6 +80,7 @@ protected function assertJobWasReleasedWithDelay($class) })->once(); $job->shouldReceive('isReleased')->andReturn(true); $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(true); + $job->shouldReceive('uuid')->andReturn('simple-test-uuid'); $instance->call($job, [ 'command' => serialize($command = new $class), @@ -98,6 +100,7 @@ protected function assertJobRanSuccessfully($class) $job->shouldReceive('isReleased')->andReturn(false); $job->shouldReceive('isDeletedOrReleased')->once()->andReturn(false); $job->shouldReceive('delete')->once(); + $job->shouldReceive('uuid')->andReturn('simple-test-uuid'); $instance->call($job, [ 'command' => serialize($command = new $class), @@ -122,7 +125,7 @@ public function handle() public function middleware() { - return [new ThrottlesExceptions(2, 10, 0, 'test')]; + return [(new ThrottlesExceptions(2, 10))->by('test')]; } } @@ -139,6 +142,6 @@ public function handle() public function middleware() { - return [new ThrottlesExceptions(2, 10, 0, 'test')]; + return [(new ThrottlesExceptions(2, 10))->by('test')]; } } From 0443f1c42c20f6a30d0d81050bc43e94c9c51145 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Tue, 9 Mar 2021 09:06:15 -0500 Subject: [PATCH 327/443] Add class argument (#36513) --- .../Database/Console/Seeds/SeedCommand.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Console/Seeds/SeedCommand.php b/src/Illuminate/Database/Console/Seeds/SeedCommand.php index ccca6fd5eeda..058e545c234f 100644 --- a/src/Illuminate/Database/Console/Seeds/SeedCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeedCommand.php @@ -6,6 +6,7 @@ use Illuminate\Console\ConfirmableTrait; use Illuminate\Database\ConnectionResolverInterface as Resolver; use Illuminate\Database\Eloquent\Model; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; class SeedCommand extends Command @@ -81,7 +82,7 @@ public function handle() */ protected function getSeeder() { - $class = $this->input->getOption('class'); + $class = $this->input->getArgument('class') ?? $this->input->getOption('class'); if (strpos($class, '\\') === false) { $class = 'Database\\Seeders\\'.$class; @@ -109,6 +110,18 @@ protected function getDatabase() return $database ?: $this->laravel['config']['database.default']; } + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['class', InputArgument::OPTIONAL, 'The class name of the root seeder', null], + ]; + } + /** * Get the console command options. * From c6ea49c80a2ac93aebb8fdf2360161b73cec26af Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Mar 2021 08:15:40 -0600 Subject: [PATCH 328/443] formatting --- src/Illuminate/Queue/Worker.php | 4 +++- src/Illuminate/Queue/WorkerOptions.php | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 4fcacb26d009..4229fe701691 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -157,7 +157,9 @@ public function daemon($connectionName, $queue, WorkerOptions $options) $this->runJob($job, $connectionName, $options); - $this->sleep($options->rest); + if ($options->rest > 0) { + $this->sleep($options->rest); + } } else { $this->sleep($options->sleep); } diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 7e99457e70d1..7b8d8dfeea3b 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -39,6 +39,13 @@ class WorkerOptions */ public $sleep; + /** + * The number of seconds to rest between jobs. + * + * @var int + */ + public $rest; + /** * The maximum amount of times a job may be attempted. * @@ -74,13 +81,6 @@ class WorkerOptions */ public $maxTime; - /** - * The number of seconds to rest between jobs. - * - * @var int - */ - public $rest; - /** * Create a new worker options instance. * @@ -103,6 +103,7 @@ public function __construct($name = 'default', $backoff = 0, $memory = 128, $tim $this->name = $name; $this->backoff = $backoff; $this->sleep = $sleep; + $this->rest = $rest; $this->force = $force; $this->memory = $memory; $this->timeout = $timeout; @@ -110,6 +111,5 @@ public function __construct($name = 'default', $backoff = 0, $memory = 128, $tim $this->stopWhenEmpty = $stopWhenEmpty; $this->maxJobs = $maxJobs; $this->maxTime = $maxTime; - $this->rest = $rest; } } From bd490fea91f39c22aa281879882b0f1832f51eae Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Mar 2021 08:28:59 -0600 Subject: [PATCH 329/443] formatting --- src/Illuminate/Redis/Limiters/DurationLimiter.php | 4 ++-- tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Redis/Limiters/DurationLimiter.php b/src/Illuminate/Redis/Limiters/DurationLimiter.php index d4e503ada980..56dbba505435 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiter.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiter.php @@ -119,7 +119,7 @@ public function acquire() public function tooManyAttempts() { [$this->decaysAt, $this->remaining] = $this->redis->eval( - $this->tooManyAttemptsScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks + $this->tooManyAttemptsLuaScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks ); return $this->remaining <= 0; @@ -181,7 +181,7 @@ protected function luaScript() * * @return string */ - protected function tooManyAttemptsScript() + protected function tooManyAttemptsLuaScript() { return <<<'LUA' diff --git a/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php b/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php index 35d9255eb751..c789d5d523f6 100644 --- a/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php +++ b/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php @@ -140,7 +140,7 @@ public function handle() public function middleware() { - return [new ThrottlesExceptionsWithRedis(2, 10, 0, $this->key)]; + return [(new ThrottlesExceptionsWithRedis(2, 10))->by($this->key)]; } } @@ -162,6 +162,6 @@ public function handle() public function middleware() { - return [new ThrottlesExceptionsWithRedis(2, 10, 0, $this->key)]; + return [(new ThrottlesExceptionsWithRedis(2, 10))->by($this->key)]; } } From 784f8ff1469a0bb288600d2bb9e02541c8e38a8d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Mar 2021 09:01:58 -0600 Subject: [PATCH 330/443] patch --- 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 264e0deba796..1f46747dbfbd 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.17'; + const VERSION = '6.20.18'; /** * The base path for the Laravel installation. From b8a70e9a3685871ed46a24fc03c0267849d2d7c8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Mar 2021 09:36:10 -0600 Subject: [PATCH 331/443] adjust behavior --- .../Queue/Middleware/ThrottlesExceptions.php | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index 3fff4e914b55..6364b1d6381a 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -15,6 +15,13 @@ class ThrottlesExceptions */ protected $key; + /** + * Indicates whether the throttle key should use the job's UUID. + * + * @var bool + */ + protected $byJob = false; + /** * The maximum number of attempts allowed before rate limiting applies. * @@ -148,7 +155,13 @@ public function backoff($backoff) */ protected function getKey($job) { - return $this->key ? $this->prefix.$this->key : $this->prefix.$job->job->uuid(); + if ($this->key) { + return $this->prefix.$this->key; + } elseif ($this->byJob) { + return $this->prefix.$job->job->uuid(); + } + + return $this->prefix.md5(get_class($job)); } /** @@ -164,6 +177,18 @@ public function by($key) return $this; } + /** + * Indicate that the throttle key should use the job's UUID. + * + * @return $this + */ + public function byJob() + { + $this->byJob = true; + + return $this; + } + /** * Get the number of seconds that should elapse before the job is retried. * From 7c37b64f8153c16b6406f5c28cf37828ebbe8846 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Mar 2021 09:37:45 -0600 Subject: [PATCH 332/443] patch --- 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 a62cd53588ac..9542156e2529 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.32.0'; + const VERSION = '8.32.1'; /** * The base path for the Laravel installation. From 6eadb692abd726128454cdcb3c634c64933582e0 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 9 Mar 2021 20:03:54 +0200 Subject: [PATCH 333/443] [8.x] update changelog --- CHANGELOG-8.x.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 28603d11124f..8dfc5721f3c9 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,19 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.30.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.31.0...8.x) + + +## [v8.31.0 (2021-03-04)](https://github.com/laravel/framework/compare/v8.30.1...v8.31.0) + +### Added +- Added new `VendorTagPublished` event ([#36458](https://github.com/laravel/framework/pull/36458)) +- Added new `Stringable::test()` method ([#36462](https://github.com/laravel/framework/pull/36462)) + +### Reverted +- Reverted [Fixed `formatWheres()` methods in `DatabaseRule`](https://github.com/laravel/framework/pull/36441) ([#36452](https://github.com/laravel/framework/pull/36452)) + +### Changed +- Make user policy command fix (Windows) ([#36464](https://github.com/laravel/framework/pull/36464)) ## [v8.30.1 (2021-03-03)](https://github.com/laravel/framework/compare/v8.30.0...v8.30.1) From bbb6b97c48a22a13fc1c8cdae157ae6c42c9d07f Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 9 Mar 2021 20:09:54 +0200 Subject: [PATCH 334/443] [6.x] update changelog --- CHANGELOG-6.x.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 860012f0bd0a..b041da96c128 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,15 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.17...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.18...6.x) + + +## [v6.20.18 (2021-03-09)](https://github.com/laravel/framework/compare/v6.20.17...v6.20.18) + +### Fixed +- Fix validator treating null as true for (required|exclude)_(if|unless) due to loose `in_array()` check ([#36504](https://github.com/laravel/framework/pull/36504)) + +### Changed +- Delete existing links that are broken in `Illuminate\Foundation\Console\StorageLinkCommand` ([#36470](https://github.com/laravel/framework/pull/36470)) ## [v6.20.17 (2021-03-02)](https://github.com/laravel/framework/compare/v6.20.16...v6.20.17) From e1ff15be92072d45448e607e90651934b4d22362 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 9 Mar 2021 20:32:59 +0200 Subject: [PATCH 335/443] [8.x] update changelog --- CHANGELOG-8.x.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 8dfc5721f3c9..b70dcd9050d3 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,27 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.31.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.32.0...8.x) + + +## [v8.32.0 (2021-03-09)](https://github.com/laravel/framework/compare/v8.31.0...v8.32.0) + +Added +- Phpredis lock serialization and compression support ([#36412](https://github.com/laravel/framework/pull/36412), [10f1a93](https://github.com/laravel/framework/commit/10f1a935205340ba8954e7075c1d9b67943db27d)) +- Added Fluent JSON Assertions ([#36454](https://github.com/laravel/framework/pull/36454)) +- Added methods to dump requests of the Laravel HTTP client ([#36466](https://github.com/laravel/framework/pull/36466)) +- Added `ThrottlesExceptions` and `ThrottlesExceptionsWithRedis` job middlewares for unstable services ([#36473](https://github.com/laravel/framework/pull/36473), [21fee76](https://github.com/laravel/framework/commit/21fee7649e1b48a7701b8ba860218741c2c3bcef), [36518](https://github.com/laravel/framework/pull/36518), [37e48ba](https://github.com/laravel/framework/commit/37e48ba864e2f463517429d41cefd94e88136c1c)) +- Added support to Eloquent Collection on `Model::destroy()` ([#36497](https://github.com/laravel/framework/pull/36497)) +- Added `rest` option to `php artisan queue:work` command ([#36521](https://github.com/laravel/framework/pull/36521), [c6ea49c](https://github.com/laravel/framework/commit/c6ea49c80a2ac93aebb8fdf2360161b73cec26af)) +- Added `prohibited_if` and `prohibited_unless` validation rules ([#36516](https://github.com/laravel/framework/pull/36516)) +- Added class `argument` to `Illuminate\Database\Console\Seeds\SeedCommand` ([#36513](https://github.com/laravel/framework/pull/36513)) + +### Fixed +- Fix validator treating null as true for (required|exclude)_(if|unless) due to loose `in_array()` check ([#36504](https://github.com/laravel/framework/pull/36504)) + +### Changed +- Delete existing links that are broken in `Illuminate\Foundation\Console\StorageLinkCommand` ([#36470](https://github.com/laravel/framework/pull/36470)) +- Use user provided url in AwsTemporaryUrl method ([#36480](https://github.com/laravel/framework/pull/36480)) +- Allow to override discover events base path ([#36515](https://github.com/laravel/framework/pull/36515)) ## [v8.31.0 (2021-03-04)](https://github.com/laravel/framework/compare/v8.30.1...v8.31.0) From 12b3d57c6f150e1b8def4535c347638113c22664 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 9 Mar 2021 20:35:12 +0200 Subject: [PATCH 336/443] [8.x] update changelog --- CHANGELOG-8.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index b70dcd9050d3..e5ca8f3668f8 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,12 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.32.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.32.1...8.x) + + +## [v8.32.1 (2021-03-09)](https://github.com/laravel/framework/compare/v8.32.0...v8.32.1) + +### Changed +- Changed `Illuminate\Queue\Middleware\ThrottlesExceptions` ([b8a70e9](https://github.com/laravel/framework/commit/b8a70e9a3685871ed46a24fc03c0267849d2d7c8)) ## [v8.32.0 (2021-03-09)](https://github.com/laravel/framework/compare/v8.31.0...v8.32.0) From b7ceae1761de6839e37b70a65177e702b1b4a38f Mon Sep 17 00:00:00 2001 From: Tom Irons Date: Wed, 10 Mar 2021 10:18:48 -0500 Subject: [PATCH 337/443] [8.x] Allow nullable columns for AsArrayObject/AsCollection casts (#36526) * Update AsArrayObject.php * Update AsCollection.php * return null * return null * formatting --- src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php | 2 +- src/Illuminate/Database/Eloquent/Casts/AsCollection.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php b/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php index 8d950e2daff4..a939e8acdbdb 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php @@ -18,7 +18,7 @@ public static function castUsing(array $arguments) return new class implements CastsAttributes { public function get($model, $key, $value, $attributes) { - return new ArrayObject(json_decode($attributes[$key], true)); + return isset($attributes[$key]) ? new ArrayObject(json_decode($attributes[$key], true)) : null; } public function set($model, $key, $value, $attributes) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php index e96834f6e4d3..c2d567b504f7 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php @@ -19,7 +19,7 @@ public static function castUsing(array $arguments) return new class implements CastsAttributes { public function get($model, $key, $value, $attributes) { - return new Collection(json_decode($attributes[$key], true)); + return isset($attributes[$key]) ? new Collection(json_decode($attributes[$key], true)) : null; } public function set($model, $key, $value, $attributes) From 5d093e276abff36b8b4e75541e13ca54829cc75c Mon Sep 17 00:00:00 2001 From: Sibghatullah Mujaddid Date: Thu, 11 Mar 2021 11:31:35 +0800 Subject: [PATCH 338/443] Accept callable class for reportable and renderable in exception handler (#36551) --- .../Foundation/Exceptions/Handler.php | 8 ++++ .../FoundationExceptionsHandlerTest.php | 48 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 38c29a3996c7..bedb1fca3be4 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -139,6 +139,10 @@ public function register() */ public function reportable(callable $reportUsing) { + if (! $reportUsing instanceof Closure) { + $reportUsing = Closure::fromCallable($reportUsing); + } + return tap(new ReportableHandler($reportUsing), function ($callback) { $this->reportCallbacks[] = $callback; }); @@ -152,6 +156,10 @@ public function reportable(callable $reportUsing) */ public function renderable(callable $renderUsing) { + if (! $renderUsing instanceof Closure) { + $renderUsing = Closure::fromCallable($renderUsing); + } + $this->renderCallbacks[] = $renderUsing; return $this; diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index 55b2d54982a5..755a01d9f31e 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -107,6 +107,20 @@ public function testHandlerCallsReportMethodWithDependencies() $this->handler->report(new ReportableException('Exception message')); } + public function testHandlerReportsExceptionUsingCallableClass() + { + $reporter = m::mock(ReportingService::class); + $reporter->shouldReceive('send')->withArgs(['Exception message'])->once(); + + $logger = m::mock(LoggerInterface::class); + $this->container->instance(LoggerInterface::class, $logger); + $logger->shouldNotReceive('error'); + + $this->handler->reportable(new CustomReporter($reporter)); + + $this->handler->report(new CustomException('Exception message')); + } + public function testReturnsJsonWithStackTraceWhenAjaxRequestAndDebugTrue() { $this->config->shouldReceive('get')->with('app.debug', null)->once()->andReturn(true); @@ -134,6 +148,15 @@ public function testReturnsCustomResponseFromRenderableCallback() $this->assertSame('{"response":"My custom exception response"}', $response); } + public function testReturnsCustomResponseFromCallableClass() + { + $this->handler->renderable(new CustomRenderer()); + + $response = $this->handler->render($this->request, new CustomException)->getContent(); + + $this->assertSame('{"response":"The CustomRenderer response"}', $response); + } + public function testReturnsCustomResponseWhenExceptionImplementsResponsable() { $response = $this->handler->render($this->request, new ResponsableException)->getContent(); @@ -302,6 +325,31 @@ public function context() } } +class CustomReporter +{ + private $service; + + public function __construct(ReportingService $service) + { + $this->service = $service; + } + + public function __invoke(CustomException $e) + { + $this->service->send($e->getMessage()); + + return false; + } +} + +class CustomRenderer +{ + public function __invoke(CustomException $e, $request) + { + return response()->json(['response' => 'The CustomRenderer response']); + } +} + interface ReportingService { public function send($message); From dd7274d23a9ee58cc1abdf7107403169a3994b68 Mon Sep 17 00:00:00 2001 From: Ahmed Ashraf Date: Wed, 10 Mar 2021 18:03:35 +0100 Subject: [PATCH 339/443] [8.x] Container - detect circular dependencies --- src/Illuminate/Container/Container.php | 8 +++++- .../CircularDependencyFoundException.php | 11 ++++++++ tests/Container/ContainerTest.php | 26 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/Illuminate/Contracts/Container/CircularDependencyFoundException.php diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 2cfa72f51bb7..abf94c99861c 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -6,6 +6,7 @@ use Closure; use Exception; use Illuminate\Contracts\Container\BindingResolutionException; +use Illuminate\Contracts\Container\CircularDependencyFoundException; use Illuminate\Contracts\Container\Container as ContainerContract; use LogicException; use ReflectionClass; @@ -659,7 +660,7 @@ public function get($id) try { return $this->resolve($id); } catch (Exception $e) { - if ($this->has($id)) { + if ($this->has($id) || $e instanceof CircularDependencyFoundException) { throw $e; } @@ -839,6 +840,11 @@ public function build($concrete) return $this->notInstantiable($concrete); } + // Check for circular dependencies + if(in_array($concrete, $this->buildStack)) { + throw new CircularDependencyFoundException("Circular dependency while initiating [{$concrete}]"); + } + $this->buildStack[] = $concrete; $constructor = $reflector->getConstructor(); diff --git a/src/Illuminate/Contracts/Container/CircularDependencyFoundException.php b/src/Illuminate/Contracts/Container/CircularDependencyFoundException.php new file mode 100644 index 000000000000..d6d0398e93ef --- /dev/null +++ b/src/Illuminate/Contracts/Container/CircularDependencyFoundException.php @@ -0,0 +1,11 @@ +assertInstanceOf(ContainerConcreteStub::class, $class); } + + public function testContainerCanCatchCircularDependency() { + $this->expectException(CircularDependencyFoundException::class); + + $container = new Container; + $container->get(CircularAStub::class); + } +} + +class CircularAStub { + public function __construct(CircularBStub $b) { + + } +} + +class CircularBStub { + public function __construct(CircularCStub $c) { + + } +} + +class CircularCStub { + public function __construct(CircularAStub $a) { + + } } class ContainerConcreteStub From 0f79023f0b176a5ac69a878d642431c402880210 Mon Sep 17 00:00:00 2001 From: Ahmed Ashraf Date: Wed, 10 Mar 2021 18:15:33 +0100 Subject: [PATCH 340/443] update doc --- src/Illuminate/Container/Container.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index abf94c99861c..ad3f6a516f2a 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -671,12 +671,13 @@ public function get($id) /** * Resolve the given type from the container. * - * @param string|callable $abstract - * @param array $parameters - * @param bool $raiseEvents + * @param string|callable $abstract + * @param array $parameters + * @param bool $raiseEvents * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @throws \Illuminate\Contracts\Container\CircularDependencyFoundException */ protected function resolve($abstract, $parameters = [], $raiseEvents = true) { @@ -813,10 +814,11 @@ protected function isBuildable($concrete, $abstract) /** * Instantiate a concrete instance of the given type. * - * @param \Closure|string $concrete + * @param \Closure|string $concrete * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @throws \Illuminate\Contracts\Container\CircularDependencyFoundException */ public function build($concrete) { From a712f72ca88f709335576530b31635738abd4c89 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Mar 2021 21:44:47 -0600 Subject: [PATCH 341/443] formatting --- src/Illuminate/Container/Container.php | 21 +++++++++---------- .../CircularDependencyFoundException.php | 11 ---------- tests/Container/ContainerTest.php | 4 ++-- 3 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 src/Illuminate/Contracts/Container/CircularDependencyFoundException.php diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index ad3f6a516f2a..4ea378983d0d 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -6,7 +6,7 @@ use Closure; use Exception; use Illuminate\Contracts\Container\BindingResolutionException; -use Illuminate\Contracts\Container\CircularDependencyFoundException; +use Illuminate\Contracts\Container\CircularDependencyException; use Illuminate\Contracts\Container\Container as ContainerContract; use LogicException; use ReflectionClass; @@ -660,7 +660,7 @@ public function get($id) try { return $this->resolve($id); } catch (Exception $e) { - if ($this->has($id) || $e instanceof CircularDependencyFoundException) { + if ($this->has($id) || $e instanceof CircularDependencyException) { throw $e; } @@ -671,13 +671,13 @@ public function get($id) /** * Resolve the given type from the container. * - * @param string|callable $abstract - * @param array $parameters - * @param bool $raiseEvents + * @param string|callable $abstract + * @param array $parameters + * @param bool $raiseEvents * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException - * @throws \Illuminate\Contracts\Container\CircularDependencyFoundException + * @throws \Illuminate\Contracts\Container\CircularDependencyException */ protected function resolve($abstract, $parameters = [], $raiseEvents = true) { @@ -814,11 +814,11 @@ protected function isBuildable($concrete, $abstract) /** * Instantiate a concrete instance of the given type. * - * @param \Closure|string $concrete + * @param \Closure|string $concrete * @return mixed * * @throws \Illuminate\Contracts\Container\BindingResolutionException - * @throws \Illuminate\Contracts\Container\CircularDependencyFoundException + * @throws \Illuminate\Contracts\Container\CircularDependencyException */ public function build($concrete) { @@ -842,9 +842,8 @@ public function build($concrete) return $this->notInstantiable($concrete); } - // Check for circular dependencies - if(in_array($concrete, $this->buildStack)) { - throw new CircularDependencyFoundException("Circular dependency while initiating [{$concrete}]"); + if (in_array($concrete, $this->buildStack)) { + throw new CircularDependencyException("Circular dependency detected while resolving [{$concrete}]."); } $this->buildStack[] = $concrete; diff --git a/src/Illuminate/Contracts/Container/CircularDependencyFoundException.php b/src/Illuminate/Contracts/Container/CircularDependencyFoundException.php deleted file mode 100644 index d6d0398e93ef..000000000000 --- a/src/Illuminate/Contracts/Container/CircularDependencyFoundException.php +++ /dev/null @@ -1,11 +0,0 @@ -expectException(CircularDependencyFoundException::class); + $this->expectException(CircularDependencyException::class); $container = new Container; $container->get(CircularAStub::class); From 6f9bb4cdd84295cbcf7908cc4b4684f47f38b8cf Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Mar 2021 21:44:53 -0600 Subject: [PATCH 342/443] formatting --- .../Container/CircularDependencyException.php | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/Illuminate/Contracts/Container/CircularDependencyException.php diff --git a/src/Illuminate/Contracts/Container/CircularDependencyException.php b/src/Illuminate/Contracts/Container/CircularDependencyException.php new file mode 100644 index 000000000000..6c90381cc0cd --- /dev/null +++ b/src/Illuminate/Contracts/Container/CircularDependencyException.php @@ -0,0 +1,11 @@ + Date: Wed, 10 Mar 2021 21:45:44 -0600 Subject: [PATCH 343/443] Apply fixes from StyleCI (#36553) --- tests/Container/ContainerTest.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 27ddca9a12b5..8b5fe7a23a88 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -564,7 +564,8 @@ public function testContainerCanResolveClasses() $this->assertInstanceOf(ContainerConcreteStub::class, $class); } - public function testContainerCanCatchCircularDependency() { + public function testContainerCanCatchCircularDependency() + { $this->expectException(CircularDependencyException::class); $container = new Container; @@ -572,21 +573,24 @@ public function testContainerCanCatchCircularDependency() { } } -class CircularAStub { - public function __construct(CircularBStub $b) { - +class CircularAStub +{ + public function __construct(CircularBStub $b) + { } } -class CircularBStub { - public function __construct(CircularCStub $c) { - +class CircularBStub +{ + public function __construct(CircularCStub $c) + { } } -class CircularCStub { - public function __construct(CircularAStub $a) { - +class CircularCStub +{ + public function __construct(CircularAStub $a) + { } } From d5cd4b3ee7e4db527c5a089af78183e6742afeb5 Mon Sep 17 00:00:00 2001 From: Sevan Nerse Date: Thu, 11 Mar 2021 16:39:04 +0300 Subject: [PATCH 344/443] Add test for stack prepend (#36555) --- tests/View/ViewFactoryTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/View/ViewFactoryTest.php b/tests/View/ViewFactoryTest.php index ab003c3b9f9d..1419f502706c 100755 --- a/tests/View/ViewFactoryTest.php +++ b/tests/View/ViewFactoryTest.php @@ -443,6 +443,27 @@ public function testMultipleStackPush() $this->assertSame('hi, Hello!', $factory->yieldPushContent('foo')); } + public function testSingleStackPrepend() + { + $factory = $this->getFactory(); + $factory->startPrepend('foo'); + echo 'hi'; + $factory->stopPrepend(); + $this->assertSame('hi', $factory->yieldPushContent('foo')); + } + + public function testMultipleStackPrepend() + { + $factory = $this->getFactory(); + $factory->startPrepend('foo'); + echo ', Hello!'; + $factory->stopPrepend(); + $factory->startPrepend('foo'); + echo 'hi'; + $factory->stopPrepend(); + $this->assertSame('hi, Hello!', $factory->yieldPushContent('foo')); + } + public function testSessionAppending() { $factory = $this->getFactory(); From 2d304d4e5dc49c5f80e0ee77cf44d08e8d94325d Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 11 Mar 2021 14:55:37 +0100 Subject: [PATCH 345/443] Consolidate empty function bodies (#36560) --- src/Illuminate/Events/NullDispatcher.php | 3 +++ src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php | 5 +++++ src/Illuminate/Support/Testing/Fakes/BusFake.php | 1 + tests/Container/ContainerTest.php | 3 +++ tests/Integration/Queue/CustomPayloadTest.php | 1 + tests/Support/SupportReflectorTest.php | 4 ++++ 6 files changed, 17 insertions(+) diff --git a/src/Illuminate/Events/NullDispatcher.php b/src/Illuminate/Events/NullDispatcher.php index 5c020cfdd732..5c539d53a361 100644 --- a/src/Illuminate/Events/NullDispatcher.php +++ b/src/Illuminate/Events/NullDispatcher.php @@ -37,6 +37,7 @@ public function __construct(DispatcherContract $dispatcher) */ public function dispatch($event, $payload = [], $halt = false) { + // } /** @@ -48,6 +49,7 @@ public function dispatch($event, $payload = [], $halt = false) */ public function push($event, $payload = []) { + // } /** @@ -59,6 +61,7 @@ public function push($event, $payload = []) */ public function until($event, $payload = []) { + // } /** diff --git a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php index 55681f4d5534..d9661334ce01 100644 --- a/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BatchRepositoryFake.php @@ -33,6 +33,7 @@ public function get($limit, $before) */ public function find(string $batchId) { + // } /** @@ -68,6 +69,7 @@ public function store(PendingBatch $batch) */ public function incrementTotalJobs(string $batchId, int $amount) { + // } /** @@ -102,6 +104,7 @@ public function incrementFailedJobs(string $batchId, string $jobId) */ public function markAsFinished(string $batchId) { + // } /** @@ -112,6 +115,7 @@ public function markAsFinished(string $batchId) */ public function cancel(string $batchId) { + // } /** @@ -122,6 +126,7 @@ public function cancel(string $batchId) */ public function delete(string $batchId) { + // } /** diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index 5b5b68534583..82f3dda5d129 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -517,6 +517,7 @@ public function chain($jobs) */ public function findBatch(string $batchId) { + // } /** diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 8b5fe7a23a88..39638694f802 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -577,6 +577,7 @@ class CircularAStub { public function __construct(CircularBStub $b) { + // } } @@ -584,6 +585,7 @@ class CircularBStub { public function __construct(CircularCStub $c) { + // } } @@ -591,6 +593,7 @@ class CircularCStub { public function __construct(CircularAStub $a) { + // } } diff --git a/tests/Integration/Queue/CustomPayloadTest.php b/tests/Integration/Queue/CustomPayloadTest.php index 3d1088b52c4d..2ce39544be34 100644 --- a/tests/Integration/Queue/CustomPayloadTest.php +++ b/tests/Integration/Queue/CustomPayloadTest.php @@ -60,5 +60,6 @@ class MyJob implements ShouldQueue public function handle() { + // } } diff --git a/tests/Support/SupportReflectorTest.php b/tests/Support/SupportReflectorTest.php index df5b3e414e46..deebed5aabc7 100644 --- a/tests/Support/SupportReflectorTest.php +++ b/tests/Support/SupportReflectorTest.php @@ -81,6 +81,7 @@ class B extends A { public function f(parent $x) { + // } } @@ -92,6 +93,7 @@ class C { public function f(A|Model $x) { + // } }' ); @@ -101,6 +103,7 @@ class TestClassWithCall { public function __call($method, $parameters) { + // } } @@ -108,5 +111,6 @@ class TestClassWithCallStatic { public static function __callStatic($method, $parameters) { + // } } From 36f5aac531f0dfd148b45be7960188db12d80f9a Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 11 Mar 2021 14:56:28 +0100 Subject: [PATCH 346/443] Fix returns with Mail & Notification components (#36559) These methods were incorrectly returning values. Since nothing was returned in the first place and the proper DocBlocks were already in place, this should be a general safe thing to do. --- src/Illuminate/Mail/Mailable.php | 2 +- src/Illuminate/Mail/Mailer.php | 6 +++--- src/Illuminate/Mail/PendingMail.php | 4 ++-- src/Illuminate/Notifications/ChannelManager.php | 4 ++-- src/Illuminate/Notifications/NotificationSender.php | 2 +- src/Illuminate/Support/Testing/Fakes/EventFake.php | 2 +- src/Illuminate/Support/Testing/Fakes/NotificationFake.php | 2 +- src/Illuminate/Support/Testing/Fakes/PendingMailFake.php | 4 ++-- src/Illuminate/Support/Testing/Fakes/QueueFake.php | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 1fe0b7ea3d20..903bd5f5f41b 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -170,7 +170,7 @@ class Mailable implements MailableContract, Renderable */ public function send($mailer) { - return $this->withLocale($this->locale, function () use ($mailer) { + $this->withLocale($this->locale, function () use ($mailer) { Container::getInstance()->call([$this, 'build']); $mailer = $mailer instanceof MailFactory diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index 668d68baaf2a..128f211f7651 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -197,7 +197,7 @@ public function bcc($users) */ public function html($html, $callback) { - return $this->send(['html' => new HtmlString($html)], [], $callback); + $this->send(['html' => new HtmlString($html)], [], $callback); } /** @@ -209,7 +209,7 @@ public function html($html, $callback) */ public function raw($text, $callback) { - return $this->send(['raw' => $text], [], $callback); + $this->send(['raw' => $text], [], $callback); } /** @@ -222,7 +222,7 @@ public function raw($text, $callback) */ public function plain($view, array $data, $callback) { - return $this->send(['text' => $view], $data, $callback); + $this->send(['text' => $view], $data, $callback); } /** diff --git a/src/Illuminate/Mail/PendingMail.php b/src/Illuminate/Mail/PendingMail.php index 43c30961f90b..10d76cb6aa9b 100644 --- a/src/Illuminate/Mail/PendingMail.php +++ b/src/Illuminate/Mail/PendingMail.php @@ -114,11 +114,11 @@ public function bcc($users) * Send a new mailable message instance. * * @param \Illuminate\Contracts\Mail\Mailable $mailable - * @return mixed + * @return void */ public function send(MailableContract $mailable) { - return $this->mailer->send($this->fill($mailable)); + $this->mailer->send($this->fill($mailable)); } /** diff --git a/src/Illuminate/Notifications/ChannelManager.php b/src/Illuminate/Notifications/ChannelManager.php index d2344ab68acc..8eb9c251024d 100644 --- a/src/Illuminate/Notifications/ChannelManager.php +++ b/src/Illuminate/Notifications/ChannelManager.php @@ -34,7 +34,7 @@ class ChannelManager extends Manager implements DispatcherContract, FactoryContr */ public function send($notifiables, $notification) { - return (new NotificationSender( + (new NotificationSender( $this, $this->container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale) )->send($notifiables, $notification); } @@ -49,7 +49,7 @@ public function send($notifiables, $notification) */ public function sendNow($notifiables, $notification, array $channels = null) { - return (new NotificationSender( + (new NotificationSender( $this, $this->container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale) )->sendNow($notifiables, $notification, $channels); } diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index 39be0e598796..aff36c7a5b0f 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -76,7 +76,7 @@ public function send($notifiables, $notification) return $this->queueNotification($notifiables, $notification); } - return $this->sendNow($notifiables, $notification); + $this->sendNow($notifiables, $notification); } /** diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 90f30212ef7b..88fcb84cea48 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -278,7 +278,7 @@ public function forgetPushed() * * @param string|object $event * @param mixed $payload - * @return void + * @return array|null */ public function until($event, $payload = []) { diff --git a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php index cf3a25afd696..28526d592556 100644 --- a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php +++ b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php @@ -210,7 +210,7 @@ protected function notificationsFor($notifiable, $notification) */ public function send($notifiables, $notification) { - return $this->sendNow($notifiables, $notification); + $this->sendNow($notifiables, $notification); } /** diff --git a/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php b/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php index c39012501ae6..52251301ceb9 100644 --- a/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php +++ b/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php @@ -22,11 +22,11 @@ public function __construct($mailer) * Send a new mailable message instance. * * @param \Illuminate\Contracts\Mail\Mailable $mailable - * @return mixed + * @return void */ public function send(Mailable $mailable) { - return $this->mailer->send($this->fill($mailable)); + $this->mailer->send($this->fill($mailable)); } /** diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index e83408fc0c74..64d6414fd81b 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -74,7 +74,7 @@ public function assertPushedOn($queue, $job, $callback = null) [$job, $callback] = [$this->firstClosureParameterType($job), $job]; } - return $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) { + $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) { if ($pushedQueue !== $queue) { return false; } From 62925b64310bb796dff479aea4acc55a1620d470 Mon Sep 17 00:00:00 2001 From: Olzhas Date: Thu, 11 Mar 2021 21:08:31 +0600 Subject: [PATCH 347/443] Add resource missing option --- .../Routing/PendingResourceRegistration.php | 13 +++++++++++++ src/Illuminate/Routing/ResourceRegistrar.php | 11 +++++++++++ tests/Routing/RouteRegistrarTest.php | 16 ++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/Illuminate/Routing/PendingResourceRegistration.php b/src/Illuminate/Routing/PendingResourceRegistration.php index 3b6c97e2042d..d2bb33c65de2 100644 --- a/src/Illuminate/Routing/PendingResourceRegistration.php +++ b/src/Illuminate/Routing/PendingResourceRegistration.php @@ -195,6 +195,19 @@ public function shallow($shallow = true) return $this; } + /** + * Define the callable that should be invoked on a missing model exception. + * + * @param $callback + * @return $this + */ + public function missing($callback) + { + $this->options['missing'] = $callback; + + return $this; + } + /** * Indicate that the resource routes should be scoped using the given binding fields. * diff --git a/src/Illuminate/Routing/ResourceRegistrar.php b/src/Illuminate/Routing/ResourceRegistrar.php index c32aa023b4bd..d52264456af1 100644 --- a/src/Illuminate/Routing/ResourceRegistrar.php +++ b/src/Illuminate/Routing/ResourceRegistrar.php @@ -20,6 +20,13 @@ class ResourceRegistrar */ protected $resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy']; + /** + * Actions that use model binding. + * + * @var string[] + */ + protected $modelBoundMethods = ['show', 'edit', 'update', 'destroy']; + /** * The parameters set for this resource instance. * @@ -421,6 +428,10 @@ protected function getResourceAction($resource, $controller, $method, $options) $action['where'] = $options['wheres']; } + if (isset($options['missing']) && in_array($method, $this->modelBoundMethods)) { + $action['missing'] = $options['missing']; + } + return $action; } diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index 47fcb2aa31e5..831ced92fdfb 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -334,6 +334,22 @@ public function testCanRegisterResourcesWithoutOption() } } + public function testCanRegisterResourceWithMissingOption() + { + $this->router->middleware('resource-middleware') + ->resource('users', RouteRegistrarControllerStub::class) + ->missing(function () { return 'missing'; }); + + $this->assertIsCallable($this->router->getRoutes()->getByName('users.show')->getMissing()); + $this->assertIsCallable($this->router->getRoutes()->getByName('users.edit')->getMissing()); + $this->assertIsCallable($this->router->getRoutes()->getByName('users.update')->getMissing()); + $this->assertIsCallable($this->router->getRoutes()->getByName('users.destroy')->getMissing()); + + $this->assertNull($this->router->getRoutes()->getByName('users.index')->getMissing()); + $this->assertNull($this->router->getRoutes()->getByName('users.create')->getMissing()); + $this->assertNull($this->router->getRoutes()->getByName('users.store')->getMissing()); + } + public function testCanAccessRegisteredResourceRoutesAsRouteCollection() { $resource = $this->router->middleware('resource-middleware') From c887875c23f393e3443b1fd2a8dd0c748e6f13ea Mon Sep 17 00:00:00 2001 From: Olzhas Date: Thu, 11 Mar 2021 21:25:07 +0600 Subject: [PATCH 348/443] Add resource missing option --- src/Illuminate/Routing/ResourceRegistrar.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Routing/ResourceRegistrar.php b/src/Illuminate/Routing/ResourceRegistrar.php index d52264456af1..c32de58c291f 100644 --- a/src/Illuminate/Routing/ResourceRegistrar.php +++ b/src/Illuminate/Routing/ResourceRegistrar.php @@ -20,13 +20,6 @@ class ResourceRegistrar */ protected $resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy']; - /** - * Actions that use model binding. - * - * @var string[] - */ - protected $modelBoundMethods = ['show', 'edit', 'update', 'destroy']; - /** * The parameters set for this resource instance. * @@ -191,6 +184,8 @@ protected function addResourceIndex($name, $base, $controller, $options) { $uri = $this->getResourceUri($name); + unset($options['missing']); + $action = $this->getResourceAction($name, $controller, 'index', $options); return $this->router->get($uri, $action); @@ -209,6 +204,8 @@ protected function addResourceCreate($name, $base, $controller, $options) { $uri = $this->getResourceUri($name).'/'.static::$verbs['create']; + unset($options['missing']); + $action = $this->getResourceAction($name, $controller, 'create', $options); return $this->router->get($uri, $action); @@ -227,6 +224,8 @@ protected function addResourceStore($name, $base, $controller, $options) { $uri = $this->getResourceUri($name); + unset($options['missing']); + $action = $this->getResourceAction($name, $controller, 'store', $options); return $this->router->post($uri, $action); @@ -428,7 +427,7 @@ protected function getResourceAction($resource, $controller, $method, $options) $action['where'] = $options['wheres']; } - if (isset($options['missing']) && in_array($method, $this->modelBoundMethods)) { + if (isset($options['missing'])) { $action['missing'] = $options['missing']; } From 61db3ef0e82b0ff5170100e2ea5198a195ac2743 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 11 Mar 2021 17:23:18 +0100 Subject: [PATCH 349/443] Update to ubuntu-20.04 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c7b91b6fe781..1a81af4975b9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: jobs: linux_tests: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 services: memcached: From 65c8e0c13323862d6e65432468bea2924e490629 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 12 Mar 2021 00:04:53 +0100 Subject: [PATCH 350/443] Fix Mailer contract returns (#36563) --- src/Illuminate/Contracts/Mail/Factory.php | 2 +- src/Illuminate/Mail/MailManager.php | 2 +- src/Illuminate/Support/Testing/Fakes/MailFake.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Contracts/Mail/Factory.php b/src/Illuminate/Contracts/Mail/Factory.php index 0719c0514595..fe45a2fd9cd8 100644 --- a/src/Illuminate/Contracts/Mail/Factory.php +++ b/src/Illuminate/Contracts/Mail/Factory.php @@ -8,7 +8,7 @@ interface Factory * Get a mailer instance by name. * * @param string|null $name - * @return \Illuminate\Mail\Mailer + * @return \Illuminate\Contracts\Mail\Mailer */ public function mailer($name = null); } diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index 97fcda7827c5..86acdde3e3aa 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -63,7 +63,7 @@ public function __construct($app) * Get a mailer instance by name. * * @param string|null $name - * @return \Illuminate\Mail\Mailer + * @return \Illuminate\Contracts\Mail\Mailer */ public function mailer($name = null) { diff --git a/src/Illuminate/Support/Testing/Fakes/MailFake.php b/src/Illuminate/Support/Testing/Fakes/MailFake.php index eb548b6910b3..a42fe341f40e 100644 --- a/src/Illuminate/Support/Testing/Fakes/MailFake.php +++ b/src/Illuminate/Support/Testing/Fakes/MailFake.php @@ -276,7 +276,7 @@ protected function queuedMailablesOf($type) * Get a mailer instance by name. * * @param string|null $name - * @return \Illuminate\Mail\Mailer + * @return \Illuminate\Contracts\Mail\Mailer */ public function mailer($name = null) { From be86b91ca8812a2564cba71f859ebf410ca1f571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Fri, 12 Mar 2021 14:52:50 +0100 Subject: [PATCH 351/443] [6.x] add make method to App facade (#36574) --- src/Illuminate/Support/Facades/App.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index 67e0b4c233e4..0bc5b34254d3 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -19,6 +19,7 @@ * @method static \Illuminate\Support\ServiceProvider register(\Illuminate\Support\ServiceProvider|string $provider, bool $force = false) * @method static void registerDeferredProvider(string $provider, string $service = null) * @method static \Illuminate\Support\ServiceProvider resolveProvider(string $provider) + * @method static mixed make($abstract, array $parameters = []) * @method static void boot() * @method static void booting(callable $callback) * @method static void booted(callable $callback) From cf9b74985e882c2405a9f6068cdd9bacfc9433a0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Mar 2021 08:11:27 -0600 Subject: [PATCH 352/443] formatting --- src/Illuminate/Routing/PendingResourceRegistration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/PendingResourceRegistration.php b/src/Illuminate/Routing/PendingResourceRegistration.php index d2bb33c65de2..59e4b8f0b78f 100644 --- a/src/Illuminate/Routing/PendingResourceRegistration.php +++ b/src/Illuminate/Routing/PendingResourceRegistration.php @@ -198,7 +198,7 @@ public function shallow($shallow = true) /** * Define the callable that should be invoked on a missing model exception. * - * @param $callback + * @param callable $callback * @return $this */ public function missing($callback) From 6d1da017689c004efece0bde8c3790202c359a31 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Mar 2021 08:12:04 -0600 Subject: [PATCH 353/443] Apply fixes from StyleCI (#36577) --- tests/Routing/RouteRegistrarTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index 831ced92fdfb..9802ad742a61 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -338,7 +338,9 @@ public function testCanRegisterResourceWithMissingOption() { $this->router->middleware('resource-middleware') ->resource('users', RouteRegistrarControllerStub::class) - ->missing(function () { return 'missing'; }); + ->missing(function () { + return 'missing'; + }); $this->assertIsCallable($this->router->getRoutes()->getByName('users.show')->getMissing()); $this->assertIsCallable($this->router->getRoutes()->getByName('users.edit')->getMissing()); From e4ed3317c2730803925918e1cb1e1e739e20ba5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Fri, 12 Mar 2021 15:45:30 +0100 Subject: [PATCH 354/443] [8.x] StringEncrypter interface for better DX (#36578) * StringEncrypter interface for better DX * StyleCI * Update Encrypter.php Co-authored-by: Taylor Otwell --- .../Contracts/Encryption/StringEncrypter.php | 26 +++++++++++++++++++ src/Illuminate/Encryption/Encrypter.php | 3 ++- src/Illuminate/Foundation/Application.php | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/Illuminate/Contracts/Encryption/StringEncrypter.php diff --git a/src/Illuminate/Contracts/Encryption/StringEncrypter.php b/src/Illuminate/Contracts/Encryption/StringEncrypter.php new file mode 100644 index 000000000000..1e6938c29a16 --- /dev/null +++ b/src/Illuminate/Contracts/Encryption/StringEncrypter.php @@ -0,0 +1,26 @@ + [\Symfony\Component\Cache\Adapter\Psr16Adapter::class, \Symfony\Component\Cache\Adapter\AdapterInterface::class, \Psr\Cache\CacheItemPoolInterface::class], 'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class], 'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class], - 'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class], 'db' => [\Illuminate\Database\DatabaseManager::class, \Illuminate\Database\ConnectionResolverInterface::class], 'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class], + 'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\StringEncrypter::class], 'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class], 'files' => [\Illuminate\Filesystem\Filesystem::class], 'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class], From a69f15d30522eb3c1db5786c6df8a6d4f87bd0a3 Mon Sep 17 00:00:00 2001 From: Markus Machatschek Date: Mon, 15 Mar 2021 14:32:05 +0100 Subject: [PATCH 355/443] Add ssl broken pipe as lost connection error (#36601) --- 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 1ecfc96140f4..a0bad6718017 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -50,6 +50,7 @@ protected function causedByLostConnection(Throwable $e) 'SSL: Connection timed out', 'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.', 'Temporary failure in name resolution', + 'SSL: Broken pipe', ]); } } From ddab370272942f456b0632b8f1d5d957266262cd Mon Sep 17 00:00:00 2001 From: Zubair Mohsin Date: Mon, 15 Mar 2021 18:36:05 +0500 Subject: [PATCH 356/443] Initializes CronExpression class using new (#36600) --- src/Illuminate/Console/Scheduling/Event.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index a680c1a64cb0..b3ab9b2db567 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -328,7 +328,7 @@ protected function expressionPasses() $date->setTimezone($this->timezone); } - return CronExpression::factory($this->expression)->isDue($date->toDateTimeString()); + return (new CronExpression($this->expression))->isDue($date->toDateTimeString()); } /** @@ -890,9 +890,8 @@ public function getSummaryForDisplay() */ public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) { - return Date::instance(CronExpression::factory( - $this->getExpression() - )->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); + return Date::instance((new CronExpression($this->getExpression())) + ->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); } /** From e0c638167c5e6911d6fc579bc4e04b66f6a94784 Mon Sep 17 00:00:00 2001 From: Roy de Vos Burchart Date: Mon, 15 Mar 2021 14:43:13 +0100 Subject: [PATCH 357/443] Remove null from return in phpdoc (#36593) --- src/Illuminate/Support/Stringable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 0d544a3987cf..d834260e11cf 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -335,7 +335,7 @@ public function markdown(array $options = []) * Get the string matching the given pattern. * * @param string $pattern - * @return static|null + * @return static */ public function match($pattern) { From c67a685598de8e12e7fcf03095ac168f85122c4e Mon Sep 17 00:00:00 2001 From: Nguyen You Date: Mon, 15 Mar 2021 20:43:55 +0700 Subject: [PATCH 358/443] Update docblock (#36592) --- src/Illuminate/Foundation/Console/stubs/view-component.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/stubs/view-component.stub b/src/Illuminate/Foundation/Console/stubs/view-component.stub index 5c6ecc586ec4..22eae518c1a4 100644 --- a/src/Illuminate/Foundation/Console/stubs/view-component.stub +++ b/src/Illuminate/Foundation/Console/stubs/view-component.stub @@ -19,7 +19,7 @@ class DummyClass extends Component /** * Get the view / contents that represent the component. * - * @return \Illuminate\Contracts\View\View|string + * @return \Illuminate\Contracts\View\View|\Closure|string */ public function render() { From 1e09138398ff1a6a9812e58041f1f9f31d846846 Mon Sep 17 00:00:00 2001 From: Dominik Date: Mon, 15 Mar 2021 14:48:31 +0100 Subject: [PATCH 359/443] Stack driver fix: respect the defined processors (#36591) This update fixes the issue: https://github.com/laravel/ideas/issues/1735 --- src/Illuminate/Log/LogManager.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 0e0abcd67c33..ed6c418abc2d 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -244,12 +244,16 @@ protected function createStackDriver(array $config) $handlers = collect($config['channels'])->flatMap(function ($channel) { return $this->channel($channel)->getHandlers(); })->all(); + + $processors = collect($config['channels'])->flatMap(function ($channel) { + return $this->channel($channel)->getProcessors(); + })->all(); if ($config['ignore_exceptions'] ?? false) { $handlers = [new WhatFailureGroupHandler($handlers)]; } - return new Monolog($this->parseChannel($config), $handlers); + return new Monolog($this->parseChannel($config), $handlers, $processors); } /** From c02e3250c3a933b08656ac4c84168353eba771a8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 15 Mar 2021 08:48:56 -0500 Subject: [PATCH 360/443] Apply fixes from StyleCI (#36603) --- 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 ed6c418abc2d..f5d0ac486e2b 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -244,7 +244,7 @@ protected function createStackDriver(array $config) $handlers = collect($config['channels'])->flatMap(function ($channel) { return $this->channel($channel)->getHandlers(); })->all(); - + $processors = collect($config['channels'])->flatMap(function ($channel) { return $this->channel($channel)->getProcessors(); })->all(); From 580fb32724e9dfbeade884dcd91721f4f47b44b5 Mon Sep 17 00:00:00 2001 From: Matthew Boynes Date: Mon, 15 Mar 2021 19:03:48 -0400 Subject: [PATCH 361/443] Require the correct password to rehash it --- src/Illuminate/Auth/SessionGuard.php | 24 ++++++++++++++++--- tests/Integration/Auth/AuthenticationTest.php | 17 ++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 1f6863141c4c..1748e9af19fb 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -573,6 +573,26 @@ protected function cycleRememberToken(AuthenticatableContract $user) $this->provider->updateRememberToken($user, $token); } + /** + * Rehash the user's password. + * + * @param string $password + * @param string $attribute + * @return bool|null + * + * @throws AuthenticationException If the password is invalid. + */ + protected function rehashUserPassword($password, $attribute) + { + if (! Hash::check($password, $this->user()->$attribute)) { + throw new AuthenticationException('Password mismatch.'); + } + + return tap($this->user()->forceFill([ + $attribute => Hash::make($password), + ]))->save(); + } + /** * Invalidate other sessions for the current user. * @@ -588,9 +608,7 @@ public function logoutOtherDevices($password, $attribute = 'password') return; } - $result = tap($this->user()->forceFill([ - $attribute => Hash::make($password), - ]))->save(); + $result = $this->rehashUserPassword($password, $attribute); if ($this->recaller() || $this->getCookieJar()->hasQueued($this->getRecallerName())) { diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index ec23afba3d18..23862f48d94a 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Auth; +use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\EloquentUserProvider; use Illuminate\Auth\Events\Attempting; use Illuminate\Auth\Events\Authenticated; @@ -211,7 +212,7 @@ public function testLoggingOutOtherDevices() $this->assertEquals(1, $user->id); - $this->app['auth']->logoutOtherDevices('adifferentpassword'); + $this->app['auth']->logoutOtherDevices('password'); $this->assertEquals(1, $user->id); Event::assertDispatched(OtherDeviceLogout::class, function ($event) { @@ -222,6 +223,20 @@ public function testLoggingOutOtherDevices() }); } + public function testPasswordMustBeValidToLogOutOtherDevices() + { + $this->expectException(AuthenticationException::class); + $this->expectExceptionMessage('Password mismatch.'); + + $this->app['auth']->loginUsingId(1); + + $user = $this->app['auth']->user(); + + $this->assertEquals(1, $user->id); + + $this->app['auth']->logoutOtherDevices('adifferentpassword'); + } + public function testLoggingInOutViaAttemptRemembering() { $this->assertTrue( From ef4541d51a805eb711e14af897515aa7b2ed3569 Mon Sep 17 00:00:00 2001 From: Matthew Boynes Date: Mon, 15 Mar 2021 19:18:55 -0400 Subject: [PATCH 362/443] Add @throws to logoutOtherDevices() --- src/Illuminate/Auth/SessionGuard.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 1748e9af19fb..ef7ab4ebecc1 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -601,6 +601,8 @@ protected function rehashUserPassword($password, $attribute) * @param string $password * @param string $attribute * @return bool|null + * + * @throws AuthenticationException If the password is invalid. */ public function logoutOtherDevices($password, $attribute = 'password') { From ceb2f46592007ca63bea9836d5547b38c8c47711 Mon Sep 17 00:00:00 2001 From: Matthew Boynes Date: Mon, 15 Mar 2021 21:14:42 -0400 Subject: [PATCH 363/443] Clarify that the current user's password is rehashing --- src/Illuminate/Auth/SessionGuard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index ef7ab4ebecc1..bc6bad4d6a14 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -574,7 +574,7 @@ protected function cycleRememberToken(AuthenticatableContract $user) } /** - * Rehash the user's password. + * Rehash the current user's password. * * @param string $password * @param string $attribute From 7aabd8f0a8f8e0a3420359f807f42ceacb5c4140 Mon Sep 17 00:00:00 2001 From: Matthew Boynes Date: Tue, 16 Mar 2021 07:50:38 -0400 Subject: [PATCH 364/443] Use FQN in docblock, remove description --- src/Illuminate/Auth/SessionGuard.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index bc6bad4d6a14..74569a7bf599 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -580,7 +580,7 @@ protected function cycleRememberToken(AuthenticatableContract $user) * @param string $attribute * @return bool|null * - * @throws AuthenticationException If the password is invalid. + * @throws \Illuminate\Auth\AuthenticationException */ protected function rehashUserPassword($password, $attribute) { @@ -602,7 +602,7 @@ protected function rehashUserPassword($password, $attribute) * @param string $attribute * @return bool|null * - * @throws AuthenticationException If the password is invalid. + * @throws \Illuminate\Auth\AuthenticationException */ public function logoutOtherDevices($password, $attribute = 'password') { From d98cf8b5baca2d12341cdc1d75888cfe6fb67260 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Tue, 16 Mar 2021 13:43:20 +0100 Subject: [PATCH 365/443] [8.x] Use different config key for overriding temporary url host in AwsTemporaryUrl method (#36612) * Use different config key for overriding temporary url host * Update FilesystemAdapter.php Co-authored-by: Taylor Otwell --- src/Illuminate/Filesystem/FilesystemAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 5d6de6ed3321..935c413cd6c0 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -601,7 +601,7 @@ public function getAwsTemporaryUrl($adapter, $path, $expiration, $options) // If an explicit base URL has been set on the disk configuration then we will use // it as the base URL instead of the default path. This allows the developer to // have full control over the base path for this filesystem's generated URLs. - if (! is_null($url = $this->driver->getConfig()->get('url'))) { + if (! is_null($url = $this->driver->getConfig()->get('temporary_url'))) { $uri = $this->replaceBaseUrl($uri, $url); } From 1e6161250074b8106c1fcf153eeaef7c0bf74c6c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Mar 2021 09:14:59 -0500 Subject: [PATCH 366/443] formatting --- src/Illuminate/Auth/SessionGuard.php | 41 ++++++++++--------- tests/Integration/Auth/AuthenticationTest.php | 6 +-- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 74569a7bf599..48d64c47d39f 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -20,6 +20,7 @@ use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; +use InvalidArgumentException; use RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; @@ -573,26 +574,6 @@ protected function cycleRememberToken(AuthenticatableContract $user) $this->provider->updateRememberToken($user, $token); } - /** - * Rehash the current user's password. - * - * @param string $password - * @param string $attribute - * @return bool|null - * - * @throws \Illuminate\Auth\AuthenticationException - */ - protected function rehashUserPassword($password, $attribute) - { - if (! Hash::check($password, $this->user()->$attribute)) { - throw new AuthenticationException('Password mismatch.'); - } - - return tap($this->user()->forceFill([ - $attribute => Hash::make($password), - ]))->save(); - } - /** * Invalidate other sessions for the current user. * @@ -622,6 +603,26 @@ public function logoutOtherDevices($password, $attribute = 'password') return $result; } + /** + * Rehash the current user's password. + * + * @param string $password + * @param string $attribute + * @return bool|null + * + * @throws \InvalidArgumentException + */ + protected function rehashUserPassword($password, $attribute) + { + if (! Hash::check($password, $this->user()->{$attribute})) { + throw new InvalidArgumentException("The given password does not match the current password."); + } + + return tap($this->user()->forceFill([ + $attribute => Hash::make($password), + ]))->save(); + } + /** * Register an authentication attempt event listener. * diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index 23862f48d94a..e2ec79050d18 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Integration\Auth; -use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\EloquentUserProvider; use Illuminate\Auth\Events\Attempting; use Illuminate\Auth\Events\Authenticated; @@ -20,6 +19,7 @@ use Illuminate\Support\Str; use Illuminate\Support\Testing\Fakes\EventFake; use Illuminate\Tests\Integration\Auth\Fixtures\AuthenticationTestUser; +use InvalidArgumentException; use Orchestra\Testbench\TestCase; /** @@ -225,8 +225,8 @@ public function testLoggingOutOtherDevices() public function testPasswordMustBeValidToLogOutOtherDevices() { - $this->expectException(AuthenticationException::class); - $this->expectExceptionMessage('Password mismatch.'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('current password'); $this->app['auth']->loginUsingId(1); From ebfa75fee5acef028a09f52a78a7069b1a09a723 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Mar 2021 09:15:38 -0500 Subject: [PATCH 367/443] Apply fixes from StyleCI (#36615) --- src/Illuminate/Auth/SessionGuard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 48d64c47d39f..4bb3fd4b6f73 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -615,7 +615,7 @@ public function logoutOtherDevices($password, $attribute = 'password') protected function rehashUserPassword($password, $attribute) { if (! Hash::check($password, $this->user()->{$attribute})) { - throw new InvalidArgumentException("The given password does not match the current password."); + throw new InvalidArgumentException('The given password does not match the current password.'); } return tap($this->user()->forceFill([ From c25308a00c7bbd38401a6254ab403146da9cfd69 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Mar 2021 09:18:55 -0500 Subject: [PATCH 368/443] version --- 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 1f46747dbfbd..5fa3b2bed350 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.18'; + const VERSION = '6.20.19'; /** * The base path for the Laravel installation. From acb117738ddb28ea7fc6a2029cf1d0d06c4b2b57 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 16 Mar 2021 19:05:22 +0200 Subject: [PATCH 369/443] [8.x] Add DB::resetRecordsModifications (#36617) * add DB::resetRecordsModifications * Update Connection.php Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Connection.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index b4fa6d4c3a0d..b2ded4c9aebb 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -867,6 +867,16 @@ public function recordsHaveBeenModified($value = true) } } + /** + * Reset the record modification state. + * + * @return void + */ + public function forgetRecordModificationState() + { + $this->recordsModified = false; + } + /** * Is Doctrine available? * From d3df83a537cfddbbb5df79a6b318d2053b44b700 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 16 Mar 2021 19:21:03 +0200 Subject: [PATCH 370/443] [6.x] update changelog --- CHANGELOG-6.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index b041da96c128..226fdd550d8a 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,12 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.18...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.19...6.x) + + +## [v6.20.19 (2021-03-16)](https://github.com/laravel/framework/compare/v6.20.18...v6.20.19) + +### Added +- Added broken pipe exception as lost connection error ([#36601](https://github.com/laravel/framework/pull/36601)) ## [v6.20.18 (2021-03-09)](https://github.com/laravel/framework/compare/v6.20.17...v6.20.18) From 9f986cef11b959679f530eb24d929b39a2690924 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 16 Mar 2021 19:40:07 +0200 Subject: [PATCH 371/443] [8.x] update changelog --- CHANGELOG-8.x.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index e5ca8f3668f8..399b85419411 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,26 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.32.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.33.0...8.x) + + +## [v8.33.0 (2021-03-16)](https://github.com/laravel/framework/compare/v8.32.1...v8.33.0) + +### Added +- Added broken pipe exception as lost connection error ([#36601](https://github.com/laravel/framework/pull/36601)) +- Added missing option to resource ([#36562](https://github.com/laravel/framework/pull/36562)) +- Introduce StringEncrypter interface ([#36578](https://github.com/laravel/framework/pull/36578)) + +### Fixed +- Fixed returns with Mail & Notification components ([#36559](https://github.com/laravel/framework/pull/36559)) +- Stack driver fix: respect the defined processors in LogManager ([#36591](https://github.com/laravel/framework/pull/36591)) +- Require the correct password to rehash it when logging out other devices ([#36608](https://github.com/laravel/framework/pull/36608), [1e61612](https://github.com/laravel/framework/commit/1e6161250074b8106c1fcf153eeaef7c0bf74c6c)) + +### Changed +- Allow nullable columns for `AsArrayObject/AsCollection` casts ([#36526](https://github.com/laravel/framework/pull/36526)) +- Accept callable class for reportable and renderable in exception handler ([#36551](https://github.com/laravel/framework/pull/36551)) +- Container - detect circular dependencies ([dd7274d](https://github.com/laravel/framework/commit/dd7274d23a9ee58cc1abdf7107403169a3994b68), [a712f72](https://github.com/laravel/framework/commit/a712f72ca88f709335576530b31635738abd4c89), [6f9bb4c](https://github.com/laravel/framework/commit/6f9bb4cdd84295cbcf7908cc4b4684f47f38b8cf)) +- Initialize CronExpression class using new keyword ([#36600](https://github.com/laravel/framework/pull/36600)) +- Use different config key for overriding temporary url host in AwsTemporaryUrl method ([#36612](https://github.com/laravel/framework/pull/36612)) ## [v8.32.1 (2021-03-09)](https://github.com/laravel/framework/compare/v8.32.0...v8.32.1) From f8423451c31215bfa83d0cd319ff3d016a83bdb3 Mon Sep 17 00:00:00 2001 From: JUNO_OKYO Date: Wed, 17 Mar 2021 01:27:50 +0700 Subject: [PATCH 372/443] Added "exclude-path" option --- src/Illuminate/Foundation/Console/RouteListCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index 46fbf5ff6256..c9844c6d81ce 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -187,6 +187,7 @@ protected function filterRoute(array $route) { if (($this->option('name') && ! Str::contains($route['name'], $this->option('name'))) || $this->option('path') && ! Str::contains($route['uri'], $this->option('path')) || + $this->option('exclude-path') && Str::contains($route['uri'], $this->option('exclude-path')) || $this->option('method') && ! Str::contains($route['method'], strtoupper($this->option('method')))) { return; } @@ -259,6 +260,7 @@ protected function getOptions() ['method', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by method'], ['name', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by name'], ['path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by path'], + ['exclude-path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by exclude path'], ['reverse', 'r', InputOption::VALUE_NONE, 'Reverse the ordering of the routes'], ['sort', null, InputOption::VALUE_OPTIONAL, 'The column (domain, method, uri, name, action, middleware) to sort by', 'uri'], ]; From 332844e5bde34f8db91aeca4d21cd4e0925d691e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Mar 2021 14:42:13 -0500 Subject: [PATCH 373/443] revert circular dep --- src/Illuminate/Container/Container.php | 6 +++--- tests/Container/ContainerTest.php | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 4ea378983d0d..642d1e082e6d 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -842,9 +842,9 @@ public function build($concrete) return $this->notInstantiable($concrete); } - if (in_array($concrete, $this->buildStack)) { - throw new CircularDependencyException("Circular dependency detected while resolving [{$concrete}]."); - } + // if (in_array($concrete, $this->buildStack)) { + // throw new CircularDependencyException("Circular dependency detected while resolving [{$concrete}]."); + // } $this->buildStack[] = $concrete; diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 39638694f802..eefe9366cbfc 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -564,13 +564,13 @@ public function testContainerCanResolveClasses() $this->assertInstanceOf(ContainerConcreteStub::class, $class); } - public function testContainerCanCatchCircularDependency() - { - $this->expectException(CircularDependencyException::class); + // public function testContainerCanCatchCircularDependency() + // { + // $this->expectException(CircularDependencyException::class); - $container = new Container; - $container->get(CircularAStub::class); - } + // $container = new Container; + // $container->get(CircularAStub::class); + // } } class CircularAStub From 354c57b8cb457549114074c500944455a288d6cc Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Mar 2021 14:42:32 -0500 Subject: [PATCH 374/443] patch --- 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 840265edce7b..cbd1cba90c73 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '8.33.0'; + const VERSION = '8.33.1'; /** * The base path for the Laravel installation. From a7ec58e55daa54568c45bd6b83754179dee950f6 Mon Sep 17 00:00:00 2001 From: Claudio Dekker <1752195+claudiodekker@users.noreply.github.com> Date: Tue, 16 Mar 2021 22:41:43 +0100 Subject: [PATCH 375/443] [8.x] Adjust Fluent Assertions (#36620) * Adjust Fluent Assertions - Add `first` scoping method - Allow `has(3)` to count the current scope - Expose `count` method publicly * Skip interaction check when top-level is non-associative * Test: Remove redundant `etc` call * Fix broken test --- .../Testing/Fluent/AssertableJson.php | 28 +++- .../Testing/Fluent/Concerns/Has.php | 76 ++++++--- .../Testing/Fluent/Concerns/Matching.php | 2 +- src/Illuminate/Testing/TestResponse.php | 2 +- tests/Testing/Fluent/AssertTest.php | 150 +++++++++++++++++- tests/Testing/TestResponseTest.php | 20 ++- 6 files changed, 242 insertions(+), 36 deletions(-) diff --git a/src/Illuminate/Testing/Fluent/AssertableJson.php b/src/Illuminate/Testing/Fluent/AssertableJson.php index 07104e114990..3d2496fac71b 100644 --- a/src/Illuminate/Testing/Fluent/AssertableJson.php +++ b/src/Illuminate/Testing/Fluent/AssertableJson.php @@ -52,13 +52,13 @@ protected function __construct(array $props, string $path = null) * @param string $key * @return string */ - protected function dotPath(string $key): string + protected function dotPath(string $key = ''): string { if (is_null($this->path)) { return $key; } - return implode('.', [$this->path, $key]); + return rtrim(implode('.', [$this->path, $key]), '.'); } /** @@ -93,6 +93,30 @@ protected function scope(string $key, Closure $callback): self return $this; } + /** + * Instantiate a new "scope" on the first child element. + * + * @param \Closure $callback + * @return $this + */ + public function first(Closure $callback): self + { + $props = $this->prop(); + + $path = $this->dotPath(); + + PHPUnit::assertNotEmpty($props, $path === '' + ? 'Cannot scope directly onto the first element of the root level because it is empty.' + : sprintf('Cannot scope directly onto the first element of property [%s] because it is empty.', $path) + ); + + $key = array_keys($props)[0]; + + $this->interactsWith($key); + + return $this->scope($key, $callback); + } + /** * Create a new instance from an array. * diff --git a/src/Illuminate/Testing/Fluent/Concerns/Has.php b/src/Illuminate/Testing/Fluent/Concerns/Has.php index dd91ee618790..979b9afa3625 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Has.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -11,12 +11,26 @@ trait Has /** * Assert that the prop is of the expected size. * - * @param string $key - * @param int $length + * @param string|int $key + * @param int|null $length * @return $this */ - protected function count(string $key, int $length): self + public function count($key, int $length = null): self { + if (is_null($length)) { + $path = $this->dotPath(); + + PHPUnit::assertCount( + $key, + $this->prop(), + $path + ? sprintf('Property [%s] does not have the expected size.', $path) + : sprintf('Root level does not have the expected size.') + ); + + return $this; + } + PHPUnit::assertCount( $length, $this->prop($key), @@ -29,15 +43,19 @@ protected function count(string $key, int $length): self /** * Ensure that the given prop exists. * - * @param string $key - * @param null $value - * @param \Closure|null $scope + * @param string|int $key + * @param int|\Closure|null $length + * @param \Closure|null $callback * @return $this */ - public function has(string $key, $value = null, Closure $scope = null): self + public function has($key, $length = null, Closure $callback = null): self { $prop = $this->prop(); + if (is_int($key) && is_null($length)) { + return $this->count($key); + } + PHPUnit::assertTrue( Arr::has($prop, $key), sprintf('Property [%s] does not exist.', $this->dotPath($key)) @@ -45,25 +63,20 @@ public function has(string $key, $value = null, Closure $scope = null): self $this->interactsWith($key); - // When all three arguments are provided this indicates a short-hand expression - // that combines both a `count`-assertion, followed by directly creating the - // `scope` on the first element. We can simply handle this correctly here. - if (is_int($value) && ! is_null($scope)) { - $prop = $this->prop($key); - $path = $this->dotPath($key); - - PHPUnit::assertTrue($value > 0, sprintf('Cannot scope directly onto the first entry of property [%s] when asserting that it has a size of 0.', $path)); - PHPUnit::assertIsArray($prop, sprintf('Direct scoping is unsupported for non-array like properties such as [%s].', $path)); - - $this->count($key, $value); + if (is_int($length) && ! is_null($callback)) { + return $this->has($key, function (self $scope) use ($length, $callback) { + return $scope->count($length) + ->first($callback) + ->etc(); + }); + } - return $this->scope($key.'.'.array_keys($prop)[0], $scope); + if (is_callable($length)) { + return $this->scope($key, $length); } - if (is_callable($value)) { - $this->scope($key, $value); - } elseif (! is_null($value)) { - $this->count($key, $value); + if (! is_null($length)) { + return $this->count($key, $length); } return $this; @@ -129,7 +142,7 @@ public function missing(string $key): self * @param string $key * @return string */ - abstract protected function dotPath(string $key): string; + abstract protected function dotPath(string $key = ''): string; /** * Marks the property as interacted. @@ -155,4 +168,19 @@ abstract protected function prop(string $key = null); * @return $this */ abstract protected function scope(string $key, Closure $callback); + + /** + * Disables the interaction check. + * + * @return $this + */ + abstract public function etc(); + + /** + * Instantiate a new "scope" on the first element. + * + * @param \Closure $callback + * @return $this + */ + abstract public function first(Closure $callback); } diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php index 3cf1f82c471c..f64519023e43 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -87,7 +87,7 @@ protected function ensureSorted(&$value): void * @param string $key * @return string */ - abstract protected function dotPath(string $key): string; + abstract protected function dotPath(string $key = ''): string; /** * Ensure that the given prop exists. diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index aeee4fe59c7e..1d46a0ac5284 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -523,7 +523,7 @@ public function assertJson($value, $strict = false) $value($assert); - if ($strict) { + if (Arr::isAssoc($assert->toArray())) { $assert->interacted(); } } diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php index acafd07589d2..20e03785a037 100644 --- a/tests/Testing/Fluent/AssertTest.php +++ b/tests/Testing/Fluent/AssertTest.php @@ -58,7 +58,7 @@ public function testAssertHasFailsWhenNestedPropMissing() $assert->has('example.another'); } - public function testAssertCountItemsInProp() + public function testAssertHasCountItemsInProp() { $assert = AssertableJson::fromArray([ 'bar' => [ @@ -70,7 +70,7 @@ public function testAssertCountItemsInProp() $assert->has('bar', 2); } - public function testAssertCountFailsWhenAmountOfItemsDoesNotMatch() + public function testAssertHasCountFailsWhenAmountOfItemsDoesNotMatch() { $assert = AssertableJson::fromArray([ 'bar' => [ @@ -85,7 +85,7 @@ public function testAssertCountFailsWhenAmountOfItemsDoesNotMatch() $assert->has('bar', 1); } - public function testAssertCountFailsWhenPropMissing() + public function testAssertHasCountFailsWhenPropMissing() { $assert = AssertableJson::fromArray([ 'bar' => [ @@ -111,6 +111,90 @@ public function testAssertHasFailsWhenSecondArgumentUnsupportedType() $assert->has('bar', 'invalid'); } + public function testAssertHasOnlyCounts() + { + $assert = AssertableJson::fromArray([ + 'foo', + 'bar', + 'baz', + ]); + + $assert->has(3); + } + + public function testAssertHasOnlyCountFails() + { + $assert = AssertableJson::fromArray([ + 'foo', + 'bar', + 'baz', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Root level does not have the expected size.'); + + $assert->has(2); + } + + public function testAssertHasOnlyCountFailsScoped() + { + $assert = AssertableJson::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] does not have the expected size.'); + + $assert->has('bar', function ($bar) { + $bar->has(3); + }); + } + + public function testAssertCount() + { + $assert = AssertableJson::fromArray([ + 'foo', + 'bar', + 'baz', + ]); + + $assert->count(3); + } + + public function testAssertCountFails() + { + $assert = AssertableJson::fromArray([ + 'foo', + 'bar', + 'baz', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Root level does not have the expected size.'); + + $assert->count(2); + } + + public function testAssertCountFailsScoped() + { + $assert = AssertableJson::fromArray([ + 'bar' => [ + 'baz' => 'example', + 'prop' => 'value', + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] does not have the expected size.'); + + $assert->has('bar', function ($bar) { + $bar->count(3); + }); + } + public function testAssertMissing() { $assert = AssertableJson::fromArray([ @@ -421,7 +505,7 @@ public function testScopeShorthandFailsWhenAssertingZeroItems() ]); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('Cannot scope directly onto the first entry of property [bar] when asserting that it has a size of 0.'); + $this->expectExceptionMessage('Property [bar] does not have the expected size.'); $assert->has('bar', 0, function (AssertableJson $item) { $item->where('key', 'first'); @@ -445,6 +529,64 @@ public function testScopeShorthandFailsWhenAmountOfItemsDoesNotMatch() }); } + public function testFirstScope() + { + $assert = AssertableJson::fromArray([ + 'foo' => [ + 'key' => 'first', + ], + 'bar' => [ + 'key' => 'second', + ], + ]); + + $assert->first(function (AssertableJson $item) { + $item->where('key', 'first'); + }); + } + + public function testFirstScopeFailsWhenNoProps() + { + $assert = AssertableJson::fromArray([]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Cannot scope directly onto the first element of the root level because it is empty.'); + + $assert->first(function (AssertableJson $item) { + // + }); + } + + public function testFirstNestedScopeFailsWhenNoProps() + { + $assert = AssertableJson::fromArray([ + 'foo' => [], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Cannot scope directly onto the first element of property [foo] because it is empty.'); + + $assert->has('foo', function (AssertableJson $assert) { + $assert->first(function (AssertableJson $item) { + // + }); + }); + } + + public function testFirstScopeFailsWhenPropSingleValue() + { + $assert = AssertableJson::fromArray([ + 'foo' => 'bar', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo] is not scopeable.'); + + $assert->first(function (AssertableJson $item) { + // + }); + } + public function testFailsWhenNotInteractingWithAllPropsInScope() { $assert = AssertableJson::fromArray([ diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index b6a1e5531a54..f35f13121e1e 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -587,16 +587,28 @@ public function testAssertJsonWithFluent() }); } - public function testAssertJsonWithFluentStrict() + public function testAssertJsonWithFluentFailsWhenNotInteractingWithAllProps() { - $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableSingleResourceStub)); + $response = TestResponse::fromBaseResponse(new Response(new JsonSerializableMixedResourcesStub)); $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage('Unexpected properties were found on the root level.'); $response->assertJson(function (AssertableJson $json) { - $json->where('0.foo', 'foo 0'); - }, true); + $json->where('foo', 'bar'); + }); + } + + public function testAssertJsonWithFluentSkipsInteractionWhenTopLevelKeysNonAssociative() + { + $response = TestResponse::fromBaseResponse(new Response([ + ['foo' => 'bar'], + ['foo' => 'baz'], + ])); + + $response->assertJson(function (AssertableJson $json) { + // + }); } public function testAssertSimilarJsonWithMixed() From 52edf7d3ecd1193e56e073b63aa93e79d8cd5b5c Mon Sep 17 00:00:00 2001 From: Lito Date: Tue, 16 Mar 2021 22:53:44 +0100 Subject: [PATCH 376/443] Added timestamp reference to schedule:work artisan command output (#36621) --- src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php b/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php index ec296ebd4972..f30a2f0c9086 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleWorkCommand.php @@ -51,7 +51,7 @@ public function handle() if (! empty($output)) { if ($key !== $keyOfLastExecutionWithOutput) { - $this->info(PHP_EOL.'Execution #'.($key + 1).' output:'); + $this->info(PHP_EOL.'['.date('c').'] Execution #'.($key + 1).' output:'); $keyOfLastExecutionWithOutput = $key; } From 0a89a875066feee39bfd363edb934f54208f1815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Dorn?= Date: Wed, 17 Mar 2021 13:44:34 +0100 Subject: [PATCH 377/443] formatting (#36623) spacing --- src/Illuminate/Session/Middleware/StartSession.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index c702d920473b..e7d2daa22315 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -59,9 +59,9 @@ public function handle($request, Closure $next) if ($this->manager->shouldBlock() || ($request->route() instanceof Route && $request->route()->locksFor())) { return $this->handleRequestWhileBlocking($request, $session, $next); - } else { - return $this->handleStatefulRequest($request, $session, $next); } + + return $this->handleStatefulRequest($request, $session, $next); } /** From 9d801898feff53bdc65529752e70be3dd31f9954 Mon Sep 17 00:00:00 2001 From: Dave Shoreman Date: Wed, 17 Mar 2021 12:44:55 +0000 Subject: [PATCH 378/443] Fix replacing required :input with null on PHP 8.1 (#36622) Fixes an issue where data lacking one or more of the fields under validation will cause tests to fail with an `ErrorException`. That exception is a PHP deprecation warning triggered by the call to `str_replace()` inside `replaceInputPlaceholder()`, which assumes the value returned from `getDisplayableValue()` will always be a string. --- src/Illuminate/Validation/Concerns/FormatsMessages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/FormatsMessages.php b/src/Illuminate/Validation/Concerns/FormatsMessages.php index 39d102a331ba..f433a5361eec 100644 --- a/src/Illuminate/Validation/Concerns/FormatsMessages.php +++ b/src/Illuminate/Validation/Concerns/FormatsMessages.php @@ -336,7 +336,7 @@ public function getDisplayableValue($attribute, $value) return $value ? 'true' : 'false'; } - return $value; + return (string) $value; } /** From 76e11ee97fc8068be1d55986b4524d4c329af387 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 17 Mar 2021 07:49:06 -0500 Subject: [PATCH 379/443] formatting --- .../Foundation/Console/RouteListCommand.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index c9844c6d81ce..8a24c5dfb8bc 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -187,11 +187,18 @@ protected function filterRoute(array $route) { if (($this->option('name') && ! Str::contains($route['name'], $this->option('name'))) || $this->option('path') && ! Str::contains($route['uri'], $this->option('path')) || - $this->option('exclude-path') && Str::contains($route['uri'], $this->option('exclude-path')) || $this->option('method') && ! Str::contains($route['method'], strtoupper($this->option('method')))) { return; } + if ($this->option('except-path')) { + foreach (explode(',', $this->option('except-path')) as $path) { + if (Str::contains($route['uri'], $path)) { + return; + } + } + } + return $route; } @@ -259,8 +266,8 @@ protected function getOptions() ['json', null, InputOption::VALUE_NONE, 'Output the route list as JSON'], ['method', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by method'], ['name', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by name'], - ['path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by path'], - ['exclude-path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by exclude path'], + ['path', null, InputOption::VALUE_OPTIONAL, 'Only show routes matching the given path pattern'], + ['except-path', null, InputOption::VALUE_OPTIONAL, 'Do not display the routes matching the given path pattern'], ['reverse', 'r', InputOption::VALUE_NONE, 'Reverse the ordering of the routes'], ['sort', null, InputOption::VALUE_OPTIONAL, 'The column (domain, method, uri, name, action, middleware) to sort by', 'uri'], ]; From cef1dc13c07c85a832dcb53cff2be90e3f0c59d2 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 17 Mar 2021 20:27:03 +0000 Subject: [PATCH 380/443] Adds `Str::remove` and `Str::of('foobar')->remove` methods --- src/Illuminate/Support/Str.php | 12 ++++++++++++ src/Illuminate/Support/Stringable.php | 11 +++++++++++ tests/Support/SupportStrTest.php | 8 ++++++++ tests/Support/SupportStringableTest.php | 9 +++++++++ 4 files changed, 40 insertions(+) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index c1ea0017b782..e2d3fb4bc530 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -491,6 +491,18 @@ public static function random($length = 16) return $string; } + /** + * Remove any occurrence of the given string in the subject. + * + * @param string $search + * @param string $subject + * @return string + */ + public static function remove($search, $subject) + { + return str_replace($search, "", $subject); + } + /** * Replace a given value in the string sequentially with an array. * diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index d834260e11cf..c66d3044dc3a 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -467,6 +467,17 @@ public function prepend(...$values) return new static(implode('', $values).$this->value); } + /** + * Remove any occurrence of the given string in the subject. + * + * @param string $search + * @return static + */ + public function remove($search) + { + return new static(Str::remove($search, $this->value)); + } + /** * Replace the given value in the given string. * diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index f873e3bd934d..81bb6ccf0903 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -365,6 +365,14 @@ public function testReplaceLast() $this->assertSame('Malmö Jönköping', Str::replaceLast('', 'yyy', 'Malmö Jönköping')); } + public function testRemove() + { + $this->assertSame("Fbar", Str::remove('o', 'Foobar')); + $this->assertSame("Foo", Str::remove('bar', 'Foobar')); + $this->assertSame("oobar", Str::remove('F', 'Foobar')); + $this->assertSame("Foobar", Str::remove('f', 'Foobar')); + } + public function testSnake() { $this->assertSame('laravel_p_h_p_framework', Str::snake('LaravelPHPFramework')); diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index d6c010fd20fd..6477f2b31a1f 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Support; use Illuminate\Support\Collection; +use Illuminate\Support\Str; use Illuminate\Support\Stringable; use PHPUnit\Framework\TestCase; @@ -452,6 +453,14 @@ public function testReplaceLast() $this->assertSame('Malmö Jönköping', (string) $this->stringable('Malmö Jönköping')->replaceLast('', 'yyy')); } + public function testRemove() + { + $this->assertSame("Fbar", (string) $this->stringable('Foobar')->remove('o')); + $this->assertSame("Foo", (string) $this->stringable('Foobar')->remove('bar')); + $this->assertSame("oobar", (string) $this->stringable('Foobar')->remove('F')); + $this->assertSame("Foobar", (string) $this->stringable('Foobar')->remove('f')); + } + public function testSnake() { $this->assertSame('laravel_p_h_p_framework', (string) $this->stringable('LaravelPHPFramework')->snake()); From 1f64f7aaf351a6a87a1b2db95a88fb94206ce9c5 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 17 Mar 2021 20:50:59 +0000 Subject: [PATCH 381/443] Adds case insensitivity support. --- src/Illuminate/Support/Str.php | 9 ++++++--- src/Illuminate/Support/Stringable.php | 7 ++++--- tests/Support/SupportStrTest.php | 5 +++++ tests/Support/SupportStringableTest.php | 5 +++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index e2d3fb4bc530..ff923d46419e 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -494,13 +494,16 @@ public static function random($length = 16) /** * Remove any occurrence of the given string in the subject. * - * @param string $search + * @param string|array $search * @param string $subject + * @param bool $caseSensitive * @return string */ - public static function remove($search, $subject) + public static function remove($search, $subject, $caseSensitive = true) { - return str_replace($search, "", $subject); + $search = is_array($search) ? implode("|", $search) : $search; + $regex = $caseSensitive ? "/$search/" : "/$search/i"; + return preg_replace($regex, "", $subject); } /** diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index c66d3044dc3a..29e62b89eca6 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -470,12 +470,13 @@ public function prepend(...$values) /** * Remove any occurrence of the given string in the subject. * - * @param string $search + * @param string|array $search + * @param bool $caseSensitive * @return static */ - public function remove($search) + public function remove($search, $caseSensitive = true) { - return new static(Str::remove($search, $this->value)); + return new static(Str::remove($search, $this->value, $caseSensitive)); } /** diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 81bb6ccf0903..d6a26b48607e 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -371,6 +371,11 @@ public function testRemove() $this->assertSame("Foo", Str::remove('bar', 'Foobar')); $this->assertSame("oobar", Str::remove('F', 'Foobar')); $this->assertSame("Foobar", Str::remove('f', 'Foobar')); + $this->assertSame("oobar", Str::remove('f', 'Foobar', false)); + + $this->assertSame("Fbr", Str::remove(["o", "a"], 'Foobar')); + $this->assertSame("Fooar", Str::remove(["f", "b"], 'Foobar')); + $this->assertSame("ooar", Str::remove(["f", "b"], 'Foobar', false)); } public function testSnake() diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 6477f2b31a1f..89fe1fb9c000 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -459,6 +459,11 @@ public function testRemove() $this->assertSame("Foo", (string) $this->stringable('Foobar')->remove('bar')); $this->assertSame("oobar", (string) $this->stringable('Foobar')->remove('F')); $this->assertSame("Foobar", (string) $this->stringable('Foobar')->remove('f')); + $this->assertSame("oobar", (string) $this->stringable('Foobar')->remove('f', false)); + + $this->assertSame("Fbr", (string) $this->stringable('Foobar')->remove(["o", "a"])); + $this->assertSame("Fooar", (string) $this->stringable('Foobar')->remove(["f", "b"])); + $this->assertSame("ooar", (string) $this->stringable('Foobar')->remove(["f", "b"], false)); } public function testSnake() From e87398a594b2f93d10f51036aa16f4c81077035f Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 17 Mar 2021 21:03:50 +0000 Subject: [PATCH 382/443] Adds regex case insensitivity. --- src/Illuminate/Support/Str.php | 473 ++++++++++++------------ tests/Support/SupportStrTest.php | 1 + tests/Support/SupportStringableTest.php | 1 + 3 files changed, 246 insertions(+), 229 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index ff923d46419e..17e5e29e501c 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -45,7 +45,7 @@ class Str /** * Get a new stringable object from the given string. * - * @param string $string + * @param string $string * @return \Illuminate\Support\Stringable */ public static function of($string) @@ -53,23 +53,11 @@ public static function of($string) return new Stringable($string); } - /** - * Return the remainder of a string after the first occurrence of a given value. - * - * @param string $subject - * @param string $search - * @return string - */ - public static function after($subject, $search) - { - return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0]; - } - /** * Return the remainder of a string after the last occurrence of a given value. * - * @param string $subject - * @param string $search + * @param string $subject + * @param string $search * @return string */ public static function afterLast($subject, $search) @@ -78,7 +66,7 @@ public static function afterLast($subject, $search) return $subject; } - $position = strrpos($subject, (string) $search); + $position = strrpos($subject, (string)$search); if ($position === false) { return $subject; @@ -88,40 +76,45 @@ public static function afterLast($subject, $search) } /** - * Transliterate a UTF-8 value to ASCII. + * Get the portion of a string before the first occurrence of a given value. * - * @param string $value - * @param string $language + * @param string $subject + * @param string $search * @return string */ - public static function ascii($value, $language = 'en') + public static function before($subject, $search) { - return ASCII::to_ascii((string) $value, $language); + if ($search === '') { + return $subject; + } + + $result = strstr($subject, (string)$search, true); + + return $result === false ? $subject : $result; } /** - * Get the portion of a string before the first occurrence of a given value. + * Get the portion of a string between two given values. * - * @param string $subject - * @param string $search + * @param string $subject + * @param string $from + * @param string $to * @return string */ - public static function before($subject, $search) + public static function between($subject, $from, $to) { - if ($search === '') { + if ($from === '' || $to === '') { return $subject; } - $result = strstr($subject, (string) $search, true); - - return $result === false ? $subject : $result; + return static::beforeLast(static::after($subject, $from), $to); } /** * Get the portion of a string before the last occurrence of a given value. * - * @param string $subject - * @param string $search + * @param string $subject + * @param string $search * @return string */ public static function beforeLast($subject, $search) @@ -140,26 +133,34 @@ public static function beforeLast($subject, $search) } /** - * Get the portion of a string between two given values. + * Returns the portion of the string specified by the start and length parameters. * - * @param string $subject - * @param string $from - * @param string $to + * @param string $string + * @param int $start + * @param int|null $length * @return string */ - public static function between($subject, $from, $to) + public static function substr($string, $start, $length = null) { - if ($from === '' || $to === '') { - return $subject; - } + return mb_substr($string, $start, $length, 'UTF-8'); + } - return static::beforeLast(static::after($subject, $from), $to); + /** + * Return the remainder of a string after the first occurrence of a given value. + * + * @param string $subject + * @param string $search + * @return string + */ + public static function after($subject, $search) + { + return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0]; } /** * Convert a value to camel case. * - * @param string $value + * @param string $value * @return string */ public static function camel($value) @@ -172,34 +173,35 @@ public static function camel($value) } /** - * Determine if a given string contains a given substring. + * Convert a value to studly caps case. * - * @param string $haystack - * @param string|string[] $needles - * @return bool + * @param string $value + * @return string */ - public static function contains($haystack, $needles) + public static function studly($value) { - foreach ((array) $needles as $needle) { - if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { - return true; - } + $key = $value; + + if (isset(static::$studlyCache[$key])) { + return static::$studlyCache[$key]; } - return false; + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + + return static::$studlyCache[$key] = str_replace(' ', '', $value); } /** * Determine if a given string contains all array values. * - * @param string $haystack - * @param string[] $needles + * @param string $haystack + * @param string[] $needles * @return bool */ public static function containsAll($haystack, array $needles) { foreach ($needles as $needle) { - if (! static::contains($haystack, $needle)) { + if (!static::contains($haystack, $needle)) { return false; } } @@ -207,17 +209,35 @@ public static function containsAll($haystack, array $needles) return true; } + /** + * Determine if a given string contains a given substring. + * + * @param string $haystack + * @param string|string[] $needles + * @return bool + */ + public static function contains($haystack, $needles) + { + foreach ((array)$needles as $needle) { + if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { + return true; + } + } + + return false; + } + /** * Determine if a given string ends with a given substring. * - * @param string $haystack - * @param string|string[] $needles + * @param string $haystack + * @param string|string[] $needles * @return bool */ public static function endsWith($haystack, $needles) { - foreach ((array) $needles as $needle) { - if ($needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle) { + foreach ((array)$needles as $needle) { + if ($needle !== '' && substr($haystack, -strlen($needle)) === (string)$needle) { return true; } } @@ -228,22 +248,22 @@ public static function endsWith($haystack, $needles) /** * Cap a string with a single instance of a given value. * - * @param string $value - * @param string $cap + * @param string $value + * @param string $cap * @return string */ public static function finish($value, $cap) { $quoted = preg_quote($cap, '/'); - return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap; + return preg_replace('/(?:' . $quoted . ')+$/u', '', $value) . $cap; } /** * Determine if a given string matches a given pattern. * - * @param string|array $pattern - * @param string $value + * @param string|array $pattern + * @param string $value * @return bool */ public static function is($pattern, $value) @@ -269,7 +289,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#u', $value) === 1) { return true; } } @@ -280,23 +300,23 @@ public static function is($pattern, $value) /** * Determine if a given string is 7 bit ASCII. * - * @param string $value + * @param string $value * @return bool */ public static function isAscii($value) { - return ASCII::is_ascii((string) $value); + return ASCII::is_ascii((string)$value); } /** * Determine if a given string is a valid UUID. * - * @param string $value + * @param string $value * @return bool */ public static function isUuid($value) { - if (! is_string($value)) { + if (!is_string($value)) { return false; } @@ -306,7 +326,7 @@ public static function isUuid($value) /** * Convert a string to kebab case. * - * @param string $value + * @param string $value * @return string */ public static function kebab($value) @@ -315,27 +335,46 @@ public static function kebab($value) } /** - * Return the length of the given string. + * Convert a string to snake case. * - * @param string $value - * @param string|null $encoding - * @return int + * @param string $value + * @param string $delimiter + * @return string */ - public static function length($value, $encoding = null) + public static function snake($value, $delimiter = '_') { - if ($encoding) { - return mb_strlen($value, $encoding); + $key = $value; + + if (isset(static::$snakeCache[$key][$delimiter])) { + return static::$snakeCache[$key][$delimiter]; } - return mb_strlen($value); + if (!ctype_lower($value)) { + $value = preg_replace('/\s+/u', '', ucwords($value)); + + $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value)); + } + + return static::$snakeCache[$key][$delimiter] = $value; + } + + /** + * Convert the given string to lower-case. + * + * @param string $value + * @return string + */ + public static function lower($value) + { + return mb_strtolower($value, 'UTF-8'); } /** * Limit the number of characters in a string. * - * @param string $value - * @param int $limit - * @param string $end + * @param string $value + * @param int $limit + * @param string $end * @return string */ public static function limit($value, $limit = 100, $end = '...') @@ -344,44 +383,49 @@ public static function limit($value, $limit = 100, $end = '...') return $value; } - return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end; + return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')) . $end; } /** - * Convert the given string to lower-case. + * Limit the number of words in a string. * - * @param string $value + * @param string $value + * @param int $words + * @param string $end * @return string */ - public static function lower($value) + public static function words($value, $words = 100, $end = '...') { - return mb_strtolower($value, 'UTF-8'); + preg_match('/^\s*+(?:\S++\s*+){1,' . $words . '}/u', $value, $matches); + + if (!isset($matches[0]) || static::length($value) === static::length($matches[0])) { + return $value; + } + + return rtrim($matches[0]) . $end; } /** - * Limit the number of words in a string. + * Return the length of the given string. * - * @param string $value - * @param int $words - * @param string $end - * @return string + * @param string $value + * @param string|null $encoding + * @return int */ - public static function words($value, $words = 100, $end = '...') + public static function length($value, $encoding = null) { - preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches); - - if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) { - return $value; + if ($encoding) { + return mb_strlen($value, $encoding); } - return rtrim($matches[0]).$end; + return mb_strlen($value); } /** * Converts GitHub flavored Markdown into HTML. * - * @param string $string - * @param array $options + * @param string $string + * @param array $options * @return string */ public static function markdown($string, array $options = []) @@ -394,9 +438,9 @@ public static function markdown($string, array $options = []) /** * Pad both sides of a string with another. * - * @param string $value - * @param int $length - * @param string $pad + * @param string $value + * @param int $length + * @param string $pad * @return string */ public static function padBoth($value, $length, $pad = ' ') @@ -407,9 +451,9 @@ public static function padBoth($value, $length, $pad = ' ') /** * Pad the left side of a string with another. * - * @param string $value - * @param int $length - * @param string $pad + * @param string $value + * @param int $length + * @param string $pad * @return string */ public static function padLeft($value, $length, $pad = ' ') @@ -420,9 +464,9 @@ public static function padLeft($value, $length, $pad = ' ') /** * Pad the right side of a string with another. * - * @param string $value - * @param int $length - * @param string $pad + * @param string $value + * @param int $length + * @param string $pad * @return string */ public static function padRight($value, $length, $pad = ' ') @@ -433,8 +477,8 @@ public static function padRight($value, $length, $pad = ' ') /** * Parse a Class[@]method style callback into class and method. * - * @param string $callback - * @param string|null $default + * @param string $callback + * @param string|null $default * @return array */ public static function parseCallback($callback, $default = null) @@ -443,37 +487,37 @@ public static function parseCallback($callback, $default = null) } /** - * Get the plural form of an English word. + * Pluralize the last word of an English, studly caps case string. * - * @param string $value - * @param int $count + * @param string $value + * @param int $count * @return string */ - public static function plural($value, $count = 2) + public static function pluralStudly($value, $count = 2) { - return Pluralizer::plural($value, $count); + $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); + + $lastWord = array_pop($parts); + + return implode('', $parts) . self::plural($lastWord, $count); } /** - * Pluralize the last word of an English, studly caps case string. + * Get the plural form of an English word. * - * @param string $value - * @param int $count + * @param string $value + * @param int $count * @return string */ - public static function pluralStudly($value, $count = 2) + public static function plural($value, $count = 2) { - $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); - - $lastWord = array_pop($parts); - - return implode('', $parts).self::plural($lastWord, $count); + return Pluralizer::plural($value, $count); } /** * Generate a more truly "random" alpha-numeric string. * - * @param int $length + * @param int $length * @return string */ public static function random($length = 16) @@ -501,17 +545,28 @@ public static function random($length = 16) */ public static function remove($search, $subject, $caseSensitive = true) { - $search = is_array($search) ? implode("|", $search) : $search; - $regex = $caseSensitive ? "/$search/" : "/$search/i"; + $regexSafeSearches = array_map( + function ($search) { + return preg_quote($search); + }, + is_array($search) ? $search : [$search] + ); + + $regex = "/" . implode("|", $regexSafeSearches) . "/"; + + if (!$caseSensitive) { + $regex .= "i"; + } + return preg_replace($regex, "", $subject); } /** * Replace a given value in the string sequentially with an array. * - * @param string $search - * @param array $replace - * @param string $subject + * @param string $search + * @param array $replace + * @param string $subject * @return string */ public static function replaceArray($search, array $replace, $subject) @@ -521,7 +576,7 @@ public static function replaceArray($search, array $replace, $subject) $result = array_shift($segments); foreach ($segments as $segment) { - $result .= (array_shift($replace) ?? $search).$segment; + $result .= (array_shift($replace) ?? $search) . $segment; } return $result; @@ -530,9 +585,9 @@ public static function replaceArray($search, array $replace, $subject) /** * Replace the first occurrence of a given value in the string. * - * @param string $search - * @param string $replace - * @param string $subject + * @param string $search + * @param string $replace + * @param string $subject * @return string */ public static function replaceFirst($search, $replace, $subject) @@ -553,9 +608,9 @@ public static function replaceFirst($search, $replace, $subject) /** * Replace the last occurrence of a given value in the string. * - * @param string $search - * @param string $replace - * @param string $subject + * @param string $search + * @param string $replace + * @param string $subject * @return string */ public static function replaceLast($search, $replace, $subject) @@ -576,32 +631,21 @@ public static function replaceLast($search, $replace, $subject) /** * Begin a string with a single instance of a given value. * - * @param string $value - * @param string $prefix + * @param string $value + * @param string $prefix * @return string */ public static function start($value, $prefix) { $quoted = preg_quote($prefix, '/'); - return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value); - } - - /** - * Convert the given string to upper-case. - * - * @param string $value - * @return string - */ - public static function upper($value) - { - return mb_strtoupper($value, 'UTF-8'); + return $prefix . preg_replace('/^(?:' . $quoted . ')+/u', '', $value); } /** * Convert the given string to title case. * - * @param string $value + * @param string $value * @return string */ public static function title($value) @@ -612,7 +656,7 @@ public static function title($value) /** * Get the singular form of an English word. * - * @param string $value + * @param string $value * @return string */ public static function singular($value) @@ -623,9 +667,9 @@ public static function singular($value) /** * Generate a URL friendly "slug" from a given string. * - * @param string $title - * @param string $separator - * @param string|null $language + * @param string $title + * @param string $separator + * @param string|null $language * @return string */ public static function slug($title, $separator = '-', $language = 'en') @@ -635,55 +679,43 @@ public static function slug($title, $separator = '-', $language = 'en') // Convert all dashes/underscores into separator $flip = $separator === '-' ? '_' : '-'; - $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); + $title = preg_replace('![' . preg_quote($flip) . ']+!u', $separator, $title); // Replace @ with the word 'at' - $title = str_replace('@', $separator.'at'.$separator, $title); + $title = str_replace('@', $separator . 'at' . $separator, $title); // Remove all characters that are not the separator, letters, numbers, or whitespace. - $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', static::lower($title)); + $title = preg_replace('![^' . preg_quote($separator) . '\pL\pN\s]+!u', '', static::lower($title)); // Replace all separator characters and whitespace by a single separator - $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); + $title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title); return trim($title, $separator); } /** - * Convert a string to snake case. + * Transliterate a UTF-8 value to ASCII. * - * @param string $value - * @param string $delimiter + * @param string $value + * @param string $language * @return string */ - public static function snake($value, $delimiter = '_') + public static function ascii($value, $language = 'en') { - $key = $value; - - if (isset(static::$snakeCache[$key][$delimiter])) { - return static::$snakeCache[$key][$delimiter]; - } - - if (! ctype_lower($value)) { - $value = preg_replace('/\s+/u', '', ucwords($value)); - - $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); - } - - return static::$snakeCache[$key][$delimiter] = $value; + return ASCII::to_ascii((string)$value, $language); } /** * Determine if a given string starts with a given substring. * - * @param string $haystack - * @param string|string[] $needles + * @param string $haystack + * @param string|string[] $needles * @return bool */ public static function startsWith($haystack, $needles) { - foreach ((array) $needles as $needle) { - if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { + foreach ((array)$needles as $needle) { + if ((string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { return true; } } @@ -691,50 +723,18 @@ public static function startsWith($haystack, $needles) return false; } - /** - * Convert a value to studly caps case. - * - * @param string $value - * @return string - */ - public static function studly($value) - { - $key = $value; - - if (isset(static::$studlyCache[$key])) { - return static::$studlyCache[$key]; - } - - $value = ucwords(str_replace(['-', '_'], ' ', $value)); - - return static::$studlyCache[$key] = str_replace(' ', '', $value); - } - - /** - * Returns the portion of the string specified by the start and length parameters. - * - * @param string $string - * @param int $start - * @param int|null $length - * @return string - */ - public static function substr($string, $start, $length = null) - { - return mb_substr($string, $start, $length, 'UTF-8'); - } - /** * Returns the number of substring occurrences. * - * @param string $haystack - * @param string $needle - * @param int $offset - * @param int|null $length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int|null $length * @return int */ public static function substrCount($haystack, $needle, $offset = 0, $length = null) { - if (! is_null($length)) { + if (!is_null($length)) { return substr_count($haystack, $needle, $offset, $length); } else { return substr_count($haystack, $needle, $offset); @@ -744,12 +744,23 @@ public static function substrCount($haystack, $needle, $offset = 0, $length = nu /** * Make a string's first character uppercase. * - * @param string $string + * @param string $string * @return string */ public static function ucfirst($string) { - return static::upper(static::substr($string, 0, 1)).static::substr($string, 1); + return static::upper(static::substr($string, 0, 1)) . static::substr($string, 1); + } + + /** + * Convert the given string to upper-case. + * + * @param string $value + * @return string + */ + public static function upper($value) + { + return mb_strtoupper($value, 'UTF-8'); } /** @@ -760,8 +771,8 @@ public static function ucfirst($string) public static function uuid() { return static::$uuidFactory - ? call_user_func(static::$uuidFactory) - : Uuid::uuid4(); + ? call_user_func(static::$uuidFactory) + : Uuid::uuid4(); } /** @@ -777,14 +788,18 @@ public static function orderedUuid() $factory = new UuidFactory(); - $factory->setRandomGenerator(new CombGenerator( - $factory->getRandomGenerator(), - $factory->getNumberConverter() - )); + $factory->setRandomGenerator( + new CombGenerator( + $factory->getRandomGenerator(), + $factory->getNumberConverter() + ) + ); - $factory->setCodec(new TimestampFirstCombCodec( - $factory->getUuidBuilder() - )); + $factory->setCodec( + new TimestampFirstCombCodec( + $factory->getUuidBuilder() + ) + ); return $factory->uuid4(); } @@ -792,7 +807,7 @@ public static function orderedUuid() /** * Set the callable that will be used to generate UUIDs. * - * @param callable|null $factory + * @param callable|null $factory * @return void */ public static function createUuidsUsing(callable $factory = null) diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index d6a26b48607e..56b8fc1b853d 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -376,6 +376,7 @@ public function testRemove() $this->assertSame("Fbr", Str::remove(["o", "a"], 'Foobar')); $this->assertSame("Fooar", Str::remove(["f", "b"], 'Foobar')); $this->assertSame("ooar", Str::remove(["f", "b"], 'Foobar', false)); + $this->assertSame("Foobar", Str::remove(["f", "|"], 'Foo|bar')); } public function testSnake() diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 89fe1fb9c000..8cce8dc14498 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -464,6 +464,7 @@ public function testRemove() $this->assertSame("Fbr", (string) $this->stringable('Foobar')->remove(["o", "a"])); $this->assertSame("Fooar", (string) $this->stringable('Foobar')->remove(["f", "b"])); $this->assertSame("ooar", (string) $this->stringable('Foobar')->remove(["f", "b"], false)); + $this->assertSame("Foobar", (string) $this->stringable('Foo|bar')->remove(["f", "|"])); } public function testSnake() From 61fb05ded8c2d001dbfaf7426b60d1b916635330 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 17 Mar 2021 21:10:15 +0000 Subject: [PATCH 383/443] Formatting fix --- src/Illuminate/Support/Str.php | 510 ++++++++++++++++----------------- 1 file changed, 253 insertions(+), 257 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 17e5e29e501c..19363d65a935 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -45,7 +45,7 @@ class Str /** * Get a new stringable object from the given string. * - * @param string $string + * @param string $string * @return \Illuminate\Support\Stringable */ public static function of($string) @@ -53,11 +53,23 @@ public static function of($string) return new Stringable($string); } + /** + * Return the remainder of a string after the first occurrence of a given value. + * + * @param string $subject + * @param string $search + * @return string + */ + public static function after($subject, $search) + { + return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0]; + } + /** * Return the remainder of a string after the last occurrence of a given value. * - * @param string $subject - * @param string $search + * @param string $subject + * @param string $search * @return string */ public static function afterLast($subject, $search) @@ -66,7 +78,7 @@ public static function afterLast($subject, $search) return $subject; } - $position = strrpos($subject, (string)$search); + $position = strrpos($subject, (string) $search); if ($position === false) { return $subject; @@ -76,45 +88,40 @@ public static function afterLast($subject, $search) } /** - * Get the portion of a string before the first occurrence of a given value. + * Transliterate a UTF-8 value to ASCII. * - * @param string $subject - * @param string $search + * @param string $value + * @param string $language * @return string */ - public static function before($subject, $search) + public static function ascii($value, $language = 'en') { - if ($search === '') { - return $subject; - } - - $result = strstr($subject, (string)$search, true); - - return $result === false ? $subject : $result; + return ASCII::to_ascii((string) $value, $language); } /** - * Get the portion of a string between two given values. + * Get the portion of a string before the first occurrence of a given value. * - * @param string $subject - * @param string $from - * @param string $to + * @param string $subject + * @param string $search * @return string */ - public static function between($subject, $from, $to) + public static function before($subject, $search) { - if ($from === '' || $to === '') { + if ($search === '') { return $subject; } - return static::beforeLast(static::after($subject, $from), $to); + $result = strstr($subject, (string) $search, true); + + return $result === false ? $subject : $result; } /** * Get the portion of a string before the last occurrence of a given value. * - * @param string $subject - * @param string $search + * @param string $subject + * @param string $search * @return string */ public static function beforeLast($subject, $search) @@ -133,34 +140,26 @@ public static function beforeLast($subject, $search) } /** - * Returns the portion of the string specified by the start and length parameters. + * Get the portion of a string between two given values. * - * @param string $string - * @param int $start - * @param int|null $length + * @param string $subject + * @param string $from + * @param string $to * @return string */ - public static function substr($string, $start, $length = null) + public static function between($subject, $from, $to) { - return mb_substr($string, $start, $length, 'UTF-8'); - } + if ($from === '' || $to === '') { + return $subject; + } - /** - * Return the remainder of a string after the first occurrence of a given value. - * - * @param string $subject - * @param string $search - * @return string - */ - public static function after($subject, $search) - { - return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0]; + return static::beforeLast(static::after($subject, $from), $to); } /** * Convert a value to camel case. * - * @param string $value + * @param string $value * @return string */ public static function camel($value) @@ -173,35 +172,34 @@ public static function camel($value) } /** - * Convert a value to studly caps case. + * Determine if a given string contains a given substring. * - * @param string $value - * @return string + * @param string $haystack + * @param string|string[] $needles + * @return bool */ - public static function studly($value) + public static function contains($haystack, $needles) { - $key = $value; - - if (isset(static::$studlyCache[$key])) { - return static::$studlyCache[$key]; + foreach ((array) $needles as $needle) { + if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { + return true; + } } - $value = ucwords(str_replace(['-', '_'], ' ', $value)); - - return static::$studlyCache[$key] = str_replace(' ', '', $value); + return false; } /** * Determine if a given string contains all array values. * - * @param string $haystack - * @param string[] $needles + * @param string $haystack + * @param string[] $needles * @return bool */ public static function containsAll($haystack, array $needles) { foreach ($needles as $needle) { - if (!static::contains($haystack, $needle)) { + if (! static::contains($haystack, $needle)) { return false; } } @@ -209,35 +207,17 @@ public static function containsAll($haystack, array $needles) return true; } - /** - * Determine if a given string contains a given substring. - * - * @param string $haystack - * @param string|string[] $needles - * @return bool - */ - public static function contains($haystack, $needles) - { - foreach ((array)$needles as $needle) { - if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { - return true; - } - } - - return false; - } - /** * Determine if a given string ends with a given substring. * - * @param string $haystack - * @param string|string[] $needles + * @param string $haystack + * @param string|string[] $needles * @return bool */ public static function endsWith($haystack, $needles) { - foreach ((array)$needles as $needle) { - if ($needle !== '' && substr($haystack, -strlen($needle)) === (string)$needle) { + foreach ((array) $needles as $needle) { + if ($needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle) { return true; } } @@ -248,22 +228,22 @@ public static function endsWith($haystack, $needles) /** * Cap a string with a single instance of a given value. * - * @param string $value - * @param string $cap + * @param string $value + * @param string $cap * @return string */ public static function finish($value, $cap) { $quoted = preg_quote($cap, '/'); - return preg_replace('/(?:' . $quoted . ')+$/u', '', $value) . $cap; + return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap; } /** * Determine if a given string matches a given pattern. * - * @param string|array $pattern - * @param string $value + * @param string|array $pattern + * @param string $value * @return bool */ public static function is($pattern, $value) @@ -289,7 +269,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#u', $value) === 1) { return true; } } @@ -300,23 +280,23 @@ public static function is($pattern, $value) /** * Determine if a given string is 7 bit ASCII. * - * @param string $value + * @param string $value * @return bool */ public static function isAscii($value) { - return ASCII::is_ascii((string)$value); + return ASCII::is_ascii((string) $value); } /** * Determine if a given string is a valid UUID. * - * @param string $value + * @param string $value * @return bool */ public static function isUuid($value) { - if (!is_string($value)) { + if (! is_string($value)) { return false; } @@ -326,7 +306,7 @@ public static function isUuid($value) /** * Convert a string to kebab case. * - * @param string $value + * @param string $value * @return string */ public static function kebab($value) @@ -335,46 +315,27 @@ public static function kebab($value) } /** - * Convert a string to snake case. + * Return the length of the given string. * - * @param string $value - * @param string $delimiter - * @return string + * @param string $value + * @param string|null $encoding + * @return int */ - public static function snake($value, $delimiter = '_') + public static function length($value, $encoding = null) { - $key = $value; - - if (isset(static::$snakeCache[$key][$delimiter])) { - return static::$snakeCache[$key][$delimiter]; - } - - if (!ctype_lower($value)) { - $value = preg_replace('/\s+/u', '', ucwords($value)); - - $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value)); + if ($encoding) { + return mb_strlen($value, $encoding); } - return static::$snakeCache[$key][$delimiter] = $value; - } - - /** - * Convert the given string to lower-case. - * - * @param string $value - * @return string - */ - public static function lower($value) - { - return mb_strtolower($value, 'UTF-8'); + return mb_strlen($value); } /** * Limit the number of characters in a string. * - * @param string $value - * @param int $limit - * @param string $end + * @param string $value + * @param int $limit + * @param string $end * @return string */ public static function limit($value, $limit = 100, $end = '...') @@ -383,49 +344,44 @@ public static function limit($value, $limit = 100, $end = '...') return $value; } - return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')) . $end; + return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end; } /** - * Limit the number of words in a string. + * Convert the given string to lower-case. * - * @param string $value - * @param int $words - * @param string $end + * @param string $value * @return string */ - public static function words($value, $words = 100, $end = '...') + public static function lower($value) { - preg_match('/^\s*+(?:\S++\s*+){1,' . $words . '}/u', $value, $matches); - - if (!isset($matches[0]) || static::length($value) === static::length($matches[0])) { - return $value; - } - - return rtrim($matches[0]) . $end; + return mb_strtolower($value, 'UTF-8'); } /** - * Return the length of the given string. + * Limit the number of words in a string. * - * @param string $value - * @param string|null $encoding - * @return int + * @param string $value + * @param int $words + * @param string $end + * @return string */ - public static function length($value, $encoding = null) + public static function words($value, $words = 100, $end = '...') { - if ($encoding) { - return mb_strlen($value, $encoding); + preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches); + + if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) { + return $value; } - return mb_strlen($value); + return rtrim($matches[0]).$end; } /** * Converts GitHub flavored Markdown into HTML. * - * @param string $string - * @param array $options + * @param string $string + * @param array $options * @return string */ public static function markdown($string, array $options = []) @@ -438,9 +394,9 @@ public static function markdown($string, array $options = []) /** * Pad both sides of a string with another. * - * @param string $value - * @param int $length - * @param string $pad + * @param string $value + * @param int $length + * @param string $pad * @return string */ public static function padBoth($value, $length, $pad = ' ') @@ -451,9 +407,9 @@ public static function padBoth($value, $length, $pad = ' ') /** * Pad the left side of a string with another. * - * @param string $value - * @param int $length - * @param string $pad + * @param string $value + * @param int $length + * @param string $pad * @return string */ public static function padLeft($value, $length, $pad = ' ') @@ -464,9 +420,9 @@ public static function padLeft($value, $length, $pad = ' ') /** * Pad the right side of a string with another. * - * @param string $value - * @param int $length - * @param string $pad + * @param string $value + * @param int $length + * @param string $pad * @return string */ public static function padRight($value, $length, $pad = ' ') @@ -477,8 +433,8 @@ public static function padRight($value, $length, $pad = ' ') /** * Parse a Class[@]method style callback into class and method. * - * @param string $callback - * @param string|null $default + * @param string $callback + * @param string|null $default * @return array */ public static function parseCallback($callback, $default = null) @@ -487,37 +443,37 @@ public static function parseCallback($callback, $default = null) } /** - * Pluralize the last word of an English, studly caps case string. + * Get the plural form of an English word. * - * @param string $value - * @param int $count + * @param string $value + * @param int $count * @return string */ - public static function pluralStudly($value, $count = 2) + public static function plural($value, $count = 2) { - $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); - - $lastWord = array_pop($parts); - - return implode('', $parts) . self::plural($lastWord, $count); + return Pluralizer::plural($value, $count); } /** - * Get the plural form of an English word. + * Pluralize the last word of an English, studly caps case string. * - * @param string $value - * @param int $count + * @param string $value + * @param int $count * @return string */ - public static function plural($value, $count = 2) + public static function pluralStudly($value, $count = 2) { - return Pluralizer::plural($value, $count); + $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); + + $lastWord = array_pop($parts); + + return implode('', $parts).self::plural($lastWord, $count); } /** * Generate a more truly "random" alpha-numeric string. * - * @param int $length + * @param int $length * @return string */ public static function random($length = 16) @@ -535,38 +491,12 @@ public static function random($length = 16) return $string; } - /** - * Remove any occurrence of the given string in the subject. - * - * @param string|array $search - * @param string $subject - * @param bool $caseSensitive - * @return string - */ - public static function remove($search, $subject, $caseSensitive = true) - { - $regexSafeSearches = array_map( - function ($search) { - return preg_quote($search); - }, - is_array($search) ? $search : [$search] - ); - - $regex = "/" . implode("|", $regexSafeSearches) . "/"; - - if (!$caseSensitive) { - $regex .= "i"; - } - - return preg_replace($regex, "", $subject); - } - /** * Replace a given value in the string sequentially with an array. * - * @param string $search - * @param array $replace - * @param string $subject + * @param string $search + * @param array $replace + * @param string $subject * @return string */ public static function replaceArray($search, array $replace, $subject) @@ -576,7 +506,7 @@ public static function replaceArray($search, array $replace, $subject) $result = array_shift($segments); foreach ($segments as $segment) { - $result .= (array_shift($replace) ?? $search) . $segment; + $result .= (array_shift($replace) ?? $search).$segment; } return $result; @@ -585,9 +515,9 @@ public static function replaceArray($search, array $replace, $subject) /** * Replace the first occurrence of a given value in the string. * - * @param string $search - * @param string $replace - * @param string $subject + * @param string $search + * @param string $replace + * @param string $subject * @return string */ public static function replaceFirst($search, $replace, $subject) @@ -608,9 +538,9 @@ public static function replaceFirst($search, $replace, $subject) /** * Replace the last occurrence of a given value in the string. * - * @param string $search - * @param string $replace - * @param string $subject + * @param string $search + * @param string $replace + * @param string $subject * @return string */ public static function replaceLast($search, $replace, $subject) @@ -628,24 +558,61 @@ public static function replaceLast($search, $replace, $subject) return $subject; } + /** + * Remove any occurrence of the given string in the subject. + * + * @param string|array $search + * @param string $subject + * @param bool $caseSensitive + * @return string + */ + public static function remove($search, $subject, $caseSensitive = true) + { + $regexSafeSearches = array_map( + function ($search) { + return preg_quote($search); + }, + is_array($search) ? $search : [$search] + ); + + $regex = "/" . implode("|", $regexSafeSearches) . "/"; + + if (!$caseSensitive) { + $regex .= "i"; + } + + return preg_replace($regex, "", $subject); + } + /** * Begin a string with a single instance of a given value. * - * @param string $value - * @param string $prefix + * @param string $value + * @param string $prefix * @return string */ public static function start($value, $prefix) { $quoted = preg_quote($prefix, '/'); - return $prefix . preg_replace('/^(?:' . $quoted . ')+/u', '', $value); + return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value); + } + + /** + * Convert the given string to upper-case. + * + * @param string $value + * @return string + */ + public static function upper($value) + { + return mb_strtoupper($value, 'UTF-8'); } /** * Convert the given string to title case. * - * @param string $value + * @param string $value * @return string */ public static function title($value) @@ -656,7 +623,7 @@ public static function title($value) /** * Get the singular form of an English word. * - * @param string $value + * @param string $value * @return string */ public static function singular($value) @@ -667,9 +634,9 @@ public static function singular($value) /** * Generate a URL friendly "slug" from a given string. * - * @param string $title - * @param string $separator - * @param string|null $language + * @param string $title + * @param string $separator + * @param string|null $language * @return string */ public static function slug($title, $separator = '-', $language = 'en') @@ -679,43 +646,55 @@ public static function slug($title, $separator = '-', $language = 'en') // Convert all dashes/underscores into separator $flip = $separator === '-' ? '_' : '-'; - $title = preg_replace('![' . preg_quote($flip) . ']+!u', $separator, $title); + $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); // Replace @ with the word 'at' - $title = str_replace('@', $separator . 'at' . $separator, $title); + $title = str_replace('@', $separator.'at'.$separator, $title); // Remove all characters that are not the separator, letters, numbers, or whitespace. - $title = preg_replace('![^' . preg_quote($separator) . '\pL\pN\s]+!u', '', static::lower($title)); + $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', static::lower($title)); // Replace all separator characters and whitespace by a single separator - $title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title); + $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); return trim($title, $separator); } /** - * Transliterate a UTF-8 value to ASCII. + * Convert a string to snake case. * - * @param string $value - * @param string $language + * @param string $value + * @param string $delimiter * @return string */ - public static function ascii($value, $language = 'en') + public static function snake($value, $delimiter = '_') { - return ASCII::to_ascii((string)$value, $language); + $key = $value; + + if (isset(static::$snakeCache[$key][$delimiter])) { + return static::$snakeCache[$key][$delimiter]; + } + + if (! ctype_lower($value)) { + $value = preg_replace('/\s+/u', '', ucwords($value)); + + $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); + } + + return static::$snakeCache[$key][$delimiter] = $value; } /** * Determine if a given string starts with a given substring. * - * @param string $haystack - * @param string|string[] $needles + * @param string $haystack + * @param string|string[] $needles * @return bool */ public static function startsWith($haystack, $needles) { - foreach ((array)$needles as $needle) { - if ((string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { + foreach ((array) $needles as $needle) { + if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { return true; } } @@ -723,18 +702,50 @@ public static function startsWith($haystack, $needles) return false; } + /** + * Convert a value to studly caps case. + * + * @param string $value + * @return string + */ + public static function studly($value) + { + $key = $value; + + if (isset(static::$studlyCache[$key])) { + return static::$studlyCache[$key]; + } + + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + + return static::$studlyCache[$key] = str_replace(' ', '', $value); + } + + /** + * Returns the portion of the string specified by the start and length parameters. + * + * @param string $string + * @param int $start + * @param int|null $length + * @return string + */ + public static function substr($string, $start, $length = null) + { + return mb_substr($string, $start, $length, 'UTF-8'); + } + /** * Returns the number of substring occurrences. * - * @param string $haystack - * @param string $needle - * @param int $offset - * @param int|null $length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int|null $length * @return int */ public static function substrCount($haystack, $needle, $offset = 0, $length = null) { - if (!is_null($length)) { + if (! is_null($length)) { return substr_count($haystack, $needle, $offset, $length); } else { return substr_count($haystack, $needle, $offset); @@ -744,23 +755,12 @@ public static function substrCount($haystack, $needle, $offset = 0, $length = nu /** * Make a string's first character uppercase. * - * @param string $string + * @param string $string * @return string */ public static function ucfirst($string) { - return static::upper(static::substr($string, 0, 1)) . static::substr($string, 1); - } - - /** - * Convert the given string to upper-case. - * - * @param string $value - * @return string - */ - public static function upper($value) - { - return mb_strtoupper($value, 'UTF-8'); + return static::upper(static::substr($string, 0, 1)).static::substr($string, 1); } /** @@ -771,8 +771,8 @@ public static function upper($value) public static function uuid() { return static::$uuidFactory - ? call_user_func(static::$uuidFactory) - : Uuid::uuid4(); + ? call_user_func(static::$uuidFactory) + : Uuid::uuid4(); } /** @@ -788,18 +788,14 @@ public static function orderedUuid() $factory = new UuidFactory(); - $factory->setRandomGenerator( - new CombGenerator( - $factory->getRandomGenerator(), - $factory->getNumberConverter() - ) - ); + $factory->setRandomGenerator(new CombGenerator( + $factory->getRandomGenerator(), + $factory->getNumberConverter() + )); - $factory->setCodec( - new TimestampFirstCombCodec( - $factory->getUuidBuilder() - ) - ); + $factory->setCodec(new TimestampFirstCombCodec( + $factory->getUuidBuilder() + )); return $factory->uuid4(); } @@ -807,7 +803,7 @@ public static function orderedUuid() /** * Set the callable that will be used to generate UUIDs. * - * @param callable|null $factory + * @param callable|null $factory * @return void */ public static function createUuidsUsing(callable $factory = null) From 66ad9cd6250432dc051b8228c439d1357c6feaeb Mon Sep 17 00:00:00 2001 From: Jason Lewis Date: Thu, 18 Mar 2021 12:18:04 +1030 Subject: [PATCH 384/443] Add morph type to attributes when making new pivot. --- src/Illuminate/Database/Eloquent/Relations/MorphToMany.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index c2d574558224..1e208625e07c 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -151,6 +151,8 @@ public function newPivot(array $attributes = [], $exists = false) { $using = $this->using; + $attributes = Arr::add($attributes, $this->morphType, $this->morphClass); + $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); From 92b7bdeb4b8c40848fa276cfe1897c656302942f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 17 Mar 2021 23:09:25 -0500 Subject: [PATCH 385/443] add more quotes --- src/Illuminate/Foundation/Inspiring.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Illuminate/Foundation/Inspiring.php b/src/Illuminate/Foundation/Inspiring.php index 6023f5635029..a7e7524e19d9 100644 --- a/src/Illuminate/Foundation/Inspiring.php +++ b/src/Illuminate/Foundation/Inspiring.php @@ -45,6 +45,11 @@ public static function quote() 'Waste no more time arguing what a good man should be, be one. - Marcus Aurelius', 'Well begun is half done. - Aristotle', 'When there is no desire, all things are at peace. - Laozi', + 'Walk as if you are kissing the Earth with your feet. - Thich Nhat Hanh', + 'Because you are alive, everything is possible. - Thich Nhat Hanh', + 'Breathing in, I calm body and mind. Breathing out, I smile. - Thich Nhat Hanh', + 'Life is available only in the present moment. - Thich Nhat Hanh', + 'The best way to take care of the future is to take care of the present moment. - Thich Nhat Hanh', ])->random(); } } From fe48f2cff966e1193aab240ffb4c90072aed89e6 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 18 Mar 2021 14:01:10 +0100 Subject: [PATCH 386/443] Fix description (#36642) --- src/Illuminate/Queue/Middleware/ThrottlesExceptions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index 6364b1d6381a..d289989c807b 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -135,7 +135,7 @@ public function withPrefix(string $prefix) } /** - * Specify the number of seconds a job should be delayed when it is released (before it has reached its max exceptions). + * Specify the number of minutes a job should be delayed when it is released (before it has reached its max exceptions). * * @param int $backoff * @return $this From 18b1b8946cc71cc074ea2733ff2054fb21d1dcb5 Mon Sep 17 00:00:00 2001 From: Nolin <37338160+aaa913121@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:02:30 +0800 Subject: [PATCH 387/443] Adjust event facade comment for ide hint (#36641) Co-authored-by: Nolin --- src/Illuminate/Support/Facades/Event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Event.php b/src/Illuminate/Support/Facades/Event.php index c6e0b014dc6c..9d66ffa25650 100755 --- a/src/Illuminate/Support/Facades/Event.php +++ b/src/Illuminate/Support/Facades/Event.php @@ -19,7 +19,7 @@ * @method static void flush(string $event) * @method static void forget(string $event) * @method static void forgetPushed() - * @method static void listen(string|array $events, \Closure|string $listener = null) + * @method static void listen(\Closure|string|array $events, \Closure|string $listener = null) * @method static void push(string $event, array $payload = []) * @method static void subscribe(object|string $subscriber) * From 7e08215f0d370c3c33beb7bba7e2c1ee2ac7aab5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Mar 2021 08:11:02 -0500 Subject: [PATCH 388/443] add getMorphType --- .../Database/Eloquent/Relations/MorphPivot.php | 10 ++++++++++ .../Database/Eloquent/Relations/MorphToMany.php | 2 -- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php index 314d61fc7f36..7fbe484aac99 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php @@ -74,6 +74,16 @@ public function delete() }); } + /** + * Get the morph type for the pivot. + * + * @return string + */ + public function getMorphType() + { + return $this->morphType; + } + /** * Set the morph type for the pivot. * diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 1e208625e07c..c2d574558224 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -151,8 +151,6 @@ public function newPivot(array $attributes = [], $exists = false) { $using = $this->using; - $attributes = Arr::add($attributes, $this->morphType, $this->morphClass); - $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); From 7b0259faa46409513b75a8a0b512b3aacfcad944 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Mar 2021 08:16:29 -0500 Subject: [PATCH 389/443] Update Str.php --- src/Illuminate/Support/Str.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 19363d65a935..f904ae597ed5 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -568,16 +568,13 @@ public static function replaceLast($search, $replace, $subject) */ public static function remove($search, $subject, $caseSensitive = true) { - $regexSafeSearches = array_map( - function ($search) { - return preg_quote($search); - }, - is_array($search) ? $search : [$search] - ); + $regexSafeSearches = array_map(function ($search) { + return preg_quote($search); + }, is_array($search) ? $search : [$search]); - $regex = "/" . implode("|", $regexSafeSearches) . "/"; + $regex = "/".implode("|", $regexSafeSearches)."/"; - if (!$caseSensitive) { + if (! $caseSensitive) { $regex .= "i"; } From 20e24701e71f71a44b477b4311d0cb69f97906f1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Mar 2021 08:19:22 -0500 Subject: [PATCH 390/443] formatting --- src/Illuminate/Support/Str.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index f904ae597ed5..6f1b0b5076ea 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -2,6 +2,7 @@ namespace Illuminate\Support; +use Illuminate\Support\Arr; use Illuminate\Support\Traits\Macroable; use League\CommonMark\GithubFlavoredMarkdownConverter; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; @@ -568,17 +569,13 @@ public static function replaceLast($search, $replace, $subject) */ public static function remove($search, $subject, $caseSensitive = true) { - $regexSafeSearches = array_map(function ($search) { - return preg_quote($search); - }, is_array($search) ? $search : [$search]); - - $regex = "/".implode("|", $regexSafeSearches)."/"; - - if (! $caseSensitive) { - $regex .= "i"; + foreach (Arr::wrap($search) as $s) { + $subject = $caseSensitive + ? str_replace($search, '', $subject) + : str_ireplace($search, '', $subject); } - return preg_replace($regex, "", $subject); + return $subject; } /** From 5390126e81d67368c543cbf2660b788e2faad731 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Mar 2021 08:20:04 -0500 Subject: [PATCH 391/443] Apply fixes from StyleCI (#36646) --- src/Illuminate/Support/Str.php | 1 - tests/Support/SupportStrTest.php | 20 ++++++++++---------- tests/Support/SupportStringableTest.php | 19 +++++++++---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 6f1b0b5076ea..65b624cdabea 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -2,7 +2,6 @@ namespace Illuminate\Support; -use Illuminate\Support\Arr; use Illuminate\Support\Traits\Macroable; use League\CommonMark\GithubFlavoredMarkdownConverter; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 56b8fc1b853d..c6cc6093224f 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -367,16 +367,16 @@ public function testReplaceLast() public function testRemove() { - $this->assertSame("Fbar", Str::remove('o', 'Foobar')); - $this->assertSame("Foo", Str::remove('bar', 'Foobar')); - $this->assertSame("oobar", Str::remove('F', 'Foobar')); - $this->assertSame("Foobar", Str::remove('f', 'Foobar')); - $this->assertSame("oobar", Str::remove('f', 'Foobar', false)); - - $this->assertSame("Fbr", Str::remove(["o", "a"], 'Foobar')); - $this->assertSame("Fooar", Str::remove(["f", "b"], 'Foobar')); - $this->assertSame("ooar", Str::remove(["f", "b"], 'Foobar', false)); - $this->assertSame("Foobar", Str::remove(["f", "|"], 'Foo|bar')); + $this->assertSame('Fbar', Str::remove('o', 'Foobar')); + $this->assertSame('Foo', Str::remove('bar', 'Foobar')); + $this->assertSame('oobar', Str::remove('F', 'Foobar')); + $this->assertSame('Foobar', Str::remove('f', 'Foobar')); + $this->assertSame('oobar', Str::remove('f', 'Foobar', false)); + + $this->assertSame('Fbr', Str::remove(['o', 'a'], 'Foobar')); + $this->assertSame('Fooar', Str::remove(['f', 'b'], 'Foobar')); + $this->assertSame('ooar', Str::remove(['f', 'b'], 'Foobar', false)); + $this->assertSame('Foobar', Str::remove(['f', '|'], 'Foo|bar')); } public function testSnake() diff --git a/tests/Support/SupportStringableTest.php b/tests/Support/SupportStringableTest.php index 8cce8dc14498..857d6402da2c 100644 --- a/tests/Support/SupportStringableTest.php +++ b/tests/Support/SupportStringableTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Support; use Illuminate\Support\Collection; -use Illuminate\Support\Str; use Illuminate\Support\Stringable; use PHPUnit\Framework\TestCase; @@ -455,16 +454,16 @@ public function testReplaceLast() public function testRemove() { - $this->assertSame("Fbar", (string) $this->stringable('Foobar')->remove('o')); - $this->assertSame("Foo", (string) $this->stringable('Foobar')->remove('bar')); - $this->assertSame("oobar", (string) $this->stringable('Foobar')->remove('F')); - $this->assertSame("Foobar", (string) $this->stringable('Foobar')->remove('f')); - $this->assertSame("oobar", (string) $this->stringable('Foobar')->remove('f', false)); + $this->assertSame('Fbar', (string) $this->stringable('Foobar')->remove('o')); + $this->assertSame('Foo', (string) $this->stringable('Foobar')->remove('bar')); + $this->assertSame('oobar', (string) $this->stringable('Foobar')->remove('F')); + $this->assertSame('Foobar', (string) $this->stringable('Foobar')->remove('f')); + $this->assertSame('oobar', (string) $this->stringable('Foobar')->remove('f', false)); - $this->assertSame("Fbr", (string) $this->stringable('Foobar')->remove(["o", "a"])); - $this->assertSame("Fooar", (string) $this->stringable('Foobar')->remove(["f", "b"])); - $this->assertSame("ooar", (string) $this->stringable('Foobar')->remove(["f", "b"], false)); - $this->assertSame("Foobar", (string) $this->stringable('Foo|bar')->remove(["f", "|"])); + $this->assertSame('Fbr', (string) $this->stringable('Foobar')->remove(['o', 'a'])); + $this->assertSame('Fooar', (string) $this->stringable('Foobar')->remove(['f', 'b'])); + $this->assertSame('ooar', (string) $this->stringable('Foobar')->remove(['f', 'b'], false)); + $this->assertSame('Foobar', (string) $this->stringable('Foo|bar')->remove(['f', '|'])); } public function testSnake() From 3dbddc06898625edfbe97d6c89820ab0ff8df24a Mon Sep 17 00:00:00 2001 From: Mohamad Norouzi Date: Thu, 18 Mar 2021 20:52:14 +0330 Subject: [PATCH 392/443] fix phpdoc of basePath method (#36649) add $path argument --- 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 935c1fc6ad9d..b186d3284e9f 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -15,7 +15,7 @@ * @method static bool runningInConsole() * @method static bool runningUnitTests() * @method static bool shouldSkipMiddleware() - * @method static string basePath() + * @method static string basePath(string $path = '') * @method static string bootstrapPath(string $path = '') * @method static string configPath(string $path = '') * @method static string databasePath(string $path = '') From 9981c774a20c9542bf6ed2482a6fe5e1eddc2d30 Mon Sep 17 00:00:00 2001 From: Sven Luijten <11269635+svenluijten@users.noreply.github.com> Date: Thu, 18 Mar 2021 18:38:36 +0100 Subject: [PATCH 393/443] [8.x] Add assertion to verify type of key in JSON (#36638) * Add assertion to verify type of key in JSON * Add support for union types * Make StyleCI happy again * Update src/Illuminate/Testing/Fluent/Concerns/Matching.php Co-authored-by: Dries Vints Co-authored-by: Dries Vints --- .../Testing/Fluent/Concerns/Matching.php | 41 ++++++ tests/Testing/Fluent/AssertTest.php | 138 ++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php index f64519023e43..0872a6191f40 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -62,6 +62,47 @@ public function whereAll(array $bindings): self return $this; } + /** + * Asserts that the property is of the expected type. + * + * @param string $key + * @param string|array $expected + * @return $this + */ + public function whereType(string $key, $expected): self + { + $this->has($key); + + $actual = $this->prop($key); + + if (! is_array($expected)) { + $expected = explode('|', $expected); + } + + PHPUnit::assertContains( + strtolower(gettype($actual)), + $expected, + sprintf('Property [%s] is not of expected type [%s].', $this->dotPath($key), implode('|', $expected)) + ); + + return $this; + } + + /** + * Asserts that all properties are of their expected types. + * + * @param array $bindings + * @return $this + */ + public function whereAllType(array $bindings): self + { + foreach ($bindings as $key => $value) { + $this->whereType($key, $value); + } + + return $this; + } + /** * Ensures that all properties are sorted the same way, recursively. * diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php index 20e03785a037..69f9278a6956 100644 --- a/tests/Testing/Fluent/AssertTest.php +++ b/tests/Testing/Fluent/AssertTest.php @@ -704,6 +704,144 @@ public function testAssertWhereAllFailsWhenAtLeastOnePropDoesNotMatchValue() ]); } + public function testAssertWhereTypeString() + { + $assert = AssertableJson::fromArray([ + 'foo' => 'bar', + ]); + + $assert->whereType('foo', 'string'); + } + + public function testAssertWhereTypeInteger() + { + $assert = AssertableJson::fromArray([ + 'foo' => 123, + ]); + + $assert->whereType('foo', 'integer'); + } + + public function testAssertWhereTypeBoolean() + { + $assert = AssertableJson::fromArray([ + 'foo' => true, + ]); + + $assert->whereType('foo', 'boolean'); + } + + public function testAssertWhereTypeDouble() + { + $assert = AssertableJson::fromArray([ + 'foo' => 12.3, + ]); + + $assert->whereType('foo', 'double'); + } + + public function testAssertWhereTypeArray() + { + $assert = AssertableJson::fromArray([ + 'foo' => ['bar', 'baz'], + 'bar' => ['foo' => 'baz'], + ]); + + $assert->whereType('foo', 'array'); + $assert->whereType('bar', 'array'); + } + + public function testAssertWhereTypeNull() + { + $assert = AssertableJson::fromArray([ + 'foo' => null, + ]); + + $assert->whereType('foo', 'null'); + } + + public function testAssertWhereAllType() + { + $assert = AssertableJson::fromArray([ + 'one' => 'foo', + 'two' => 123, + 'three' => true, + 'four' => 12.3, + 'five' => ['foo', 'bar'], + 'six' => ['foo' => 'bar'], + 'seven' => null, + ]); + + $assert->whereAllType([ + 'one' => 'string', + 'two' => 'integer', + 'three' => 'boolean', + 'four' => 'double', + 'five' => 'array', + 'six' => 'array', + 'seven' => 'null', + ]); + } + + public function testAssertWhereTypeWhenWrongTypeIsGiven() + { + $assert = AssertableJson::fromArray([ + 'foo' => 'bar', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo] is not of expected type [integer].'); + + $assert->whereType('foo', 'integer'); + } + + public function testAssertWhereTypeWithUnionTypes() + { + $firstAssert = AssertableJson::fromArray([ + 'foo' => 'bar', + ]); + + $secondAssert = AssertableJson::fromArray([ + 'foo' => null, + ]); + + $firstAssert->whereType('foo', ['string', 'null']); + $secondAssert->whereType('foo', ['string', 'null']); + } + + public function testAssertWhereTypeWhenWrongUnionTypeIsGiven() + { + $assert = AssertableJson::fromArray([ + 'foo' => 123, + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo] is not of expected type [string|null].'); + + $assert->whereType('foo', ['string', 'null']); + } + + public function testAssertWhereTypeWithPipeInUnionType() + { + $assert = AssertableJson::fromArray([ + 'foo' => 'bar', + ]); + + $assert->whereType('foo', 'string|null'); + } + + public function testAssertWhereTypeWithPipeInWrongUnionType() + { + $assert = AssertableJson::fromArray([ + 'foo' => 'bar', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [foo] is not of expected type [integer|null].'); + + $assert->whereType('foo', 'integer|null'); + } + public function testAssertHasAll() { $assert = AssertableJson::fromArray([ From 371e7c4e078646a4e6d01e7ec09f5e19f8b3fb32 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 18 Mar 2021 22:27:31 +0100 Subject: [PATCH 394/443] Always prefer typesafe string comparisons. (#36657) --- src/Illuminate/Http/Request.php | 2 +- src/Illuminate/Queue/DatabaseQueue.php | 4 ++-- src/Illuminate/Routing/CompiledRouteCollection.php | 2 +- src/Illuminate/Support/Str.php | 2 +- src/Illuminate/Support/helpers.php | 2 +- src/Illuminate/Testing/Concerns/TestDatabases.php | 2 +- src/Illuminate/Validation/Validator.php | 2 +- tests/Auth/AuthAccessGateTest.php | 6 +++--- tests/Console/Scheduling/EventTest.php | 4 ++-- tests/Database/DatabaseEloquentFactoryTest.php | 6 +++--- .../Database/DatabaseMigrationRefreshCommandTest.php | 4 ++-- tests/Filesystem/FilesystemTest.php | 6 +++--- tests/Http/HttpClientTest.php | 6 +++--- tests/Integration/Database/MigratorEventsTest.php | 12 ++++++------ .../NotificationBroadcastChannelTest.php | 2 +- tests/Support/SupportCollectionTest.php | 10 +++++----- tests/Support/SupportTestingQueueFakeTest.php | 4 ++-- tests/Testing/ParallelTestingTest.php | 2 +- tests/Validation/ValidationValidatorTest.php | 10 +++++----- 19 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 068cf23790da..06f143c6020f 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -142,7 +142,7 @@ public function path() { $pattern = trim($this->getPathInfo(), '/'); - return $pattern == '' ? '/' : $pattern; + return $pattern === '' ? '/' : $pattern; } /** diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index cc77007c0b2f..1ca050f48e50 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -253,8 +253,8 @@ protected function getLockForPopping() $databaseEngine = $this->database->getPdo()->getAttribute(PDO::ATTR_DRIVER_NAME); $databaseVersion = $this->database->getConfig('version') ?? $this->database->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); - if ($databaseEngine == 'mysql' && ! strpos($databaseVersion, 'MariaDB') && version_compare($databaseVersion, '8.0.1', '>=') || - $databaseEngine == 'pgsql' && version_compare($databaseVersion, '9.5', '>=')) { + if ($databaseEngine === 'mysql' && ! strpos($databaseVersion, 'MariaDB') && version_compare($databaseVersion, '8.0.1', '>=') || + $databaseEngine === 'pgsql' && version_compare($databaseVersion, '9.5', '>=')) { return 'FOR UPDATE SKIP LOCKED'; } diff --git a/src/Illuminate/Routing/CompiledRouteCollection.php b/src/Illuminate/Routing/CompiledRouteCollection.php index c53954194e06..45a186e484c0 100644 --- a/src/Illuminate/Routing/CompiledRouteCollection.php +++ b/src/Illuminate/Routing/CompiledRouteCollection.php @@ -297,7 +297,7 @@ protected function newRoute(array $attributes) ), '/'); } - return $this->router->newRoute($attributes['methods'], $baseUri == '' ? '/' : $baseUri, $attributes['action']) + return $this->router->newRoute($attributes['methods'], $baseUri === '' ? '/' : $baseUri, $attributes['action']) ->setFallback($attributes['fallback']) ->setDefaults($attributes['defaults']) ->setWheres($attributes['wheres']) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 65b624cdabea..9fd8ccb98a57 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -522,7 +522,7 @@ public static function replaceArray($search, array $replace, $subject) */ public static function replaceFirst($search, $replace, $subject) { - if ($search == '') { + if ($search === '') { return $subject; } diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 8795e276d07b..660c34af55a2 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -157,7 +157,7 @@ function filled($value) */ function object_get($object, $key, $default = null) { - if (is_null($key) || trim($key) == '') { + if (is_null($key) || trim($key) === '') { return $object; } diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php index 7f81c604bcdc..9e3198a0f166 100644 --- a/src/Illuminate/Testing/Concerns/TestDatabases.php +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -133,7 +133,7 @@ protected function whenNotUsingInMemoryDatabase($callback) { $database = DB::getConfig('database'); - if ($database != ':memory:') { + if ($database !== ':memory:') { $callback($database); } } diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 0aa44d6c197e..74f471aa32fa 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -528,7 +528,7 @@ protected function validateAttribute($attribute, $rule) [$rule, $parameters] = ValidationRuleParser::parse($rule); - if ($rule == '') { + if ($rule === '') { return; } diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 01bd87325450..913d1c4733ad 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -262,9 +262,9 @@ public function testAfterCallbacksAreCalledWithResult() }); $gate->after(function ($user, $ability, $result) { - if ($ability == 'foo') { + if ($ability === 'foo') { $this->assertTrue($result, 'After callback on `foo` should receive true as result'); - } elseif ($ability == 'bar') { + } elseif ($ability === 'bar') { $this->assertFalse($result, 'After callback on `bar` should receive false as result'); } else { $this->assertNull($result, 'After callback on `missing` should receive null as result'); @@ -312,7 +312,7 @@ public function testAfterCallbacksDoNotOverrideEachOther() $gate = $this->getBasicGate(); $gate->after(function ($user, $ability, $result) { - return $ability == 'allow'; + return $ability === 'allow'; }); $gate->after(function ($user, $ability, $result) { diff --git a/tests/Console/Scheduling/EventTest.php b/tests/Console/Scheduling/EventTest.php index a5b05a9dd787..20d8f8ff92ba 100644 --- a/tests/Console/Scheduling/EventTest.php +++ b/tests/Console/Scheduling/EventTest.php @@ -66,7 +66,7 @@ public function testBuildCommandInBackgroundUsingWindows() public function testBuildCommandSendOutputTo() { - $quote = (DIRECTORY_SEPARATOR == '\\') ? '"' : "'"; + $quote = (DIRECTORY_SEPARATOR === '\\') ? '"' : "'"; $event = new Event(m::mock(EventMutex::class), 'php -i'); @@ -81,7 +81,7 @@ public function testBuildCommandSendOutputTo() public function testBuildCommandAppendOutput() { - $quote = (DIRECTORY_SEPARATOR == '\\') ? '"' : "'"; + $quote = (DIRECTORY_SEPARATOR === '\\') ? '"' : "'"; $event = new Event(m::mock(EventMutex::class), 'php -i'); diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index fd402edfdf2c..a3260bddac5e 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -243,7 +243,7 @@ public function test_belongs_to_relationship() ->create(); $this->assertCount(3, $posts->filter(function ($post) { - return $post->user->name == 'Taylor Otwell'; + return $post->user->name === 'Taylor Otwell'; })); $this->assertCount(1, FactoryTestUser::all()); @@ -401,11 +401,11 @@ public function test_sequences() $this->assertCount(4, $user->roles); $this->assertCount(2, $user->roles->filter(function ($role) { - return $role->pivot->admin == 'Y'; + return $role->pivot->admin === 'Y'; })); $this->assertCount(2, $user->roles->filter(function ($role) { - return $role->pivot->admin == 'N'; + return $role->pivot->admin === 'N'; })); } diff --git a/tests/Database/DatabaseMigrationRefreshCommandTest.php b/tests/Database/DatabaseMigrationRefreshCommandTest.php index dfb4180fe22c..ce11dd67fc52 100755 --- a/tests/Database/DatabaseMigrationRefreshCommandTest.php +++ b/tests/Database/DatabaseMigrationRefreshCommandTest.php @@ -40,7 +40,7 @@ public function testRefreshCommandCallsCommandsWithProperArguments() $console->shouldReceive('find')->with('migrate')->andReturn($migrateCommand); $dispatcher->shouldReceive('dispatch')->once()->with(m::type(DatabaseRefreshed::class)); - $quote = DIRECTORY_SEPARATOR == '\\' ? '"' : "'"; + $quote = DIRECTORY_SEPARATOR === '\\' ? '"' : "'"; $resetCommand->shouldReceive('run')->with(new InputMatcher("--force=1 {$quote}migrate:reset{$quote}"), m::any()); $migrateCommand->shouldReceive('run')->with(new InputMatcher('--force=1 migrate'), m::any()); @@ -65,7 +65,7 @@ public function testRefreshCommandCallsCommandsWithStep() $console->shouldReceive('find')->with('migrate')->andReturn($migrateCommand); $dispatcher->shouldReceive('dispatch')->once()->with(m::type(DatabaseRefreshed::class)); - $quote = DIRECTORY_SEPARATOR == '\\' ? '"' : "'"; + $quote = DIRECTORY_SEPARATOR === '\\' ? '"' : "'"; $rollbackCommand->shouldReceive('run')->with(new InputMatcher("--step=2 --force=1 {$quote}migrate:rollback{$quote}"), m::any()); $migrateCommand->shouldReceive('run')->with(new InputMatcher('--force=1 migrate'), m::any()); diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index d1ff89f680ce..4f0279718387 100755 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -137,7 +137,7 @@ public function testSetChmod() $files = new Filesystem; $files->chmod(self::$tempDir.'/file.txt', 0755); $filePermission = substr(sprintf('%o', fileperms(self::$tempDir.'/file.txt')), -4); - $expectedPermissions = DIRECTORY_SEPARATOR == '\\' ? '0666' : '0755'; + $expectedPermissions = DIRECTORY_SEPARATOR === '\\' ? '0666' : '0755'; $this->assertEquals($expectedPermissions, $filePermission); } @@ -148,7 +148,7 @@ public function testGetChmod() $files = new Filesystem; $filePermission = $files->chmod(self::$tempDir.'/file.txt'); - $expectedPermissions = DIRECTORY_SEPARATOR == '\\' ? '0666' : '0755'; + $expectedPermissions = DIRECTORY_SEPARATOR === '\\' ? '0666' : '0755'; $this->assertEquals($expectedPermissions, $filePermission); } @@ -488,7 +488,7 @@ public function testMakeDirectory() */ public function testSharedGet() { - if (PHP_OS == 'Darwin') { + if (PHP_OS === 'Darwin') { $this->markTestSkipped('The operating system is MacOS.'); } diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 95f08521babb..125811093fa7 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -688,13 +688,13 @@ public function testCanAssertAgainstOrderOfHttpRequestsWithCallables() $exampleUrls = [ function ($request) { - return $request->url() == 'http://example.com/1'; + return $request->url() === 'http://example.com/1'; }, function ($request) { - return $request->url() == 'http://example.com/2'; + return $request->url() === 'http://example.com/2'; }, function ($request) { - return $request->url() == 'http://example.com/3'; + return $request->url() === 'http://example.com/3'; }, ]; diff --git a/tests/Integration/Database/MigratorEventsTest.php b/tests/Integration/Database/MigratorEventsTest.php index 75d3ac6327da..0ecbb91827e1 100644 --- a/tests/Integration/Database/MigratorEventsTest.php +++ b/tests/Integration/Database/MigratorEventsTest.php @@ -41,16 +41,16 @@ public function testMigrationEventsContainTheMigrationAndMethod() $this->artisan('migrate:rollback', $this->migrateOptions()); Event::assertDispatched(MigrationStarted::class, function ($event) { - return $event->method == 'up' && $event->migration instanceof Migration; + return $event->method === 'up' && $event->migration instanceof Migration; }); Event::assertDispatched(MigrationStarted::class, function ($event) { - return $event->method == 'down' && $event->migration instanceof Migration; + return $event->method === 'down' && $event->migration instanceof Migration; }); Event::assertDispatched(MigrationEnded::class, function ($event) { - return $event->method == 'up' && $event->migration instanceof Migration; + return $event->method === 'up' && $event->migration instanceof Migration; }); Event::assertDispatched(MigrationEnded::class, function ($event) { - return $event->method == 'down' && $event->migration instanceof Migration; + return $event->method === 'down' && $event->migration instanceof Migration; }); } @@ -62,10 +62,10 @@ public function testTheNoMigrationEventIsFiredWhenNothingToMigrate() $this->artisan('migrate:rollback'); Event::assertDispatched(NoPendingMigrations::class, function ($event) { - return $event->method == 'up'; + return $event->method === 'up'; }); Event::assertDispatched(NoPendingMigrations::class, function ($event) { - return $event->method == 'down'; + return $event->method === 'down'; }); } } diff --git a/tests/Notifications/NotificationBroadcastChannelTest.php b/tests/Notifications/NotificationBroadcastChannelTest.php index e4cae95c3219..51c9401671fa 100644 --- a/tests/Notifications/NotificationBroadcastChannelTest.php +++ b/tests/Notifications/NotificationBroadcastChannelTest.php @@ -83,7 +83,7 @@ public function testNotificationIsBroadcastedNow() $events = m::mock(Dispatcher::class); $events->shouldReceive('dispatch')->once()->with(m::on(function ($event) { - return $event->connection == 'sync'; + return $event->connection === 'sync'; })); $channel = new BroadcastChannel($events); $channel->send($notifiable, $notification); diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 8c562d572d48..e7f7a464959e 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -582,7 +582,7 @@ public function testFilter($collection) $c = new $collection(['id' => 1, 'first' => 'Hello', 'second' => 'World']); $this->assertEquals(['first' => 'Hello', 'second' => 'World'], $c->filter(function ($item, $key) { - return $key != 'id'; + return $key !== 'id'; })->all()); } @@ -3126,7 +3126,7 @@ public function testRejectRemovesElementsPassingTruthTest($collection) $c = new $collection(['foo', 'bar']); $this->assertEquals(['foo'], $c->reject(function ($v) { - return $v == 'bar'; + return $v === 'bar'; })->values()->all()); $c = new $collection(['foo', null]); @@ -3137,12 +3137,12 @@ public function testRejectRemovesElementsPassingTruthTest($collection) $c = new $collection(['foo', 'bar']); $this->assertEquals(['foo', 'bar'], $c->reject(function ($v) { - return $v == 'baz'; + return $v === 'baz'; })->values()->all()); $c = new $collection(['id' => 1, 'primary' => 'foo', 'secondary' => 'bar']); $this->assertEquals(['primary' => 'foo', 'secondary' => 'bar'], $c->reject(function ($item, $key) { - return $key == 'id'; + return $key === 'id'; })->all()); } @@ -3215,7 +3215,7 @@ public function testSearchReturnsFalseWhenItemIsNotFound($collection) return $value < 1 && is_numeric($value); })); $this->assertFalse($c->search(function ($value) { - return $value == 'nope'; + return $value === 'nope'; })); } diff --git a/tests/Support/SupportTestingQueueFakeTest.php b/tests/Support/SupportTestingQueueFakeTest.php index a2996c492d2b..cf22717cf29b 100644 --- a/tests/Support/SupportTestingQueueFakeTest.php +++ b/tests/Support/SupportTestingQueueFakeTest.php @@ -220,7 +220,7 @@ public function testAssertPushedWithChainUsingCallback() $this->fake->assertPushedWithChain(JobWithChainAndParameterStub::class, [ JobStub::class, ], function ($job) { - return $job->parameter == 'second'; + return $job->parameter === 'second'; }); try { @@ -228,7 +228,7 @@ public function testAssertPushedWithChainUsingCallback() JobStub::class, JobStub::class, ], function ($job) { - return $job->parameter == 'second'; + return $job->parameter === 'second'; }); $this->fail(); } catch (ExpectationFailedException $e) { diff --git a/tests/Testing/ParallelTestingTest.php b/tests/Testing/ParallelTestingTest.php index d7a0406019ed..cb6fafb95382 100644 --- a/tests/Testing/ParallelTestingTest.php +++ b/tests/Testing/ParallelTestingTest.php @@ -58,7 +58,7 @@ public function testOptions() $this->assertFalse($parallelTesting->option('recreate_databases')); $parallelTesting->resolveOptionsUsing(function ($option) { - return $option == 'recreate_databases'; + return $option === 'recreate_databases'; }); $this->assertFalse($parallelTesting->option('recreate_caches')); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 1772582d18ba..79edde0850c6 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -3830,7 +3830,7 @@ public function testSometimesAddingRules() $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['x' => 'foo'], ['x' => 'Required']); $v->sometimes('x', 'Confirmed', function ($i) { - return $i->x == 'foo'; + return $i->x === 'foo'; }); $this->assertEquals(['x' => ['Required', 'Confirmed']], $v->getRules()); @@ -3844,21 +3844,21 @@ public function testSometimesAddingRules() $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['x' => 'foo'], ['x' => 'Required']); $v->sometimes('x', 'Confirmed', function ($i) { - return $i->x == 'bar'; + return $i->x === 'bar'; }); $this->assertEquals(['x' => ['Required']], $v->getRules()); $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['x' => 'foo'], ['x' => 'Required']); $v->sometimes('x', 'Foo|Bar', function ($i) { - return $i->x == 'foo'; + return $i->x === 'foo'; }); $this->assertEquals(['x' => ['Required', 'Foo', 'Bar']], $v->getRules()); $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['x' => 'foo'], ['x' => 'Required']); $v->sometimes('x', ['Foo', 'Bar:Baz'], function ($i) { - return $i->x == 'foo'; + return $i->x === 'foo'; }); $this->assertEquals(['x' => ['Required', 'Foo', 'Bar:Baz']], $v->getRules()); @@ -3963,7 +3963,7 @@ public function testCustomDependentValidators() ['*.name' => 'dependent_rule:*.age'] ); $v->addDependentExtension('dependent_rule', function ($name) use ($v) { - return Arr::get($v->getData(), $name) == 'Jamie'; + return Arr::get($v->getData(), $name) === 'Jamie'; }); $this->assertTrue($v->passes()); } From ee20cac5f424bd0492e817321872b1c3287545d4 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 18 Mar 2021 22:27:49 +0100 Subject: [PATCH 395/443] Avoid using FQCN in tests. (#36656) --- tests/Cache/CacheArrayStoreTest.php | 5 +++-- tests/Container/ContainerTest.php | 3 ++- tests/Database/DatabaseEloquentFactoryTest.php | 3 ++- tests/Database/DatabaseTransactionsTest.php | 10 ++++++---- .../Testing/Concerns/InteractsWithContainerTest.php | 3 ++- tests/Http/HttpClientTest.php | 7 ++++--- .../Database/EloquentModelEncryptedCastingTest.php | 5 +++-- .../Database/EloquentModelLoadCountTest.php | 9 +++++---- tests/Integration/Queue/QueueConnectionTest.php | 3 ++- tests/Integration/Queue/UniqueJobTest.php | 5 +++-- tests/Integration/Queue/WithoutOverlappingJobsTest.php | 5 +++-- tests/Mail/MailManagerTest.php | 3 ++- 12 files changed, 37 insertions(+), 24 deletions(-) diff --git a/tests/Cache/CacheArrayStoreTest.php b/tests/Cache/CacheArrayStoreTest.php index 3e1a2febbb82..b491ac47ef69 100755 --- a/tests/Cache/CacheArrayStoreTest.php +++ b/tests/Cache/CacheArrayStoreTest.php @@ -5,6 +5,7 @@ use Illuminate\Cache\ArrayStore; use Illuminate\Support\Carbon; use PHPUnit\Framework\TestCase; +use stdClass; class CacheArrayStoreTest extends TestCase { @@ -198,7 +199,7 @@ public function testAnotherOwnerCanForceReleaseALock() public function testValuesAreNotStoredByReference() { $store = new ArrayStore($serialize = true); - $object = new \stdClass; + $object = new stdClass; $object->foo = true; $store->put('object', $object, 10); @@ -210,7 +211,7 @@ public function testValuesAreNotStoredByReference() public function testValuesAreStoredByReferenceIfSerializationIsDisabled() { $store = new ArrayStore; - $object = new \stdClass; + $object = new stdClass; $object->foo = true; $store->put('object', $object, 10); diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index eefe9366cbfc..d3c88e26ed3a 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerExceptionInterface; use stdClass; +use TypeError; class ContainerTest extends TestCase { @@ -123,7 +124,7 @@ public function testSharedConcreteResolution() public function testBindFailsLoudlyWithInvalidArgument() { - $this->expectException(\TypeError::class); + $this->expectException(TypeError::class); $container = new Container; $concrete = new ContainerConcreteStub(); diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index a3260bddac5e..e01a53a196ec 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Database; +use Faker\Generator; use Illuminate\Container\Container; use Illuminate\Contracts\Foundation\Application; use Illuminate\Database\Capsule\Manager as DB; @@ -18,7 +19,7 @@ class DatabaseEloquentFactoryTest extends TestCase protected function setUp(): void { $container = Container::getInstance(); - $container->singleton(\Faker\Generator::class, function ($app, $parameters) { + $container->singleton(Generator::class, function ($app, $parameters) { return \Faker\Factory::create('en_US'); }); $container->instance(Application::class, $app = Mockery::mock(Application::class)); diff --git a/tests/Database/DatabaseTransactionsTest.php b/tests/Database/DatabaseTransactionsTest.php index 2385d6d26313..94e3b7d86f2d 100644 --- a/tests/Database/DatabaseTransactionsTest.php +++ b/tests/Database/DatabaseTransactionsTest.php @@ -2,10 +2,12 @@ namespace Illuminate\Tests\Database; +use Exception; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\DatabaseTransactionsManager; use Mockery as m; use PHPUnit\Framework\TestCase; +use Throwable; class DatabaseTransactionsTest extends TestCase { @@ -176,9 +178,9 @@ public function testTransactionIsRolledBack() 'value' => 2, ]); - throw new \Exception; + throw new Exception; }); - } catch (\Throwable $e) { + } catch (Throwable $e) { } } @@ -230,10 +232,10 @@ public function testNestedTransactionsAreRolledBack() 'value' => 2, ]); - throw new \Exception; + throw new Exception; }); }); - } catch (\Throwable $e) { + } catch (Throwable $e) { } } diff --git a/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php b/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php index cfe4460ad07d..1d11691b9771 100644 --- a/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php +++ b/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php @@ -4,6 +4,7 @@ use Illuminate\Foundation\Mix; use Orchestra\Testbench\TestCase; +use stdClass; class InteractsWithContainerTest extends TestCase { @@ -17,7 +18,7 @@ public function testWithoutMixBindsEmptyHandlerAndReturnsInstance() public function testWithMixRestoresOriginalHandlerAndReturnsInstance() { - $handler = new \stdClass(); + $handler = new stdClass(); $this->app->instance(Mix::class, $handler); $this->withoutMix(); diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 125811093fa7..d5be7aefaf25 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -10,6 +10,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; use OutOfBoundsException; +use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\VarDumper; @@ -659,7 +660,7 @@ public function testAssertionsSentOutOfOrderThrowAssertionFailed() $this->factory->get($exampleUrls[2]); $this->factory->get($exampleUrls[1]); - $this->expectException(\PHPUnit\Framework\AssertionFailedError::class); + $this->expectException(AssertionFailedError::class); $this->factory->assertSentInOrder($exampleUrls); } @@ -677,7 +678,7 @@ public function testWrongNumberOfRequestsThrowAssertionFailed() $this->factory->get($exampleUrls[0]); $this->factory->get($exampleUrls[1]); - $this->expectException(\PHPUnit\Framework\AssertionFailedError::class); + $this->expectException(AssertionFailedError::class); $this->factory->assertSentInOrder($exampleUrls); } @@ -778,7 +779,7 @@ function (Request $request) { 'name' => 'Taylor', ]); - $this->expectException(\PHPUnit\Framework\AssertionFailedError::class); + $this->expectException(AssertionFailedError::class); $this->factory->assertSentInOrder($executionOrder); } diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index 1554af9c60ed..c89b81bbeed0 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -8,6 +8,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Schema; +use stdClass; /** * @group integration @@ -130,7 +131,7 @@ public function testJsonAttributeIsCastable() public function testObjectIsCastable() { - $object = new \stdClass(); + $object = new stdClass(); $object->key1 = 'value1'; $this->encrypter->expects('encrypt') @@ -146,7 +147,7 @@ public function testObjectIsCastable() 'secret_object' => $object, ]); - $this->assertInstanceOf(\stdClass::class, $object->secret_object); + $this->assertInstanceOf(stdClass::class, $object->secret_object); $this->assertSame('value1', $object->secret_object->key1); $this->assertDatabaseHas('encrypted_casts', [ 'id' => $object->id, diff --git a/tests/Integration/Database/EloquentModelLoadCountTest.php b/tests/Integration/Database/EloquentModelLoadCountTest.php index ac3e926f7c5d..92c46d540a8b 100644 --- a/tests/Integration/Database/EloquentModelLoadCountTest.php +++ b/tests/Integration/Database/EloquentModelLoadCountTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Database\EloquentModelLoadCountTest; +use DB; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Schema\Blueprint; @@ -49,11 +50,11 @@ public function testLoadCountSingleRelation() { $model = BaseModel::first(); - \DB::enableQueryLog(); + DB::enableQueryLog(); $model->loadCount('related1'); - $this->assertCount(1, \DB::getQueryLog()); + $this->assertCount(1, DB::getQueryLog()); $this->assertEquals(2, $model->related1_count); } @@ -61,11 +62,11 @@ public function testLoadCountMultipleRelations() { $model = BaseModel::first(); - \DB::enableQueryLog(); + DB::enableQueryLog(); $model->loadCount(['related1', 'related2']); - $this->assertCount(1, \DB::getQueryLog()); + $this->assertCount(1, DB::getQueryLog()); $this->assertEquals(2, $model->related1_count); $this->assertEquals(1, $model->related2_count); } diff --git a/tests/Integration/Queue/QueueConnectionTest.php b/tests/Integration/Queue/QueueConnectionTest.php index d9824e22d077..2a264fce8f34 100644 --- a/tests/Integration/Queue/QueueConnectionTest.php +++ b/tests/Integration/Queue/QueueConnectionTest.php @@ -9,6 +9,7 @@ use Illuminate\Support\Facades\Bus; use Mockery as m; use Orchestra\Testbench\TestCase; +use Throwable; /** * @group integration @@ -52,7 +53,7 @@ public function testJobWillGetDispatchedInsideATransactionWhenExplicitlyIndicate try { Bus::dispatch((new QueueConnectionTestJob)->beforeCommit()); - } catch (\Throwable $e) { + } catch (Throwable $e) { // This job was dispatched } } diff --git a/tests/Integration/Queue/UniqueJobTest.php b/tests/Integration/Queue/UniqueJobTest.php index f463eb58881e..4bc207b7fbd7 100644 --- a/tests/Integration/Queue/UniqueJobTest.php +++ b/tests/Integration/Queue/UniqueJobTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Queue; +use Exception; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Queue\ShouldBeUnique; @@ -83,7 +84,7 @@ public function testLockIsReleasedForFailedJobs() { UniqueTestFailJob::$handled = false; - $this->expectException(\Exception::class); + $this->expectException(Exception::class); try { dispatch($job = new UniqueTestFailJob); @@ -191,7 +192,7 @@ public function handle() { static::$handled = true; - throw new \Exception; + throw new Exception; } } diff --git a/tests/Integration/Queue/WithoutOverlappingJobsTest.php b/tests/Integration/Queue/WithoutOverlappingJobsTest.php index c693c338533c..d07ddfae834e 100644 --- a/tests/Integration/Queue/WithoutOverlappingJobsTest.php +++ b/tests/Integration/Queue/WithoutOverlappingJobsTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Queue; +use Exception; use Illuminate\Bus\Dispatcher; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Cache\Repository as Cache; @@ -57,7 +58,7 @@ public function testLockIsReleasedOnJobExceptions() $job->shouldReceive('isReleased')->andReturn(false); $job->shouldReceive('isDeletedOrReleased')->andReturn(false); - $this->expectException(\Exception::class); + $this->expectException(Exception::class); try { $instance->call($job, [ @@ -147,6 +148,6 @@ public function handle() { static::$handled = true; - throw new \Exception; + throw new Exception; } } diff --git a/tests/Mail/MailManagerTest.php b/tests/Mail/MailManagerTest.php index 9a67d4c2d9ca..e7610ffe1cdd 100644 --- a/tests/Mail/MailManagerTest.php +++ b/tests/Mail/MailManagerTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Mail; +use InvalidArgumentException; use Orchestra\Testbench\TestCase; class MailManagerTest extends TestCase @@ -21,7 +22,7 @@ public function testEmptyTransportConfig($transport) 'timeout' => null, ]); - $this->expectException(\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage("Unsupported mail transport [{$transport}]"); $this->app['mail.manager']->mailer('custom_smtp'); } From 56dcc1e23bcb8dca99b6fb533cdb28f3a777bb9e Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 18 Mar 2021 22:28:00 +0100 Subject: [PATCH 396/443] Fix docblock return type. (#36655) --- src/Illuminate/Support/Stringable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 29e62b89eca6..de9c8b69833a 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -324,7 +324,7 @@ public function lower() * Convert GitHub flavored Markdown into HTML. * * @param array $options - * @return string + * @return static */ public function markdown(array $options = []) { From d89b025116ee4bc8db59f03dc53b7bdff29b0931 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 18 Mar 2021 22:28:17 +0100 Subject: [PATCH 397/443] Always use stricter string assertions. (#36654) --- tests/Bus/BusBatchTest.php | 2 +- tests/Container/ContextualBindingTest.php | 20 +++++------ .../Database/DatabaseEloquentBuilderTest.php | 2 +- .../Database/DatabaseEloquentFactoryTest.php | 2 +- .../DatabaseEloquentIntegrationTest.php | 12 +++---- tests/Database/DatabaseQueryBuilderTest.php | 4 +-- .../DatabaseTransactionsManagerTest.php | 14 ++++---- ...aseSchemaBuilderAlterTableWithEnumTest.php | 2 +- .../Integration/Queue/JobDispatchingTest.php | 2 +- .../Queue/ModelSerializationTest.php | 8 ++--- tests/Integration/Queue/RateLimitedTest.php | 2 +- .../Queue/RateLimitedWithRedisTest.php | 2 +- .../NotificationMailMessageTest.php | 4 +-- tests/Redis/RedisConnectorTest.php | 2 +- tests/Support/SupportCollectionTest.php | 4 +-- tests/Support/SupportStrTest.php | 4 +-- tests/View/ViewTest.php | 34 +++++++++---------- 17 files changed, 60 insertions(+), 60 deletions(-) diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index 1da999569e84..cd2e06ee346a 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -333,7 +333,7 @@ public function test_chain_can_be_added_to_batch() $this->assertEquals(3, $batch->totalJobs); $this->assertEquals(3, $batch->pendingJobs); - $this->assertEquals('test-queue', $chainHeadJob->chainQueue); + $this->assertSame('test-queue', $chainHeadJob->chainQueue); $this->assertTrue(is_string($chainHeadJob->batchId)); $this->assertTrue(is_string($secondJob->batchId)); $this->assertTrue(is_string($thirdJob->batchId)); diff --git a/tests/Container/ContextualBindingTest.php b/tests/Container/ContextualBindingTest.php index 1ddd5ebf8aba..026a22f2ab82 100644 --- a/tests/Container/ContextualBindingTest.php +++ b/tests/Container/ContextualBindingTest.php @@ -386,8 +386,8 @@ public function testContextualBindingGivesValuesFromConfigOptionalValueNull() $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); - $this->assertEquals('laravel', $resolvedInstance->username); - $this->assertEquals('hunter42', $resolvedInstance->password); + $this->assertSame('laravel', $resolvedInstance->username); + $this->assertSame('hunter42', $resolvedInstance->password); $this->assertNull($resolvedInstance->alias); } @@ -422,9 +422,9 @@ public function testContextualBindingGivesValuesFromConfigOptionalValueSet() $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); - $this->assertEquals('laravel', $resolvedInstance->username); - $this->assertEquals('hunter42', $resolvedInstance->password); - $this->assertEquals('lumen', $resolvedInstance->alias); + $this->assertSame('laravel', $resolvedInstance->username); + $this->assertSame('hunter42', $resolvedInstance->password); + $this->assertSame('lumen', $resolvedInstance->alias); } public function testContextualBindingGivesValuesFromConfigWithDefault() @@ -451,8 +451,8 @@ public function testContextualBindingGivesValuesFromConfigWithDefault() $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); - $this->assertEquals('DEFAULT_USERNAME', $resolvedInstance->username); - $this->assertEquals('hunter42', $resolvedInstance->password); + $this->assertSame('DEFAULT_USERNAME', $resolvedInstance->username); + $this->assertSame('hunter42', $resolvedInstance->password); $this->assertNull($resolvedInstance->alias); } @@ -477,9 +477,9 @@ public function testContextualBindingGivesValuesFromConfigArray() $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigArray::class); - $this->assertEquals('laravel', $resolvedInstance->settings['username']); - $this->assertEquals('hunter42', $resolvedInstance->settings['password']); - $this->assertEquals('lumen', $resolvedInstance->settings['alias']); + $this->assertSame('laravel', $resolvedInstance->settings['username']); + $this->assertSame('hunter42', $resolvedInstance->settings['password']); + $this->assertSame('lumen', $resolvedInstance->settings['alias']); } } diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 6e0a59148954..27f57d1f8e87 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -467,7 +467,7 @@ public function testGlobalMacrosAreCalledOnBuilder() $builder = $this->getBuilder(); $this->assertTrue(Builder::hasGlobalMacro('foo')); - $this->assertEquals('bar', $builder->foo('bar')); + $this->assertSame('bar', $builder->foo('bar')); $this->assertEquals($builder->bam(), $builder->getQuery()); } diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index e01a53a196ec..7344dbb6c285 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -481,7 +481,7 @@ public function test_can_be_macroable() return 'Hello World'; }); - $this->assertEquals('Hello World', $factory->getFoo()); + $this->assertSame('Hello World', $factory->getFoo()); } /** diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index d3a7ffb3a414..2c5011b12551 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -1377,14 +1377,14 @@ public function testFreshMethodOnCollection() EloquentTestUser::find(2)->update(['email' => 'dev@mathieutu.ovh']); $this->assertCount(3, $users); - $this->assertNotEquals('Mathieu TUDISCO', $users[0]->name); - $this->assertNotEquals('dev@mathieutu.ovh', $users[1]->email); + $this->assertNotSame('Mathieu TUDISCO', $users[0]->name); + $this->assertNotSame('dev@mathieutu.ovh', $users[1]->email); $refreshedUsers = $users->fresh(); $this->assertCount(2, $refreshedUsers); - $this->assertEquals('Mathieu TUDISCO', $refreshedUsers[0]->name); - $this->assertEquals('dev@mathieutu.ovh', $refreshedUsers[1]->email); + $this->assertSame('Mathieu TUDISCO', $refreshedUsers[0]->name); + $this->assertSame('dev@mathieutu.ovh', $refreshedUsers[1]->email); } public function testTimestampsUsingDefaultDateFormat() @@ -1817,10 +1817,10 @@ public function testMorphPivotsCanBeRefreshed() ]); $this->assertInstanceOf(MorphPivot::class, $freshPivot = $pivot->fresh()); - $this->assertEquals('primary', $freshPivot->taxonomy); + $this->assertSame('primary', $freshPivot->taxonomy); $this->assertSame($pivot, $pivot->refresh()); - $this->assertEquals('primary', $pivot->taxonomy); + $this->assertSame('primary', $pivot->taxonomy); } /** diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 55b02d9b5ae8..39597512a21f 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -198,7 +198,7 @@ public function testWhenCallbackWithReturn() public function testWhenCallbackWithDefault() { $callback = function ($query, $condition) { - $this->assertEquals('truthy', $condition); + $this->assertSame('truthy', $condition); $query->where('id', '=', 1); }; @@ -263,7 +263,7 @@ public function testUnlessCallbackWithDefault() }; $default = function ($query, $condition) { - $this->assertEquals('truthy', $condition); + $this->assertSame('truthy', $condition); $query->where('id', '=', 2); }; diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php index 172a48e5a4a1..4118180a12c7 100755 --- a/tests/Database/DatabaseTransactionsManagerTest.php +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -16,11 +16,11 @@ public function testBeginningTransactions() $manager->begin('admin', 1); $this->assertCount(3, $manager->getTransactions()); - $this->assertEquals('default', $manager->getTransactions()[0]->connection); + $this->assertSame('default', $manager->getTransactions()[0]->connection); $this->assertEquals(1, $manager->getTransactions()[0]->level); - $this->assertEquals('default', $manager->getTransactions()[1]->connection); + $this->assertSame('default', $manager->getTransactions()[1]->connection); $this->assertEquals(2, $manager->getTransactions()[1]->level); - $this->assertEquals('admin', $manager->getTransactions()[2]->connection); + $this->assertSame('admin', $manager->getTransactions()[2]->connection); $this->assertEquals(1, $manager->getTransactions()[2]->level); } @@ -36,10 +36,10 @@ public function testRollingBackTransactions() $this->assertCount(2, $manager->getTransactions()); - $this->assertEquals('default', $manager->getTransactions()[0]->connection); + $this->assertSame('default', $manager->getTransactions()[0]->connection); $this->assertEquals(1, $manager->getTransactions()[0]->level); - $this->assertEquals('admin', $manager->getTransactions()[1]->connection); + $this->assertSame('admin', $manager->getTransactions()[1]->connection); $this->assertEquals(1, $manager->getTransactions()[1]->level); } @@ -55,7 +55,7 @@ public function testRollingBackTransactionsAllTheWay() $this->assertCount(1, $manager->getTransactions()); - $this->assertEquals('admin', $manager->getTransactions()[0]->connection); + $this->assertSame('admin', $manager->getTransactions()[0]->connection); $this->assertEquals(1, $manager->getTransactions()[0]->level); } @@ -71,7 +71,7 @@ public function testCommittingTransactions() $this->assertCount(1, $manager->getTransactions()); - $this->assertEquals('admin', $manager->getTransactions()[0]->connection); + $this->assertSame('admin', $manager->getTransactions()[0]->connection); $this->assertEquals(1, $manager->getTransactions()[0]->level); } diff --git a/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php b/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php index 92c0f30bb44e..9b52c60e4f5c 100644 --- a/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php +++ b/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php @@ -30,7 +30,7 @@ public function testGetAllTablesAndColumnListing() $tables = Schema::getAllTables(); $this->assertCount(1, $tables); - $this->assertEquals('stdClass', get_class($tables[0])); + $this->assertSame('stdClass', get_class($tables[0])); $tableProperties = array_values((array) $tables[0]); $this->assertEquals(['users', 'BASE TABLE'], $tableProperties); diff --git a/tests/Integration/Queue/JobDispatchingTest.php b/tests/Integration/Queue/JobDispatchingTest.php index 4391c50b54d8..7d7daf8fafe7 100644 --- a/tests/Integration/Queue/JobDispatchingTest.php +++ b/tests/Integration/Queue/JobDispatchingTest.php @@ -27,7 +27,7 @@ public function testJobCanUseCustomMethodsAfterDispatch() Job::dispatch('test')->replaceValue('new-test'); $this->assertTrue(Job::$ran); - $this->assertEquals('new-test', Job::$value); + $this->assertSame('new-test', Job::$value); } } diff --git a/tests/Integration/Queue/ModelSerializationTest.php b/tests/Integration/Queue/ModelSerializationTest.php index 332442d2cc17..dc82a083c1b3 100644 --- a/tests/Integration/Queue/ModelSerializationTest.php +++ b/tests/Integration/Queue/ModelSerializationTest.php @@ -232,8 +232,8 @@ public function testItSerializesACollectionInCorrectOrder() $unserialized = unserialize($serialized); - $this->assertEquals('taylor@laravel.com', $unserialized->users->first()->email); - $this->assertEquals('mohamed@laravel.com', $unserialized->users->last()->email); + $this->assertSame('taylor@laravel.com', $unserialized->users->first()->email); + $this->assertSame('mohamed@laravel.com', $unserialized->users->last()->email); } public function testItCanUnserializeACollectionInCorrectOrderAndHandleDeletedModels() @@ -252,8 +252,8 @@ public function testItCanUnserializeACollectionInCorrectOrderAndHandleDeletedMod $this->assertCount(2, $unserialized->users); - $this->assertEquals('3@laravel.com', $unserialized->users->first()->email); - $this->assertEquals('1@laravel.com', $unserialized->users->last()->email); + $this->assertSame('3@laravel.com', $unserialized->users->first()->email); + $this->assertSame('1@laravel.com', $unserialized->users->last()->email); } public function testItCanUnserializeCustomCollection() diff --git a/tests/Integration/Queue/RateLimitedTest.php b/tests/Integration/Queue/RateLimitedTest.php index c3a74027cc7e..b90104690ef6 100644 --- a/tests/Integration/Queue/RateLimitedTest.php +++ b/tests/Integration/Queue/RateLimitedTest.php @@ -92,7 +92,7 @@ public function testMiddlewareSerialization() })->bindTo($restoredRateLimited, RateLimited::class); $this->assertFalse($restoredRateLimited->shouldRelease); - $this->assertEquals('limiterName', $fetch('limiterName')); + $this->assertSame('limiterName', $fetch('limiterName')); $this->assertInstanceOf(RateLimiter::class, $fetch('limiter')); } diff --git a/tests/Integration/Queue/RateLimitedWithRedisTest.php b/tests/Integration/Queue/RateLimitedWithRedisTest.php index f08f3146a108..b8571a91a098 100644 --- a/tests/Integration/Queue/RateLimitedWithRedisTest.php +++ b/tests/Integration/Queue/RateLimitedWithRedisTest.php @@ -124,7 +124,7 @@ public function testMiddlewareSerialization() })->bindTo($restoredRateLimited, RateLimitedWithRedis::class); $this->assertFalse($restoredRateLimited->shouldRelease); - $this->assertEquals('limiterName', $fetch('limiterName')); + $this->assertSame('limiterName', $fetch('limiterName')); $this->assertInstanceOf(RateLimiter::class, $fetch('limiter')); $this->assertInstanceOf(Redis::class, $fetch('redis')); } diff --git a/tests/Notifications/NotificationMailMessageTest.php b/tests/Notifications/NotificationMailMessageTest.php index f86949a5a369..e68e9a0a4620 100644 --- a/tests/Notifications/NotificationMailMessageTest.php +++ b/tests/Notifications/NotificationMailMessageTest.php @@ -172,7 +172,7 @@ public function testWhenCallbackWithReturn() public function testWhenCallbackWithDefault() { $callback = function (MailMessage $mailMessage, $condition) { - $this->assertEquals('truthy', $condition); + $this->assertSame('truthy', $condition); $mailMessage->cc('truthy@example.com'); }; @@ -237,7 +237,7 @@ public function testUnlessCallbackWithDefault() }; $default = function (MailMessage $mailMessage, $condition) { - $this->assertEquals('truthy', $condition); + $this->assertSame('truthy', $condition); $mailMessage->cc('truthy@example.com'); }; diff --git a/tests/Redis/RedisConnectorTest.php b/tests/Redis/RedisConnectorTest.php index 965ef46eb69a..07ec786fe2fd 100644 --- a/tests/Redis/RedisConnectorTest.php +++ b/tests/Redis/RedisConnectorTest.php @@ -41,7 +41,7 @@ public function testDefaultConfiguration() $phpRedisClient = $this->redis['phpredis']->connection()->client(); $this->assertEquals($host, $phpRedisClient->getHost()); $this->assertEquals($port, $phpRedisClient->getPort()); - $this->assertEquals('default', $phpRedisClient->client('GETNAME')); + $this->assertSame('default', $phpRedisClient->client('GETNAME')); } public function testUrl() diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index e7f7a464959e..ecbf2222398e 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3607,7 +3607,7 @@ public function testReduce($collection) 'foo' => 'bar', 'baz' => 'qux', ]); - $this->assertEquals('foobarbazqux', $data->reduce(function ($carry, $element, $key) { + $this->assertSame('foobarbazqux', $data->reduce(function ($carry, $element, $key) { return $carry .= $key.$element; })); } @@ -3621,7 +3621,7 @@ public function testReduceWithKeys($collection) 'foo' => 'bar', 'baz' => 'qux', ]); - $this->assertEquals('foobarbazqux', $data->reduceWithKeys(function ($carry, $element, $key) { + $this->assertSame('foobarbazqux', $data->reduceWithKeys(function ($carry, $element, $key) { return $carry .= $key.$element; })); } diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index c6cc6093224f..dc8ec88b5f57 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -528,8 +528,8 @@ public function invalidUuidList() public function testMarkdown() { - $this->assertEquals("

hello world

\n", Str::markdown('*hello world*')); - $this->assertEquals("

hello world

\n", Str::markdown('# hello world')); + $this->assertSame("

hello world

\n", Str::markdown('*hello world*')); + $this->assertSame("

hello world

\n", Str::markdown('# hello world')); } } diff --git a/tests/View/ViewTest.php b/tests/View/ViewTest.php index d4a3047a38de..308e2e81e0f7 100755 --- a/tests/View/ViewTest.php +++ b/tests/View/ViewTest.php @@ -127,12 +127,12 @@ public function testViewAcceptsArrayableImplementations() public function testViewGettersSetters() { $view = $this->getView(['foo' => 'bar']); - $this->assertEquals('view', $view->name()); - $this->assertEquals('path', $view->getPath()); + $this->assertSame('view', $view->name()); + $this->assertSame('path', $view->getPath()); $data = $view->getData(); - $this->assertEquals('bar', $data['foo']); + $this->assertSame('bar', $data['foo']); $view->setPath('newPath'); - $this->assertEquals('newPath', $view->getPath()); + $this->assertSame('newPath', $view->getPath()); } public function testViewArrayAccess() @@ -140,9 +140,9 @@ public function testViewArrayAccess() $view = $this->getView(['foo' => 'bar']); $this->assertInstanceOf(ArrayAccess::class, $view); $this->assertTrue($view->offsetExists('foo')); - $this->assertEquals('bar', $view->offsetGet('foo')); + $this->assertSame('bar', $view->offsetGet('foo')); $view->offsetSet('foo', 'baz'); - $this->assertEquals('baz', $view->offsetGet('foo')); + $this->assertSame('baz', $view->offsetGet('foo')); $view->offsetUnset('foo'); $this->assertFalse($view->offsetExists('foo')); } @@ -152,9 +152,9 @@ public function testViewConstructedWithObjectData() $view = $this->getView(new DataObjectStub); $this->assertInstanceOf(ArrayAccess::class, $view); $this->assertTrue($view->offsetExists('foo')); - $this->assertEquals('bar', $view->offsetGet('foo')); + $this->assertSame('bar', $view->offsetGet('foo')); $view->offsetSet('foo', 'baz'); - $this->assertEquals('baz', $view->offsetGet('foo')); + $this->assertSame('baz', $view->offsetGet('foo')); $view->offsetUnset('foo'); $this->assertFalse($view->offsetExists('foo')); } @@ -163,9 +163,9 @@ public function testViewMagicMethods() { $view = $this->getView(['foo' => 'bar']); $this->assertTrue(isset($view->foo)); - $this->assertEquals('bar', $view->foo); + $this->assertSame('bar', $view->foo); $view->foo = 'baz'; - $this->assertEquals('baz', $view->foo); + $this->assertSame('baz', $view->foo); $this->assertEquals($view['foo'], $view->foo); unset($view->foo); $this->assertFalse(isset($view->foo)); @@ -208,8 +208,8 @@ public function testViewRenderSections() $view->getFactory()->shouldReceive('getSections')->once()->andReturn(['foo', 'bar']); $sections = $view->renderSections(); - $this->assertEquals('foo', $sections[0]); - $this->assertEquals('bar', $sections[1]); + $this->assertSame('foo', $sections[0]); + $this->assertSame('bar', $sections[1]); } public function testWithErrors() @@ -219,18 +219,18 @@ public function testWithErrors() $this->assertSame($view, $view->withErrors($errors)); $this->assertInstanceOf(ViewErrorBag::class, $view->errors); $foo = $view->errors->get('foo'); - $this->assertEquals('bar', $foo[0]); + $this->assertSame('bar', $foo[0]); $qu = $view->errors->get('qu'); - $this->assertEquals('ux', $qu[0]); + $this->assertSame('ux', $qu[0]); $data = ['foo' => 'baz']; $this->assertSame($view, $view->withErrors(new MessageBag($data))); $foo = $view->errors->get('foo'); - $this->assertEquals('baz', $foo[0]); + $this->assertSame('baz', $foo[0]); $foo = $view->errors->getBag('default')->get('foo'); - $this->assertEquals('baz', $foo[0]); + $this->assertSame('baz', $foo[0]); $this->assertSame($view, $view->withErrors(new MessageBag($data), 'login')); $foo = $view->errors->getBag('login')->get('foo'); - $this->assertEquals('baz', $foo[0]); + $this->assertSame('baz', $foo[0]); } protected function getView($data = []) From 74c9365845225459349b76e759ad64daba1ddf45 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Fri, 19 Mar 2021 01:05:33 +0100 Subject: [PATCH 398/443] Remove empty constructor braces. (#36661) --- src/Illuminate/Collections/LazyCollection.php | 4 ++-- .../Providers/ArtisanServiceProvider.php | 2 +- src/Illuminate/Http/Testing/MimeType.php | 2 +- src/Illuminate/Mail/MailManager.php | 2 +- src/Illuminate/Support/Str.php | 2 +- .../Concerns/ValidatesAttributes.php | 12 +++++----- .../UsePusherChannelsNamesTest.php | 6 ++--- tests/Bus/BusBatchTest.php | 6 ++--- tests/Cache/CacheManagerTest.php | 4 ++-- tests/Console/CommandTest.php | 4 ++-- tests/Container/ContainerTaggingTest.php | 2 +- tests/Container/ContainerTest.php | 2 +- tests/Container/ResolvingCallbackTest.php | 2 +- .../AddQueuedCookiesToResponseTest.php | 6 ++--- .../Database/DatabaseEloquentBuilderTest.php | 10 ++++---- .../DatabaseEloquentCollectionTest.php | 16 ++++++------- .../DatabaseEloquentIrregularPluralTest.php | 2 +- tests/Database/DatabaseEloquentModelTest.php | 8 +++---- tests/Database/DatabaseEloquentPivotTest.php | 2 +- .../DatabaseMigrationRefreshCommandTest.php | 4 ++-- tests/Database/DatabaseMySqlBuilderTest.php | 4 ++-- .../Database/DatabasePostgresBuilderTest.php | 4 ++-- tests/Database/DatabaseQueryBuilderTest.php | 4 ++-- tests/Database/DatabaseSQLiteBuilderTest.php | 2 +- ...DatabaseSchemaBlueprintIntegrationTest.php | 16 ++++++------- .../DatabaseTransactionsManagerTest.php | 16 ++++++------- tests/Database/DatabaseTransactionsTest.php | 14 +++++------ tests/Database/SqlServerBuilderTest.php | 4 ++-- tests/Events/EventsSubscriberTest.php | 4 ++-- tests/Events/QueuedEventsTest.php | 4 ++-- .../Foundation/FoundationApplicationTest.php | 2 +- .../FoundationExceptionsHandlerTest.php | 6 ++--- .../ConvertEmptyStringsToNullTest.php | 2 +- .../Http/Middleware/TrimStringsTest.php | 2 +- .../Concerns/InteractsWithContainerTest.php | 2 +- tests/Integration/Auth/AuthenticationTest.php | 6 ++--- ...DatabaseEloquentModelCustomCastingTest.php | 2 +- .../Database/EloquentBelongsToManyTest.php | 2 +- .../Database/EloquentBelongsToTest.php | 2 +- .../Database/EloquentHasOneIsTest.php | 2 +- .../EloquentModelEncryptedCastingTest.php | 2 +- .../Database/EloquentModelJsonCastingTest.php | 2 +- .../Database/EloquentModelRefreshTest.php | 2 +- .../Database/EloquentMorphOneIsTest.php | 2 +- .../Database/EloquentMorphToIsTest.php | 2 +- .../Database/EloquentRelationshipsTest.php | 6 ++--- .../Database/SchemaBuilderTest.php | 4 ++-- .../Mail/SendingMailWithLocaleTest.php | 2 +- tests/Integration/Queue/JobChainingTest.php | 14 +++++------ tests/Integration/Queue/WorkCommandTest.php | 2 +- tests/Mail/MailLogTransportTest.php | 2 +- tests/Mail/MailSesTransportTest.php | 2 +- .../NotificationMailMessageTest.php | 24 +++++++++---------- ...NotificationSendQueuedNotificationTest.php | 4 ++-- .../Notifications/NotificationSenderTest.php | 6 ++--- tests/Redis/ConcurrentLimiterTest.php | 2 +- tests/Redis/RedisManagerExtensionTest.php | 6 ++--- tests/Support/SupportCollectionTest.php | 2 +- tests/Support/SupportReflectsClosuresTest.php | 2 +- tests/Testing/ParallelConsoleOutputTest.php | 2 +- tests/Testing/TestResponseTest.php | 14 +++++------ tests/Validation/ValidationValidatorTest.php | 2 +- tests/View/ComponentTest.php | 8 +++---- tests/View/ViewComponentTest.php | 4 ++-- 64 files changed, 158 insertions(+), 158 deletions(-) diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 9b90792925b4..fbf2dbe9c84c 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1071,7 +1071,7 @@ public function chunkWhile(callable $callback) return new static(function () use ($callback) { $iterator = $this->getIterator(); - $chunk = new Collection(); + $chunk = new Collection; if ($iterator->valid()) { $chunk[$iterator->key()] = $iterator->current(); @@ -1083,7 +1083,7 @@ public function chunkWhile(callable $callback) if (! $callback($iterator->current(), $iterator->key(), $chunk)) { yield new static($chunk); - $chunk = new Collection(); + $chunk = new Collection; } $chunk[$iterator->key()] = $iterator->current(); diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 4426e4b5d34c..a0dd7067b555 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -466,7 +466,7 @@ protected function registerEventClearCommand() protected function registerEventListCommand() { $this->app->singleton('command.event.list', function () { - return new EventListCommand(); + return new EventListCommand; }); } diff --git a/src/Illuminate/Http/Testing/MimeType.php b/src/Illuminate/Http/Testing/MimeType.php index aff03d4bbba6..d188a4be35e8 100644 --- a/src/Illuminate/Http/Testing/MimeType.php +++ b/src/Illuminate/Http/Testing/MimeType.php @@ -22,7 +22,7 @@ class MimeType public static function getMimeTypes() { if (self::$mime === null) { - self::$mime = new MimeTypes(); + self::$mime = new MimeTypes; } return self::$mime; diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index 86acdde3e3aa..8786414d8bdf 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -335,7 +335,7 @@ protected function createPostmarkTransport(array $config) $config['token'] ?? $this->app['config']->get('services.postmark.token'), $headers ), function ($transport) { - $transport->registerPlugin(new ThrowExceptionOnFailurePlugin()); + $transport->registerPlugin(new ThrowExceptionOnFailurePlugin); }); } diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 9fd8ccb98a57..5207bbdb0dff 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -779,7 +779,7 @@ public static function orderedUuid() return call_user_func(static::$uuidFactory); } - $factory = new UuidFactory(); + $factory = new UuidFactory; $factory->setRandomGenerator(new CombGenerator( $factory->getRandomGenerator(), diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 447585d25f5c..431b860bc20b 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -617,15 +617,15 @@ public function validateEmail($attribute, $value, $parameters) ->unique() ->map(function ($validation) { if ($validation === 'rfc') { - return new RFCValidation(); + return new RFCValidation; } elseif ($validation === 'strict') { - return new NoRFCWarningsValidation(); + return new NoRFCWarningsValidation; } elseif ($validation === 'dns') { - return new DNSCheckValidation(); + return new DNSCheckValidation; } elseif ($validation === 'spoof') { - return new SpoofCheckValidation(); + return new SpoofCheckValidation; } elseif ($validation === 'filter') { - return new FilterEmailValidation(); + return new FilterEmailValidation; } elseif ($validation === 'filter_unicode') { return FilterEmailValidation::unicode(); } elseif (is_string($validation) && class_exists($validation)) { @@ -633,7 +633,7 @@ public function validateEmail($attribute, $value, $parameters) } }) ->values() - ->all() ?: [new RFCValidation()]; + ->all() ?: [new RFCValidation]; return (new EmailValidator)->isValid($value, new MultipleValidationWithAnd($validations)); } diff --git a/tests/Broadcasting/UsePusherChannelsNamesTest.php b/tests/Broadcasting/UsePusherChannelsNamesTest.php index 5d6e908f5d57..b07dbb2fcc6a 100644 --- a/tests/Broadcasting/UsePusherChannelsNamesTest.php +++ b/tests/Broadcasting/UsePusherChannelsNamesTest.php @@ -13,7 +13,7 @@ class UsePusherChannelsNamesTest extends TestCase */ public function testChannelNameNormalization($requestChannelName, $normalizedName) { - $broadcaster = new FakeBroadcasterUsingPusherChannelsNames(); + $broadcaster = new FakeBroadcasterUsingPusherChannelsNames; $this->assertSame( $normalizedName, @@ -23,7 +23,7 @@ public function testChannelNameNormalization($requestChannelName, $normalizedNam public function testChannelNameNormalizationSpecialCase() { - $broadcaster = new FakeBroadcasterUsingPusherChannelsNames(); + $broadcaster = new FakeBroadcasterUsingPusherChannelsNames; $this->assertSame( 'private-123', @@ -36,7 +36,7 @@ public function testChannelNameNormalizationSpecialCase() */ public function testIsGuardedChannel($requestChannelName, $_, $guarded) { - $broadcaster = new FakeBroadcasterUsingPusherChannelsNames(); + $broadcaster = new FakeBroadcasterUsingPusherChannelsNames; $this->assertSame( $guarded, diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index cd2e06ee346a..8212298bc158 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -310,11 +310,11 @@ public function test_chain_can_be_added_to_batch() $batch = $this->createTestBatch($queue); - $chainHeadJob = new ChainHeadJob(); + $chainHeadJob = new ChainHeadJob; - $secondJob = new SecondTestJob(); + $secondJob = new SecondTestJob; - $thirdJob = new ThirdTestJob(); + $thirdJob = new ThirdTestJob; $queue->shouldReceive('connection')->once() ->with('test-connection') diff --git a/tests/Cache/CacheManagerTest.php b/tests/Cache/CacheManagerTest.php index 8a8d3446d173..dde234b01248 100644 --- a/tests/Cache/CacheManagerTest.php +++ b/tests/Cache/CacheManagerTest.php @@ -39,7 +39,7 @@ public function testForgetDriver() $cacheManager->shouldReceive('resolve') ->withArgs(['array']) ->times(4) - ->andReturn(new ArrayStore()); + ->andReturn(new ArrayStore); $cacheManager->shouldReceive('getDefaultDriver') ->once() @@ -64,7 +64,7 @@ public function testForgetDriverForgets() ], ]); $cacheManager->extend('forget', function () { - return new ArrayStore(); + return new ArrayStore; }); $cacheManager->store('forget')->forever('foo', 'bar'); diff --git a/tests/Console/CommandTest.php b/tests/Console/CommandTest.php index cc7a7403a9f8..e7f8d76ee858 100644 --- a/tests/Console/CommandTest.php +++ b/tests/Console/CommandTest.php @@ -33,7 +33,7 @@ public function handle() $command->setLaravel($application); $input = new ArrayInput([]); - $output = new NullOutput(); + $output = new NullOutput; $application->shouldReceive('make')->with(OutputStyle::class, ['input' => $input, 'output' => $output])->andReturn(m::mock(OutputStyle::class)); $application->shouldReceive('call')->with([$command, 'handle'])->andReturnUsing(function () use ($command, $application) { @@ -84,7 +84,7 @@ protected function getOptions() '--option-one' => 'test-first-option', '--option-two' => 'test-second-option', ]); - $output = new NullOutput(); + $output = new NullOutput; $command->run($input, $output); diff --git a/tests/Container/ContainerTaggingTest.php b/tests/Container/ContainerTaggingTest.php index 754c977e3c12..5cbc8ea57d91 100644 --- a/tests/Container/ContainerTaggingTest.php +++ b/tests/Container/ContainerTaggingTest.php @@ -48,7 +48,7 @@ public function testContainerTags() public function testTaggedServicesAreLazyLoaded() { $container = $this->createPartialMock(Container::class, ['make']); - $container->expects($this->once())->method('make')->willReturn(new ContainerImplementationTaggedStub()); + $container->expects($this->once())->method('make')->willReturn(new ContainerImplementationTaggedStub); $container->tag(ContainerImplementationTaggedStub::class, ['foo']); $container->tag(ContainerImplementationTaggedStubTwo::class, ['foo']); diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index d3c88e26ed3a..5cdb0204ddd9 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -127,7 +127,7 @@ public function testBindFailsLoudlyWithInvalidArgument() $this->expectException(TypeError::class); $container = new Container; - $concrete = new ContainerConcreteStub(); + $concrete = new ContainerConcreteStub; $container->bind(ContainerConcreteStub::class, $concrete); } diff --git a/tests/Container/ResolvingCallbackTest.php b/tests/Container/ResolvingCallbackTest.php index e8aeecb73a68..91a749710388 100644 --- a/tests/Container/ResolvingCallbackTest.php +++ b/tests/Container/ResolvingCallbackTest.php @@ -303,7 +303,7 @@ public function testResolvingCallbacksAreCallWhenRebindHappenForResolvedAbstract $this->assertEquals(3, $callCounter); $container->bind(ResolvingContractStub::class, function () { - return new ResolvingImplementationStubTwo(); + return new ResolvingImplementationStubTwo; }); $this->assertEquals(4, $callCounter); diff --git a/tests/Cookie/Middleware/AddQueuedCookiesToResponseTest.php b/tests/Cookie/Middleware/AddQueuedCookiesToResponseTest.php index 335fa4e9beab..48447c2d3501 100644 --- a/tests/Cookie/Middleware/AddQueuedCookiesToResponseTest.php +++ b/tests/Cookie/Middleware/AddQueuedCookiesToResponseTest.php @@ -13,14 +13,14 @@ class AddQueuedCookiesToResponseTest extends TestCase { public function testHandle(): void { - $cookieJar = new CookieJar(); + $cookieJar = new CookieJar; $cookieOne = $cookieJar->make('foo', 'bar', 0, '/path'); $cookieTwo = $cookieJar->make('foo', 'rab', 0, '/'); $cookieJar->queue($cookieOne); $cookieJar->queue($cookieTwo); $addQueueCookiesToResponseMiddleware = new AddQueuedCookiesToResponse($cookieJar); $next = function (Request $request) { - return new Response(); + return new Response; }; $this->assertEquals( [ @@ -33,7 +33,7 @@ public function testHandle(): void ], ], ], - $addQueueCookiesToResponseMiddleware->handle(new Request(), $next)->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY) + $addQueueCookiesToResponseMiddleware->handle(new Request, $next)->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY) ); } } diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 27f57d1f8e87..b4eec40cfc8a 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -660,7 +660,7 @@ public function testQueryPassThru() $this->assertSame('foo', $builder->raw('bar')); $builder = $this->getBuilder(); - $grammar = new Grammar(); + $grammar = new Grammar; $builder->getQuery()->shouldReceive('getGrammar')->once()->andReturn($grammar); $this->assertSame($grammar, $builder->getGrammar()); } @@ -1097,7 +1097,7 @@ public function testWhereKeyMethodWithInt() public function testWhereKeyMethodWithStringZero() { - $model = new EloquentBuilderTestStubStringPrimaryKey(); + $model = new EloquentBuilderTestStubStringPrimaryKey; $builder = $this->getBuilder()->setModel($model); $keyName = $model->getQualifiedKeyName(); @@ -1110,7 +1110,7 @@ public function testWhereKeyMethodWithStringZero() public function testWhereKeyMethodWithStringNull() { - $model = new EloquentBuilderTestStubStringPrimaryKey(); + $model = new EloquentBuilderTestStubStringPrimaryKey; $builder = $this->getBuilder()->setModel($model); $keyName = $model->getQualifiedKeyName(); @@ -1149,7 +1149,7 @@ public function testWhereKeyMethodWithCollection() public function testWhereKeyNotMethodWithStringZero() { - $model = new EloquentBuilderTestStubStringPrimaryKey(); + $model = new EloquentBuilderTestStubStringPrimaryKey; $builder = $this->getBuilder()->setModel($model); $keyName = $model->getQualifiedKeyName(); @@ -1162,7 +1162,7 @@ public function testWhereKeyNotMethodWithStringZero() public function testWhereKeyNotMethodWithStringNull() { - $model = new EloquentBuilderTestStubStringPrimaryKey(); + $model = new EloquentBuilderTestStubStringPrimaryKey; $builder = $this->getBuilder()->setModel($model); $keyName = $model->getQualifiedKeyName(); diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index 0f2ffa48490b..34df7c07672d 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -278,10 +278,10 @@ public function testCollectionDiffsWithGivenCollection() public function testCollectionReturnsDuplicateBasedOnlyOnKeys() { - $one = new TestEloquentCollectionModel(); - $two = new TestEloquentCollectionModel(); - $three = new TestEloquentCollectionModel(); - $four = new TestEloquentCollectionModel(); + $one = new TestEloquentCollectionModel; + $two = new TestEloquentCollectionModel; + $three = new TestEloquentCollectionModel; + $four = new TestEloquentCollectionModel; $one->id = 1; $one->someAttribute = '1'; $two->id = 1; @@ -346,10 +346,10 @@ public function testCollectionReturnsUniqueItems() public function testCollectionReturnsUniqueStrictBasedOnKeysOnly() { - $one = new TestEloquentCollectionModel(); - $two = new TestEloquentCollectionModel(); - $three = new TestEloquentCollectionModel(); - $four = new TestEloquentCollectionModel(); + $one = new TestEloquentCollectionModel; + $two = new TestEloquentCollectionModel; + $three = new TestEloquentCollectionModel; + $four = new TestEloquentCollectionModel; $one->id = 1; $one->someAttribute = '1'; $two->id = 1; diff --git a/tests/Database/DatabaseEloquentIrregularPluralTest.php b/tests/Database/DatabaseEloquentIrregularPluralTest.php index 8c73974d4565..4342ca5c541c 100644 --- a/tests/Database/DatabaseEloquentIrregularPluralTest.php +++ b/tests/Database/DatabaseEloquentIrregularPluralTest.php @@ -70,7 +70,7 @@ protected function schema() /** @test */ public function itPluralizesTheTableName() { - $model = new IrregularPluralHuman(); + $model = new IrregularPluralHuman; $this->assertSame('irregular_plural_humans', $model->getTable()); } diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index b5049151adab..4c2210be5106 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -72,7 +72,7 @@ public function testAttributeManipulation() public function testSetAttributeWithNumericKey() { - $model = new EloquentDateModelStub(); + $model = new EloquentDateModelStub; $model->setAttribute(0, 'value'); $this->assertEquals([0 => 'value'], $model->getAttributes()); @@ -95,7 +95,7 @@ public function testDirtyAttributes() public function testIntAndNullComparisonWhenDirty() { - $model = new EloquentModelCastingStub(); + $model = new EloquentModelCastingStub; $model->intAttribute = null; $model->syncOriginal(); $this->assertFalse($model->isDirty('intAttribute')); @@ -105,7 +105,7 @@ public function testIntAndNullComparisonWhenDirty() public function testFloatAndNullComparisonWhenDirty() { - $model = new EloquentModelCastingStub(); + $model = new EloquentModelCastingStub; $model->floatAttribute = null; $model->syncOriginal(); $this->assertFalse($model->isDirty('floatAttribute')); @@ -2110,7 +2110,7 @@ public function testNotTouchingModelWithoutTimestamps() public function testGetOriginalCastsAttributes() { - $model = new EloquentModelCastingStub(); + $model = new EloquentModelCastingStub; $model->intAttribute = '1'; $model->floatAttribute = '0.1234'; $model->stringAttribute = 432; diff --git a/tests/Database/DatabaseEloquentPivotTest.php b/tests/Database/DatabaseEloquentPivotTest.php index b2fbba69d99c..50beacb588da 100755 --- a/tests/Database/DatabaseEloquentPivotTest.php +++ b/tests/Database/DatabaseEloquentPivotTest.php @@ -156,7 +156,7 @@ public function testPivotModelWithoutParentReturnsModelTimestampColumns() public function testWithoutRelations() { - $original = new Pivot(); + $original = new Pivot; $original->pivotParent = 'foo'; $original->setRelation('bar', 'baz'); diff --git a/tests/Database/DatabaseMigrationRefreshCommandTest.php b/tests/Database/DatabaseMigrationRefreshCommandTest.php index ce11dd67fc52..8502fdfe8450 100755 --- a/tests/Database/DatabaseMigrationRefreshCommandTest.php +++ b/tests/Database/DatabaseMigrationRefreshCommandTest.php @@ -24,7 +24,7 @@ protected function tearDown(): void public function testRefreshCommandCallsCommandsWithProperArguments() { - $command = new RefreshCommand(); + $command = new RefreshCommand; $app = new ApplicationDatabaseRefreshStub(['path.database' => __DIR__]); $dispatcher = $app->instance(Dispatcher::class, $events = m::mock()); @@ -49,7 +49,7 @@ public function testRefreshCommandCallsCommandsWithProperArguments() public function testRefreshCommandCallsCommandsWithStep() { - $command = new RefreshCommand(); + $command = new RefreshCommand; $app = new ApplicationDatabaseRefreshStub(['path.database' => __DIR__]); $dispatcher = $app->instance(Dispatcher::class, $events = m::mock()); diff --git a/tests/Database/DatabaseMySqlBuilderTest.php b/tests/Database/DatabaseMySqlBuilderTest.php index dd36209eb40e..464ce75c741f 100644 --- a/tests/Database/DatabaseMySqlBuilderTest.php +++ b/tests/Database/DatabaseMySqlBuilderTest.php @@ -17,7 +17,7 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new MySqlGrammar(); + $grammar = new MySqlGrammar; $connection = m::mock(Connection::class); $connection->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8mb4'); @@ -33,7 +33,7 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new MySqlGrammar(); + $grammar = new MySqlGrammar; $connection = m::mock(Connection::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index 490f66cb4ad8..6587d31ad2e6 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -17,7 +17,7 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new PostgresGrammar(); + $grammar = new PostgresGrammar; $connection = m::mock(Connection::class); $connection->shouldReceive('getConfig')->once()->with('charset')->andReturn('utf8'); @@ -32,7 +32,7 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new PostgresGrammar(); + $grammar = new PostgresGrammar; $connection = m::mock(Connection::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 39597512a21f..0fed6c3a1ba9 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -1976,7 +1976,7 @@ public function testExistsOr() $builder = $this->getBuilder(); $builder->getConnection()->shouldReceive('select')->andReturn([['exists' => 0]]); $results = $builder->from('users')->doesntExistOr(function () { - throw new RuntimeException(); + throw new RuntimeException; }); $this->assertTrue($results); } @@ -1992,7 +1992,7 @@ public function testDoesntExistsOr() $builder = $this->getBuilder(); $builder->getConnection()->shouldReceive('select')->andReturn([['exists' => 1]]); $results = $builder->from('users')->existsOr(function () { - throw new RuntimeException(); + throw new RuntimeException; }); $this->assertTrue($results); } diff --git a/tests/Database/DatabaseSQLiteBuilderTest.php b/tests/Database/DatabaseSQLiteBuilderTest.php index b2587ea67d82..4b4ab452dc35 100644 --- a/tests/Database/DatabaseSQLiteBuilderTest.php +++ b/tests/Database/DatabaseSQLiteBuilderTest.php @@ -15,7 +15,7 @@ class DatabaseSQLiteBuilderTest extends TestCase { protected function setUp(): void { - $app = new Container(); + $app = new Container; Container::setInstance($app) ->singleton('files', Filesystem::class); diff --git a/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php b/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php index 794d6380a8ab..635921019d4c 100644 --- a/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php +++ b/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php @@ -169,7 +169,7 @@ public function testAddUniqueIndexWithoutNameWorks() $table->string('name')->nullable()->unique()->change(); }); - $queries = $blueprintMySql->toSql($this->db->connection(), new MySqlGrammar()); + $queries = $blueprintMySql->toSql($this->db->connection(), new MySqlGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -186,7 +186,7 @@ public function testAddUniqueIndexWithoutNameWorks() $table->string('name')->nullable()->unique()->change(); }); - $queries = $blueprintPostgres->toSql($this->db->connection(), new PostgresGrammar()); + $queries = $blueprintPostgres->toSql($this->db->connection(), new PostgresGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -203,7 +203,7 @@ public function testAddUniqueIndexWithoutNameWorks() $table->string('name')->nullable()->unique()->change(); }); - $queries = $blueprintSQLite->toSql($this->db->connection(), new SQLiteGrammar()); + $queries = $blueprintSQLite->toSql($this->db->connection(), new SQLiteGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -220,7 +220,7 @@ public function testAddUniqueIndexWithoutNameWorks() $table->string('name')->nullable()->unique()->change(); }); - $queries = $blueprintSqlServer->toSql($this->db->connection(), new SqlServerGrammar()); + $queries = $blueprintSqlServer->toSql($this->db->connection(), new SqlServerGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -244,7 +244,7 @@ public function testAddUniqueIndexWithNameWorks() $table->string('name')->nullable()->unique('index1')->change(); }); - $queries = $blueprintMySql->toSql($this->db->connection(), new MySqlGrammar()); + $queries = $blueprintMySql->toSql($this->db->connection(), new MySqlGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -261,7 +261,7 @@ public function testAddUniqueIndexWithNameWorks() $table->unsignedInteger('name')->nullable()->unique('index1')->change(); }); - $queries = $blueprintPostgres->toSql($this->db->connection(), new PostgresGrammar()); + $queries = $blueprintPostgres->toSql($this->db->connection(), new PostgresGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -278,7 +278,7 @@ public function testAddUniqueIndexWithNameWorks() $table->unsignedInteger('name')->nullable()->unique('index1')->change(); }); - $queries = $blueprintSQLite->toSql($this->db->connection(), new SQLiteGrammar()); + $queries = $blueprintSQLite->toSql($this->db->connection(), new SQLiteGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', @@ -295,7 +295,7 @@ public function testAddUniqueIndexWithNameWorks() $table->unsignedInteger('name')->nullable()->unique('index1')->change(); }); - $queries = $blueprintSqlServer->toSql($this->db->connection(), new SqlServerGrammar()); + $queries = $blueprintSqlServer->toSql($this->db->connection(), new SqlServerGrammar); $expected = [ 'CREATE TEMPORARY TABLE __temp__users AS SELECT name FROM users', diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php index 4118180a12c7..e8d82e048720 100755 --- a/tests/Database/DatabaseTransactionsManagerTest.php +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -9,7 +9,7 @@ class DatabaseTransactionsManagerTest extends TestCase { public function testBeginningTransactions() { - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); $manager->begin('default', 2); @@ -26,7 +26,7 @@ public function testBeginningTransactions() public function testRollingBackTransactions() { - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); $manager->begin('default', 2); @@ -45,7 +45,7 @@ public function testRollingBackTransactions() public function testRollingBackTransactionsAllTheWay() { - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); $manager->begin('default', 2); @@ -61,7 +61,7 @@ public function testRollingBackTransactionsAllTheWay() public function testCommittingTransactions() { - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); $manager->begin('default', 2); @@ -79,7 +79,7 @@ public function testCallbacksAreAddedToTheCurrentTransaction() { $callbacks = []; - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); @@ -102,7 +102,7 @@ public function testCommittingTransactionsExecutesCallbacks() { $callbacks = []; - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); @@ -129,7 +129,7 @@ public function testCommittingExecutesOnlyCallbacksOfTheConnection() { $callbacks = []; - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->begin('default', 1); @@ -154,7 +154,7 @@ public function testCallbackIsExecutedIfNoTransactions() { $callbacks = []; - $manager = (new DatabaseTransactionsManager()); + $manager = (new DatabaseTransactionsManager); $manager->addCallback(function () use (&$callbacks) { $callbacks[] = ['default', 1]; diff --git a/tests/Database/DatabaseTransactionsTest.php b/tests/Database/DatabaseTransactionsTest.php index 94e3b7d86f2d..167dbaee6a48 100644 --- a/tests/Database/DatabaseTransactionsTest.php +++ b/tests/Database/DatabaseTransactionsTest.php @@ -62,7 +62,7 @@ protected function tearDown(): void public function testTransactionIsRecordedAndCommitted() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('commit')->once()->with('default'); @@ -81,7 +81,7 @@ public function testTransactionIsRecordedAndCommitted() public function testTransactionIsRecordedAndCommittedUsingTheSeparateMethods() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('commit')->once()->with('default'); @@ -100,7 +100,7 @@ public function testTransactionIsRecordedAndCommittedUsingTheSeparateMethods() public function testNestedTransactionIsRecordedAndCommitted() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('begin')->once()->with('default', 2); $transactionManager->shouldReceive('commit')->once()->with('default'); @@ -126,7 +126,7 @@ public function testNestedTransactionIsRecordedAndCommitted() public function testNestedTransactionIsRecordeForDifferentConnectionsdAndCommitted() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('begin')->once()->with('second_connection', 1); $transactionManager->shouldReceive('begin')->once()->with('second_connection', 2); @@ -161,7 +161,7 @@ public function testNestedTransactionIsRecordeForDifferentConnectionsdAndCommitt public function testTransactionIsRolledBack() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('rollback')->once()->with('default', 0); $transactionManager->shouldNotReceive('commit'); @@ -186,7 +186,7 @@ public function testTransactionIsRolledBack() public function testTransactionIsRolledBackUsingSeparateMethods() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('rollback')->once()->with('default', 0); $transactionManager->shouldNotReceive('commit'); @@ -208,7 +208,7 @@ public function testTransactionIsRolledBackUsingSeparateMethods() public function testNestedTransactionsAreRolledBack() { - $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager = m::mock(new DatabaseTransactionsManager); $transactionManager->shouldReceive('begin')->once()->with('default', 1); $transactionManager->shouldReceive('begin')->once()->with('default', 2); $transactionManager->shouldReceive('rollback')->once()->with('default', 1); diff --git a/tests/Database/SqlServerBuilderTest.php b/tests/Database/SqlServerBuilderTest.php index de82f796056c..039cadb8394a 100644 --- a/tests/Database/SqlServerBuilderTest.php +++ b/tests/Database/SqlServerBuilderTest.php @@ -17,7 +17,7 @@ protected function tearDown(): void public function testCreateDatabase() { - $grammar = new SqlServerGrammar(); + $grammar = new SqlServerGrammar; $connection = m::mock(Connection::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); @@ -31,7 +31,7 @@ public function testCreateDatabase() public function testDropDatabaseIfExists() { - $grammar = new SqlServerGrammar(); + $grammar = new SqlServerGrammar; $connection = m::mock(Connection::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); diff --git a/tests/Events/EventsSubscriberTest.php b/tests/Events/EventsSubscriberTest.php index 2cc47f1aa114..2b69c47c45d1 100644 --- a/tests/Events/EventsSubscriberTest.php +++ b/tests/Events/EventsSubscriberTest.php @@ -27,7 +27,7 @@ public function testEventSubscribers() public function testEventSubscribeCanAcceptObject() { - $d = new Dispatcher(); + $d = new Dispatcher; $subs = m::mock(ExampleSubscriber::class); $subs->shouldReceive('subscribe')->once()->with($d); @@ -37,7 +37,7 @@ public function testEventSubscribeCanAcceptObject() public function testEventSubscribeCanReturnMappings() { - $d = new Dispatcher(); + $d = new Dispatcher; $d->subscribe(DeclarativeSubscriber::class); $d->dispatch('myEvent1'); diff --git a/tests/Events/QueuedEventsTest.php b/tests/Events/QueuedEventsTest.php index 148fcdb235bb..134432c291c0 100644 --- a/tests/Events/QueuedEventsTest.php +++ b/tests/Events/QueuedEventsTest.php @@ -39,7 +39,7 @@ public function testCustomizedQueuedEventHandlersAreQueued() { $d = new Dispatcher; - $fakeQueue = new QueueFake(new Container()); + $fakeQueue = new QueueFake(new Container); $d->setQueueResolver(function () use ($fakeQueue) { return $fakeQueue; @@ -55,7 +55,7 @@ public function testQueueIsSetByGetQueue() { $d = new Dispatcher; - $fakeQueue = new QueueFake(new Container()); + $fakeQueue = new QueueFake(new Container); $d->setQueueResolver(function () use ($fakeQueue) { return $fakeQueue; diff --git a/tests/Foundation/FoundationApplicationTest.php b/tests/Foundation/FoundationApplicationTest.php index 0f0c4b636f21..51f1eac0f500 100755 --- a/tests/Foundation/FoundationApplicationTest.php +++ b/tests/Foundation/FoundationApplicationTest.php @@ -430,7 +430,7 @@ public function testEnvPathsAreUsedAndMadeAbsoluteForCachePathsWhenSpecifiedAsRe public function testEnvPathsAreUsedAndMadeAbsoluteForCachePathsWhenSpecifiedAsRelativeWithNullBasePath() { - $app = new Application(); + $app = new Application; $_SERVER['APP_SERVICES_CACHE'] = 'relative/path/services.php'; $_SERVER['APP_PACKAGES_CACHE'] = 'relative/path/packages.php'; $_SERVER['APP_CONFIG_CACHE'] = 'relative/path/config.php'; diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index 755a01d9f31e..90f701ece326 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -150,7 +150,7 @@ public function testReturnsCustomResponseFromRenderableCallback() public function testReturnsCustomResponseFromCallableClass() { - $this->handler->renderable(new CustomRenderer()); + $this->handler->renderable(new CustomRenderer); $response = $this->handler->render($this->request, new CustomException)->getContent(); @@ -274,7 +274,7 @@ public function testRecordsNotFoundReturns404WithoutReporting() $this->config->shouldReceive('get')->with('app.debug', null)->once()->andReturn(true); $this->request->shouldReceive('expectsJson')->once()->andReturn(true); - $response = $this->handler->render($this->request, new RecordsNotFoundException()); + $response = $this->handler->render($this->request, new RecordsNotFoundException); $this->assertEquals(404, $response->getStatusCode()); $this->assertStringContainsString('"message": "Not found."', $response->getContent()); @@ -283,7 +283,7 @@ public function testRecordsNotFoundReturns404WithoutReporting() $this->container->instance(LoggerInterface::class, $logger); $logger->shouldNotReceive('error'); - $this->handler->report(new RecordsNotFoundException()); + $this->handler->report(new RecordsNotFoundException); } } diff --git a/tests/Foundation/Http/Middleware/ConvertEmptyStringsToNullTest.php b/tests/Foundation/Http/Middleware/ConvertEmptyStringsToNullTest.php index 6e3d767b125d..02913813e7bc 100644 --- a/tests/Foundation/Http/Middleware/ConvertEmptyStringsToNullTest.php +++ b/tests/Foundation/Http/Middleware/ConvertEmptyStringsToNullTest.php @@ -11,7 +11,7 @@ class ConvertEmptyStringsToNullTest extends TestCase { public function testConvertsEmptyStringsToNull() { - $middleware = new ConvertEmptyStringsToNull(); + $middleware = new ConvertEmptyStringsToNull; $symfonyRequest = new SymfonyRequest([ 'foo' => 'bar', 'baz' => '', diff --git a/tests/Foundation/Http/Middleware/TrimStringsTest.php b/tests/Foundation/Http/Middleware/TrimStringsTest.php index 1561eab6b03c..33262af684f7 100644 --- a/tests/Foundation/Http/Middleware/TrimStringsTest.php +++ b/tests/Foundation/Http/Middleware/TrimStringsTest.php @@ -11,7 +11,7 @@ class TrimStringsTest extends TestCase { public function testTrimStringsIgnoringExceptAttribute() { - $middleware = new TrimStringsWithExceptAttribute(); + $middleware = new TrimStringsWithExceptAttribute; $symfonyRequest = new SymfonyRequest([ 'abc' => ' 123 ', 'xyz' => ' 456 ', diff --git a/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php b/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php index 1d11691b9771..f4ae9c17818b 100644 --- a/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php +++ b/tests/Foundation/Testing/Concerns/InteractsWithContainerTest.php @@ -18,7 +18,7 @@ public function testWithoutMixBindsEmptyHandlerAndReturnsInstance() public function testWithMixRestoresOriginalHandlerAndReturnsInstance() { - $handler = new stdClass(); + $handler = new stdClass; $this->app->instance(Mix::class, $handler); $this->withoutMix(); diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index e2ec79050d18..6f3dbce1a343 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -313,7 +313,7 @@ public function testDispatcherChangesIfThereIsOneOnTheCustomAuthGuard() ]; Auth::extend('myCustomDriver', function () { - return new MyCustomGuardStub(); + return new MyCustomGuardStub; }); $this->assertInstanceOf(MyCustomGuardStub::class, $this->app['auth']->guard('myGuard')); @@ -333,7 +333,7 @@ public function testHasNoProblemIfThereIsNoDispatchingTheAuthCustomGuard() ]; Auth::extend('myCustomDriver', function () { - return new MyDispatcherLessCustomGuardStub(); + return new MyDispatcherLessCustomGuardStub; }); $this->assertInstanceOf(MyDispatcherLessCustomGuardStub::class, $this->app['auth']->guard('myGuard')); @@ -350,7 +350,7 @@ class MyCustomGuardStub public function __construct() { - $this->setDispatcher(new Dispatcher()); + $this->setDispatcher(new Dispatcher); } public function setDispatcher(Dispatcher $events) diff --git a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php index bbbb1bc3e50d..c5fb6636b4d3 100644 --- a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php +++ b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php @@ -447,7 +447,7 @@ class ValueObjectWithCasterInstance extends ValueObject { public static function castUsing(array $arguments) { - return new ValueObjectCaster(); + return new ValueObjectCaster; } } diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index b66cd3d3f34c..6ab1dd6f55fd 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -349,7 +349,7 @@ public function testFindMethod() $this->assertEquals($tag2->name, $post->tags()->find($tag2->id)->name); $this->assertCount(0, $post->tags()->findMany([])); $this->assertCount(2, $post->tags()->findMany([$tag->id, $tag2->id])); - $this->assertCount(0, $post->tags()->findMany(new Collection())); + $this->assertCount(0, $post->tags()->findMany(new Collection)); $this->assertCount(2, $post->tags()->findMany(new Collection([$tag->id, $tag2->id]))); } diff --git a/tests/Integration/Database/EloquentBelongsToTest.php b/tests/Integration/Database/EloquentBelongsToTest.php index e04e39deba50..eb7a59e27f97 100644 --- a/tests/Integration/Database/EloquentBelongsToTest.php +++ b/tests/Integration/Database/EloquentBelongsToTest.php @@ -96,7 +96,7 @@ public function testParentIsModel() public function testParentIsNotAnotherModel() { $child = User::has('parent')->first(); - $parent = new User(); + $parent = new User; $parent->id = 3; $this->assertFalse($child->parent()->is($parent)); diff --git a/tests/Integration/Database/EloquentHasOneIsTest.php b/tests/Integration/Database/EloquentHasOneIsTest.php index 74f76e56ffe6..85c7db998aa0 100644 --- a/tests/Integration/Database/EloquentHasOneIsTest.php +++ b/tests/Integration/Database/EloquentHasOneIsTest.php @@ -51,7 +51,7 @@ public function testChildIsModel() public function testChildIsNotAnotherModel() { $parent = Post::first(); - $child = new Attachment(); + $child = new Attachment; $child->id = 2; $this->assertFalse($parent->attachment()->is($child)); diff --git a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php index c89b81bbeed0..abe44ad7a2b5 100644 --- a/tests/Integration/Database/EloquentModelEncryptedCastingTest.php +++ b/tests/Integration/Database/EloquentModelEncryptedCastingTest.php @@ -131,7 +131,7 @@ public function testJsonAttributeIsCastable() public function testObjectIsCastable() { - $object = new stdClass(); + $object = new stdClass; $object->key1 = 'value1'; $this->encrypter->expects('encrypt') diff --git a/tests/Integration/Database/EloquentModelJsonCastingTest.php b/tests/Integration/Database/EloquentModelJsonCastingTest.php index a7487333916e..48707a89c7c8 100644 --- a/tests/Integration/Database/EloquentModelJsonCastingTest.php +++ b/tests/Integration/Database/EloquentModelJsonCastingTest.php @@ -52,7 +52,7 @@ public function testArraysAreCastable() public function testObjectsAreCastable() { - $object = new stdClass(); + $object = new stdClass; $object->key1 = 'value1'; /** @var \Illuminate\Tests\Integration\Database\EloquentModelJsonCastingTest\JsonCast $user */ diff --git a/tests/Integration/Database/EloquentModelRefreshTest.php b/tests/Integration/Database/EloquentModelRefreshTest.php index 18b648d7f0d4..626bacab5cbb 100644 --- a/tests/Integration/Database/EloquentModelRefreshTest.php +++ b/tests/Integration/Database/EloquentModelRefreshTest.php @@ -100,7 +100,7 @@ class AsPivotPost extends Post public function children() { return $this - ->belongsToMany(static::class, (new AsPivotPostPivot())->getTable(), 'foreign_id', 'related_id') + ->belongsToMany(static::class, (new AsPivotPostPivot)->getTable(), 'foreign_id', 'related_id') ->using(AsPivotPostPivot::class); } } diff --git a/tests/Integration/Database/EloquentMorphOneIsTest.php b/tests/Integration/Database/EloquentMorphOneIsTest.php index 7d670264aac2..96d40842e436 100644 --- a/tests/Integration/Database/EloquentMorphOneIsTest.php +++ b/tests/Integration/Database/EloquentMorphOneIsTest.php @@ -52,7 +52,7 @@ public function testChildIsModel() public function testChildIsNotAnotherModel() { $parent = Post::first(); - $child = new Attachment(); + $child = new Attachment; $child->id = 2; $this->assertFalse($parent->attachment()->is($child)); diff --git a/tests/Integration/Database/EloquentMorphToIsTest.php b/tests/Integration/Database/EloquentMorphToIsTest.php index dbc33ed48c73..fa2daaf1a7f0 100644 --- a/tests/Integration/Database/EloquentMorphToIsTest.php +++ b/tests/Integration/Database/EloquentMorphToIsTest.php @@ -52,7 +52,7 @@ public function testParentIsModel() public function testParentIsNotAnotherModel() { $child = Comment::first(); - $parent = new Post(); + $parent = new Post; $parent->id = 2; $this->assertFalse($child->commentable()->is($parent)); diff --git a/tests/Integration/Database/EloquentRelationshipsTest.php b/tests/Integration/Database/EloquentRelationshipsTest.php index 650d7e41c59d..155ed617e5ad 100644 --- a/tests/Integration/Database/EloquentRelationshipsTest.php +++ b/tests/Integration/Database/EloquentRelationshipsTest.php @@ -56,11 +56,11 @@ public function testOverriddenRelationships() public function testAlwaysUnsetBelongsToRelationWhenReceivedModelId() { // create users - $user1 = (new FakeRelationship())->forceFill(['id' => 1]); - $user2 = (new FakeRelationship())->forceFill(['id' => 2]); + $user1 = (new FakeRelationship)->forceFill(['id' => 1]); + $user2 = (new FakeRelationship)->forceFill(['id' => 2]); // sync user 1 using Model - $post = new Post(); + $post = new Post; $post->author()->associate($user1); $post->syncOriginal(); diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 8b18d7b17d44..6c27935c7e2d 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -61,9 +61,9 @@ public function testRegisterCustomDoctrineType() 'DROP TABLE __temp__test', ]; - $statements = $blueprint->toSql($this->getConnection(), new SQLiteGrammar()); + $statements = $blueprint->toSql($this->getConnection(), new SQLiteGrammar); - $blueprint->build($this->getConnection(), new SQLiteGrammar()); + $blueprint->build($this->getConnection(), new SQLiteGrammar); $this->assertArrayHasKey(TinyInteger::NAME, Type::getTypesMap()); $this->assertSame('tinyinteger', Schema::getColumnType('test', 'test_column')); diff --git a/tests/Integration/Mail/SendingMailWithLocaleTest.php b/tests/Integration/Mail/SendingMailWithLocaleTest.php index 951d00a9e157..de1c12ee1008 100644 --- a/tests/Integration/Mail/SendingMailWithLocaleTest.php +++ b/tests/Integration/Mail/SendingMailWithLocaleTest.php @@ -67,7 +67,7 @@ public function testMailIsSentWithSelectedLocale() public function testMailIsSentWithLocaleFromMailable() { - $mailable = new TestMail(); + $mailable = new TestMail; $mailable->locale('ar'); Mail::to('test@mail.com')->send($mailable); diff --git a/tests/Integration/Queue/JobChainingTest.php b/tests/Integration/Queue/JobChainingTest.php index 5f4d143b5b51..337bfcd5b197 100644 --- a/tests/Integration/Queue/JobChainingTest.php +++ b/tests/Integration/Queue/JobChainingTest.php @@ -63,8 +63,8 @@ public function testJobsCanBeChainedOnSuccessUsingPendingChain() public function testJobsCanBeChainedOnSuccessUsingBusFacade() { Bus::dispatchChain([ - new JobChainingTestFirstJob(), - new JobChainingTestSecondJob(), + new JobChainingTestFirstJob, + new JobChainingTestSecondJob, ]); $this->assertTrue(JobChainingTestFirstJob::$ran); @@ -74,8 +74,8 @@ public function testJobsCanBeChainedOnSuccessUsingBusFacade() public function testJobsCanBeChainedOnSuccessUsingBusFacadeAsArguments() { Bus::dispatchChain( - new JobChainingTestFirstJob(), - new JobChainingTestSecondJob() + new JobChainingTestFirstJob, + new JobChainingTestSecondJob ); $this->assertTrue(JobChainingTestFirstJob::$ran); @@ -156,9 +156,9 @@ public function testThirdJobIsNotFiredIfSecondFails() public function testCatchCallbackIsCalledOnFailure() { Bus::chain([ - new JobChainingTestFirstJob(), - new JobChainingTestFailingJob(), - new JobChainingTestSecondJob(), + new JobChainingTestFirstJob, + new JobChainingTestFailingJob, + new JobChainingTestSecondJob, ])->catch(static function () { self::$catchCallbackRan = true; })->dispatch(); diff --git a/tests/Integration/Queue/WorkCommandTest.php b/tests/Integration/Queue/WorkCommandTest.php index 26ea5921ba40..c41939328fa1 100644 --- a/tests/Integration/Queue/WorkCommandTest.php +++ b/tests/Integration/Queue/WorkCommandTest.php @@ -119,7 +119,7 @@ public function testMaxJobsExceeded() public function testMaxTimeExceeded() { - Queue::connection('database')->push(new ThirdJob()); + Queue::connection('database')->push(new ThirdJob); Queue::connection('database')->push(new FirstJob); Queue::connection('database')->push(new SecondJob); diff --git a/tests/Mail/MailLogTransportTest.php b/tests/Mail/MailLogTransportTest.php index 644ee64c5827..5848734d2eec 100644 --- a/tests/Mail/MailLogTransportTest.php +++ b/tests/Mail/MailLogTransportTest.php @@ -36,7 +36,7 @@ public function testGetLogTransportWithConfiguredChannel() public function testGetLogTransportWithPsrLogger() { $this->app['config']->set('mail.driver', 'log'); - $logger = $this->app->instance('log', new NullLogger()); + $logger = $this->app->instance('log', new NullLogger); $transportLogger = app('mailer')->getSwiftMailer()->getTransport()->logger(); diff --git a/tests/Mail/MailSesTransportTest.php b/tests/Mail/MailSesTransportTest.php index ff787fb7b53b..5d1d8f1fe885 100644 --- a/tests/Mail/MailSesTransportTest.php +++ b/tests/Mail/MailSesTransportTest.php @@ -16,7 +16,7 @@ class MailSesTransportTest extends TestCase /** @group Foo */ public function testGetTransport() { - $container = new Container(); + $container = new Container; $container->singleton('config', function () { return new Repository([ diff --git a/tests/Notifications/NotificationMailMessageTest.php b/tests/Notifications/NotificationMailMessageTest.php index e68e9a0a4620..ba31b96df353 100644 --- a/tests/Notifications/NotificationMailMessageTest.php +++ b/tests/Notifications/NotificationMailMessageTest.php @@ -141,11 +141,11 @@ public function testWhenCallback() $mailMessage->cc('cc@example.com'); }; - $message = new MailMessage(); + $message = new MailMessage; $message->when(true, $callback); $this->assertSame([['cc@example.com', null]], $message->cc); - $message = new MailMessage(); + $message = new MailMessage; $message->when(false, $callback); $this->assertSame([], $message->cc); } @@ -158,12 +158,12 @@ public function testWhenCallbackWithReturn() return $mailMessage->cc('cc@example.com'); }; - $message = new MailMessage(); + $message = new MailMessage; $message->when(true, $callback)->bcc('bcc@example.com'); $this->assertSame([['cc@example.com', null]], $message->cc); $this->assertSame([['bcc@example.com', null]], $message->bcc); - $message = new MailMessage(); + $message = new MailMessage; $message->when(false, $callback)->bcc('bcc@example.com'); $this->assertSame([], $message->cc); $this->assertSame([['bcc@example.com', null]], $message->bcc); @@ -183,11 +183,11 @@ public function testWhenCallbackWithDefault() $mailMessage->cc('zero@example.com'); }; - $message = new MailMessage(); + $message = new MailMessage; $message->when('truthy', $callback, $default); $this->assertSame([['truthy@example.com', null]], $message->cc); - $message = new MailMessage(); + $message = new MailMessage; $message->when(0, $callback, $default); $this->assertSame([['zero@example.com', null]], $message->cc); } @@ -200,11 +200,11 @@ public function testUnlessCallback() $mailMessage->cc('test@example.com'); }; - $message = new MailMessage(); + $message = new MailMessage; $message->unless(false, $callback); $this->assertSame([['test@example.com', null]], $message->cc); - $message = new MailMessage(); + $message = new MailMessage; $message->unless(true, $callback); $this->assertSame([], $message->cc); } @@ -217,12 +217,12 @@ public function testUnlessCallbackWithReturn() return $mailMessage->cc('cc@example.com'); }; - $message = new MailMessage(); + $message = new MailMessage; $message->unless(false, $callback)->bcc('bcc@example.com'); $this->assertSame([['cc@example.com', null]], $message->cc); $this->assertSame([['bcc@example.com', null]], $message->bcc); - $message = new MailMessage(); + $message = new MailMessage; $message->unless(true, $callback)->bcc('bcc@example.com'); $this->assertSame([], $message->cc); $this->assertSame([['bcc@example.com', null]], $message->bcc); @@ -242,11 +242,11 @@ public function testUnlessCallbackWithDefault() $mailMessage->cc('truthy@example.com'); }; - $message = new MailMessage(); + $message = new MailMessage; $message->unless(0, $callback, $default); $this->assertSame([['zero@example.com', null]], $message->cc); - $message = new MailMessage(); + $message = new MailMessage; $message->unless('truthy', $callback, $default); $this->assertSame([['truthy@example.com', null]], $message->cc); } diff --git a/tests/Notifications/NotificationSendQueuedNotificationTest.php b/tests/Notifications/NotificationSendQueuedNotificationTest.php index bdd1f5e197a6..3068d8130fe4 100644 --- a/tests/Notifications/NotificationSendQueuedNotificationTest.php +++ b/tests/Notifications/NotificationSendQueuedNotificationTest.php @@ -36,7 +36,7 @@ public function testSerializationOfNotifiableModel() $identifier = new ModelIdentifier(NotifiableUser::class, [null], [], null); $serializedIdentifier = serialize($identifier); - $job = new SendQueuedNotifications(new NotifiableUser(), 'notification'); + $job = new SendQueuedNotifications(new NotifiableUser, 'notification'); $serialized = serialize($job); $this->assertStringContainsString($serializedIdentifier, $serialized); @@ -44,7 +44,7 @@ public function testSerializationOfNotifiableModel() public function testSerializationOfNormalNotifiable() { - $notifiable = new AnonymousNotifiable(); + $notifiable = new AnonymousNotifiable; $serializedNotifiable = serialize($notifiable); $job = new SendQueuedNotifications($notifiable, 'notification'); diff --git a/tests/Notifications/NotificationSenderTest.php b/tests/Notifications/NotificationSenderTest.php index 6c5a6aaf849d..5c8674a45db8 100644 --- a/tests/Notifications/NotificationSenderTest.php +++ b/tests/Notifications/NotificationSenderTest.php @@ -33,7 +33,7 @@ public function testItCanSendQueuedNotificationsWithAStringVia() $sender = new NotificationSender($manager, $bus, $events); - $sender->send($notifiable, new DummyQueuedNotificationWithStringVia()); + $sender->send($notifiable, new DummyQueuedNotificationWithStringVia); } public function testItCanSendNotificationsWithAnEmptyStringVia() @@ -46,7 +46,7 @@ public function testItCanSendNotificationsWithAnEmptyStringVia() $sender = new NotificationSender($manager, $bus, $events); - $sender->sendNow($notifiable, new DummyNotificationWithEmptyStringVia()); + $sender->sendNow($notifiable, new DummyNotificationWithEmptyStringVia); } public function testItCannotSendNotificationsViaDatabaseForAnonymousNotifiables() @@ -59,7 +59,7 @@ public function testItCannotSendNotificationsViaDatabaseForAnonymousNotifiables( $sender = new NotificationSender($manager, $bus, $events); - $sender->sendNow($notifiable, new DummyNotificationWithDatabaseVia()); + $sender->sendNow($notifiable, new DummyNotificationWithDatabaseVia); } } diff --git a/tests/Redis/ConcurrentLimiterTest.php b/tests/Redis/ConcurrentLimiterTest.php index 35e5e64d2ea0..7285e9586732 100644 --- a/tests/Redis/ConcurrentLimiterTest.php +++ b/tests/Redis/ConcurrentLimiterTest.php @@ -149,7 +149,7 @@ public function testItReleasesIfErrorIsThrown() try { $lock->block(1, function () { - throw new Error(); + throw new Error; }); } catch (Error $e) { } diff --git a/tests/Redis/RedisManagerExtensionTest.php b/tests/Redis/RedisManagerExtensionTest.php index 650b118ec646..5cac41877cc2 100644 --- a/tests/Redis/RedisManagerExtensionTest.php +++ b/tests/Redis/RedisManagerExtensionTest.php @@ -19,7 +19,7 @@ protected function setUp(): void { parent::setUp(); - $this->redis = new RedisManager(new Application(), 'my_custom_driver', [ + $this->redis = new RedisManager(new Application, 'my_custom_driver', [ 'default' => [ 'host' => 'some-host', 'port' => 'some-port', @@ -39,7 +39,7 @@ protected function setUp(): void ]); $this->redis->extend('my_custom_driver', function () { - return new FakeRedisConnector(); + return new FakeRedisConnector; }); } @@ -72,7 +72,7 @@ public function test_parse_connection_configuration_for_cluster() 'url3', ], ]; - $redis = new RedisManager(new Application(), 'my_custom_driver', [ + $redis = new RedisManager(new Application, 'my_custom_driver', [ 'clusters' => [ $name => $config, ], diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index ecbf2222398e..3c09a0018def 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3580,7 +3580,7 @@ public function testConcatWithCollection($collection) */ public function testDump($collection) { - $log = new Collection(); + $log = new Collection; VarDumper::setHandler(function ($value) use ($log) { $log->add($value); diff --git a/tests/Support/SupportReflectsClosuresTest.php b/tests/Support/SupportReflectsClosuresTest.php index 3ab1200fedd0..1546b33c3696 100644 --- a/tests/Support/SupportReflectsClosuresTest.php +++ b/tests/Support/SupportReflectsClosuresTest.php @@ -12,7 +12,7 @@ public function testReflectsClosures() { $this->assertParameterTypes([ExampleParameter::class], function (ExampleParameter $one) { // assert the Closure isn't actually executed - throw new RuntimeException(); + throw new RuntimeException; }); $this->assertParameterTypes([], function () { diff --git a/tests/Testing/ParallelConsoleOutputTest.php b/tests/Testing/ParallelConsoleOutputTest.php index 1543be66aee3..7e9da0244df1 100644 --- a/tests/Testing/ParallelConsoleOutputTest.php +++ b/tests/Testing/ParallelConsoleOutputTest.php @@ -10,7 +10,7 @@ class ParallelConsoleOutputTest extends TestCase { public function testWrite() { - $original = new BufferedOutput(); + $original = new BufferedOutput; $output = new ParallelConsoleOutput($original); $output->write('Running phpunit in 12 processes with laravel/laravel.'); diff --git a/tests/Testing/TestResponseTest.php b/tests/Testing/TestResponseTest.php index f35f13121e1e..7257b0159e58 100644 --- a/tests/Testing/TestResponseTest.php +++ b/tests/Testing/TestResponseTest.php @@ -1241,7 +1241,7 @@ public function testItCanBeTapped() public function testAssertPlainCookie() { $response = TestResponse::fromBaseResponse( - (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value')) + (new Response)->withCookie(new Cookie('cookie-name', 'cookie-value')) ); $response->assertPlainCookie('cookie-name', 'cookie-value'); @@ -1260,7 +1260,7 @@ public function testAssertCookie() $encryptedValue = $encrypter->encrypt(CookieValuePrefix::create($cookieName, $encrypter->getKey()).$cookieValue, false); $response = TestResponse::fromBaseResponse( - (new Response())->withCookie(new Cookie($cookieName, $encryptedValue)) + (new Response)->withCookie(new Cookie($cookieName, $encryptedValue)) ); $response->assertCookie($cookieName, $cookieValue); @@ -1269,7 +1269,7 @@ public function testAssertCookie() public function testAssertCookieExpired() { $response = TestResponse::fromBaseResponse( - (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', time() - 5000)) + (new Response)->withCookie(new Cookie('cookie-name', 'cookie-value', time() - 5000)) ); $response->assertCookieExpired('cookie-name'); @@ -1278,7 +1278,7 @@ public function testAssertCookieExpired() public function testAssertSessionCookieExpiredDoesNotTriggerOnSessionCookies() { $response = TestResponse::fromBaseResponse( - (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) + (new Response)->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) ); $this->expectException(ExpectationFailedException::class); @@ -1289,7 +1289,7 @@ public function testAssertSessionCookieExpiredDoesNotTriggerOnSessionCookies() public function testAssertCookieNotExpired() { $response = TestResponse::fromBaseResponse( - (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', time() + 5000)) + (new Response)->withCookie(new Cookie('cookie-name', 'cookie-value', time() + 5000)) ); $response->assertCookieNotExpired('cookie-name'); @@ -1298,7 +1298,7 @@ public function testAssertCookieNotExpired() public function testAssertSessionCookieNotExpired() { $response = TestResponse::fromBaseResponse( - (new Response())->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) + (new Response)->withCookie(new Cookie('cookie-name', 'cookie-value', 0)) ); $response->assertCookieNotExpired('cookie-name'); @@ -1306,7 +1306,7 @@ public function testAssertSessionCookieNotExpired() public function testAssertCookieMissing() { - $response = TestResponse::fromBaseResponse(new Response()); + $response = TestResponse::fromBaseResponse(new Response); $response->assertCookieMissing('cookie-name'); } diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 79edde0850c6..c7b10c1128ba 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -2634,7 +2634,7 @@ public function testValidateEmailWithFilterUnicodeCheck() public function testValidateEmailWithCustomClassCheck() { $container = m::mock(Container::class); - $container->shouldReceive('make')->with(NoRFCWarningsValidation::class)->andReturn(new NoRFCWarningsValidation()); + $container->shouldReceive('make')->with(NoRFCWarningsValidation::class)->andReturn(new NoRFCWarningsValidation); $v = new Validator($this->getIlluminateArrayTranslator(), ['x' => 'foo@bar '], ['x' => 'email:'.NoRFCWarningsValidation::class]); $v->setContainer($container); diff --git a/tests/View/ComponentTest.php b/tests/View/ComponentTest.php index 8049c7aa5bc5..6185daa23ddc 100644 --- a/tests/View/ComponentTest.php +++ b/tests/View/ComponentTest.php @@ -52,7 +52,7 @@ public function testInlineViewsGetCreated() $this->viewFactory->shouldReceive('exists')->once()->andReturn(false); $this->viewFactory->shouldReceive('addNamespace')->once()->with('__components', '/tmp'); - $component = new TestInlineViewComponent(); + $component = new TestInlineViewComponent; $this->assertSame('__components::c6327913fef3fca4518bcd7df1d0ff630758e241', $component->resolveView()); } @@ -61,7 +61,7 @@ public function testRegularViewsGetReturned() $view = m::mock(View::class); $this->viewFactory->shouldReceive('make')->once()->with('alert', [], [])->andReturn($view); - $component = new TestRegularViewComponent(); + $component = new TestRegularViewComponent; $this->assertSame($view, $component->resolveView()); } @@ -71,14 +71,14 @@ public function testRegularViewNamesGetReturned() $this->viewFactory->shouldReceive('exists')->once()->andReturn(true); $this->viewFactory->shouldReceive('addNamespace')->never(); - $component = new TestRegularViewNameViewComponent(); + $component = new TestRegularViewNameViewComponent; $this->assertSame('alert', $component->resolveView()); } public function testHtmlablesGetReturned() { - $component = new TestHtmlableReturningViewComponent(); + $component = new TestHtmlableReturningViewComponent; $view = $component->resolveView(); diff --git a/tests/View/ViewComponentTest.php b/tests/View/ViewComponentTest.php index 8ce0b90349f1..c7ac6cda96ec 100644 --- a/tests/View/ViewComponentTest.php +++ b/tests/View/ViewComponentTest.php @@ -62,7 +62,7 @@ public function testPublicMethodsWithNoArgsAreConvertedToStringableCallablesInvo public function testItIgnoresExceptedMethodsAndProperties() { - $component = new TestExceptedViewComponent(); + $component = new TestExceptedViewComponent; $variables = $component->data(); // Ignored methods (with no args) are not invoked behind the scenes. @@ -75,7 +75,7 @@ public function testItIgnoresExceptedMethodsAndProperties() public function testMethodsOverridePropertyValues() { - $component = new TestHelloPropertyHelloMethodComponent(); + $component = new TestHelloPropertyHelloMethodComponent; $variables = $component->data(); $this->assertArrayHasKey('hello', $variables); $this->assertSame('world', $variables['hello']()); From 9522b1f18491c17f31c0aa57a3032364f5cf4216 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Fri, 19 Mar 2021 01:06:23 +0100 Subject: [PATCH 399/443] Use proper tests assertions (#36653) --- tests/Bus/BusBatchTest.php | 10 +++++----- tests/Database/DatabaseEloquentIntegrationTest.php | 4 ++-- tests/Http/HttpRequestTest.php | 14 +++++++------- .../DatabaseEloquentModelCustomCastingTest.php | 2 +- ...DatabaseSchemaBuilderAlterTableWithEnumTest.php | 3 ++- tests/Integration/Http/ResourceTest.php | 2 +- tests/Validation/ValidationAddFailureTest.php | 2 +- tests/Validation/ValidationValidatorTest.php | 2 +- 8 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index 8212298bc158..8711fdb14a02 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -113,7 +113,7 @@ public function test_jobs_can_be_added_to_the_batch() $this->assertEquals(3, $batch->totalJobs); $this->assertEquals(3, $batch->pendingJobs); - $this->assertTrue(is_string($job->batchId)); + $this->assertIsString($job->batchId); $this->assertInstanceOf(CarbonImmutable::class, $batch->createdAt); } @@ -301,7 +301,7 @@ public function test_batch_state_can_be_inspected() $batch->cancelledAt = now(); $this->assertTrue($batch->cancelled()); - $this->assertTrue(is_string(json_encode($batch))); + $this->assertIsString(json_encode($batch)); } public function test_chain_can_be_added_to_batch() @@ -334,9 +334,9 @@ public function test_chain_can_be_added_to_batch() $this->assertEquals(3, $batch->totalJobs); $this->assertEquals(3, $batch->pendingJobs); $this->assertSame('test-queue', $chainHeadJob->chainQueue); - $this->assertTrue(is_string($chainHeadJob->batchId)); - $this->assertTrue(is_string($secondJob->batchId)); - $this->assertTrue(is_string($thirdJob->batchId)); + $this->assertIsString($chainHeadJob->batchId); + $this->assertIsString($secondJob->batchId); + $this->assertIsString($thirdJob->batchId); $this->assertInstanceOf(CarbonImmutable::class, $batch->createdAt); } diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 2c5011b12551..4c8f77398733 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -811,12 +811,12 @@ public function testBelongsToManyRelationshipModelsAreProperlyHydratedWithSoleQu $user->friends()->create(['email' => 'abigailotwell@gmail.com']); $user->friends()->get()->each(function ($friend) { - $this->assertTrue($friend->pivot instanceof EloquentTestFriendPivot); + $this->assertInstanceOf(EloquentTestFriendPivot::class, $friend->pivot); }); $soleFriend = $user->friends()->where('email', 'abigailotwell@gmail.com')->sole(); - $this->assertTrue($soleFriend->pivot instanceof EloquentTestFriendPivot); + $this->assertInstanceOf(EloquentTestFriendPivot::class, $soleFriend->pivot); } public function testBelongsToManyRelationshipMissingModelExceptionWithSoleQueryWorks() diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 65272b796302..c019499419f6 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -1024,7 +1024,7 @@ public function testMagicMethods() // Parameter 'foo' is 'bar', then it ISSET and is NOT EMPTY. $this->assertSame('bar', $request->foo); $this->assertTrue(isset($request->foo)); - $this->assertFalse(empty($request->foo)); + $this->assertNotEmpty($request->foo); // Parameter 'empty' is '', then it ISSET and is EMPTY. $this->assertSame('', $request->empty); @@ -1034,7 +1034,7 @@ public function testMagicMethods() // Parameter 'undefined' is undefined/null, then it NOT ISSET and is EMPTY. $this->assertNull($request->undefined); $this->assertFalse(isset($request->undefined)); - $this->assertTrue(empty($request->undefined)); + $this->assertEmpty($request->undefined); // Simulates Route parameters. $request = Request::create('/example/bar', 'GET', ['xyz' => 'overwritten']); @@ -1049,18 +1049,18 @@ public function testMagicMethods() $this->assertSame('bar', $request->foo); $this->assertSame('bar', $request['foo']); $this->assertTrue(isset($request->foo)); - $this->assertFalse(empty($request->foo)); + $this->assertNotEmpty($request->foo); // Router parameter 'undefined' is undefined/null, then it NOT ISSET and is EMPTY. $this->assertNull($request->undefined); $this->assertFalse(isset($request->undefined)); - $this->assertTrue(empty($request->undefined)); + $this->assertEmpty($request->undefined); // Special case: router parameter 'xyz' is 'overwritten' by QueryString, then it ISSET and is NOT EMPTY. // Basically, QueryStrings have priority over router parameters. $this->assertSame('overwritten', $request->xyz); $this->assertTrue(isset($request->foo)); - $this->assertFalse(empty($request->foo)); + $this->assertNotEmpty($request->foo); // Simulates empty QueryString and Routes. $request = Request::create('/', 'GET'); @@ -1074,7 +1074,7 @@ public function testMagicMethods() // Parameter 'undefined' is undefined/null, then it NOT ISSET and is EMPTY. $this->assertNull($request->undefined); $this->assertFalse(isset($request->undefined)); - $this->assertTrue(empty($request->undefined)); + $this->assertEmpty($request->undefined); // Special case: simulates empty QueryString and Routes, without the Route Resolver. // It'll happen when you try to get a parameter outside a route. @@ -1083,7 +1083,7 @@ public function testMagicMethods() // Parameter 'undefined' is undefined/null, then it NOT ISSET and is EMPTY. $this->assertNull($request->undefined); $this->assertFalse(isset($request->undefined)); - $this->assertTrue(empty($request->undefined)); + $this->assertEmpty($request->undefined); } public function testHttpRequestFlashCallsSessionFlashInputWithInputData() diff --git a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php index c5fb6636b4d3..c2966b21dc28 100644 --- a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php +++ b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php @@ -106,7 +106,7 @@ public function testBasicCustomCasting() $model = new TestEloquentModelWithCustomCast; $model->birthday_at = now(); - $this->assertTrue(is_string($model->toArray()['birthday_at'])); + $this->assertIsString($model->toArray()['birthday_at']); } public function testGetOriginalWithCastValueObjects() diff --git a/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php b/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php index 9b52c60e4f5c..f2a8cb201323 100644 --- a/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php +++ b/tests/Integration/Database/DatabaseSchemaBuilderAlterTableWithEnumTest.php @@ -4,6 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use stdClass; class DatabaseSchemaBuilderAlterTableWithEnumTest extends DatabaseMySqlTestCase { @@ -30,7 +31,7 @@ public function testGetAllTablesAndColumnListing() $tables = Schema::getAllTables(); $this->assertCount(1, $tables); - $this->assertSame('stdClass', get_class($tables[0])); + $this->assertInstanceOf(stdClass::class, $tables[0]); $tableProperties = array_values((array) $tables[0]); $this->assertEquals(['users', 'BASE TABLE'], $tableProperties); diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 2553fd49c1e8..a1e5e2cafacf 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -781,7 +781,7 @@ public function testCollectionResourcesAreCountable() $collection = new PostCollectionResource($posts); $this->assertCount(2, $collection); - $this->assertSame(2, count($collection)); + $this->assertCount(2, $collection); } public function testKeysArePreservedIfTheResourceIsFlaggedToPreserveKeys() diff --git a/tests/Validation/ValidationAddFailureTest.php b/tests/Validation/ValidationAddFailureTest.php index ec94133a18ed..20fa5e43706f 100644 --- a/tests/Validation/ValidationAddFailureTest.php +++ b/tests/Validation/ValidationAddFailureTest.php @@ -25,7 +25,7 @@ public function testAddFailureExists() $validator = $this->makeValidator(); $method_name = 'addFailure'; $this->assertTrue(method_exists($validator, $method_name)); - $this->assertTrue(is_callable([$validator, $method_name])); + $this->assertIsCallable([$validator, $method_name]); } public function testAddFailureIsFunctional() diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index c7b10c1128ba..435113cca55b 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -5238,7 +5238,7 @@ public function message() ); $this->assertFalse($v->passes()); - $this->assertTrue(is_array($v->failed()['foo.foo.bar'])); + $this->assertIsArray($v->failed()['foo.foo.bar']); } public function testImplicitCustomValidationObjects() From a64526c55354205cf2623f85c9af48fa0664dc5a Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Fri, 19 Mar 2021 01:30:52 +0100 Subject: [PATCH 400/443] No need to call unset many times. (#36663) --- tests/Auth/AuthAccessGateTest.php | 10 ++++++---- tests/Bus/BusBatchTest.php | 5 +---- tests/Database/DatabaseEloquentFactoryTest.php | 10 +++------- tests/Events/EventsDispatcherTest.php | 3 +-- .../Bootstrap/LoadEnvironmentVariablesTest.php | 3 +-- .../Routing/CompiledRouteCollectionTest.php | 3 +-- tests/Pipeline/PipelineTest.php | 3 +-- 7 files changed, 14 insertions(+), 23 deletions(-) diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 913d1c4733ad..c9c0d7d08ef2 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -184,10 +184,12 @@ public function testBeforeAndAfterCallbacksCanAllowGuests() $this->assertTrue($_SERVER['__laravel.gateAfter']); $this->assertFalse($_SERVER['__laravel.gateAfter2']); - unset($_SERVER['__laravel.gateBefore']); - unset($_SERVER['__laravel.gateBefore2']); - unset($_SERVER['__laravel.gateAfter']); - unset($_SERVER['__laravel.gateAfter2']); + unset( + $_SERVER['__laravel.gateBefore'], + $_SERVER['__laravel.gateBefore2'], + $_SERVER['__laravel.gateAfter'], + $_SERVER['__laravel.gateAfter2'] + ); } public function testResourceGatesCanBeDefined() diff --git a/tests/Bus/BusBatchTest.php b/tests/Bus/BusBatchTest.php index 8711fdb14a02..d502c04da2b3 100644 --- a/tests/Bus/BusBatchTest.php +++ b/tests/Bus/BusBatchTest.php @@ -70,10 +70,7 @@ public function createSchema() */ protected function tearDown(): void { - unset($_SERVER['__finally.batch']); - unset($_SERVER['__then.batch']); - unset($_SERVER['__catch.batch']); - unset($_SERVER['__catch.exception']); + unset($_SERVER['__finally.batch'], $_SERVER['__then.batch'], $_SERVER['__catch.batch'], $_SERVER['__catch.exception']); $this->schema()->drop('job_batches'); diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index 7344dbb6c285..2d1def239514 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -200,8 +200,7 @@ public function test_after_creating_and_making_callbacks_are_called() $this->assertSame($user, $_SERVER['__test.user.making']); $this->assertSame($user, $_SERVER['__test.user.creating']); - unset($_SERVER['__test.user.making']); - unset($_SERVER['__test.user.creating']); + unset($_SERVER['__test.user.making'], $_SERVER['__test.user.creating']); } public function test_has_many_relationship() @@ -232,9 +231,7 @@ public function test_has_many_relationship() $this->assertInstanceOf(Eloquent::class, $_SERVER['__test.post.creating-user']); $this->assertInstanceOf(Eloquent::class, $_SERVER['__test.post.state-user']); - unset($_SERVER['__test.post.creating-post']); - unset($_SERVER['__test.post.creating-user']); - unset($_SERVER['__test.post.state-user']); + unset($_SERVER['__test.post.creating-post'], $_SERVER['__test.post.creating-user'], $_SERVER['__test.post.state-user']); } public function test_belongs_to_relationship() @@ -331,8 +328,7 @@ public function test_belongs_to_many_relationship() $this->assertInstanceOf(Eloquent::class, $_SERVER['__test.role.creating-role']); $this->assertInstanceOf(Eloquent::class, $_SERVER['__test.role.creating-user']); - unset($_SERVER['__test.role.creating-role']); - unset($_SERVER['__test.role.creating-user']); + unset($_SERVER['__test.role.creating-role'], $_SERVER['__test.role.creating-user']); } public function test_belongs_to_many_relationship_with_existing_model_instances() diff --git a/tests/Events/EventsDispatcherTest.php b/tests/Events/EventsDispatcherTest.php index f5ae19c95aa2..ea09fe576ca7 100755 --- a/tests/Events/EventsDispatcherTest.php +++ b/tests/Events/EventsDispatcherTest.php @@ -388,8 +388,7 @@ public function testBothClassesAndInterfacesWork() $this->assertSame('fooo', $_SERVER['__event.test1']); $this->assertSame('baar', $_SERVER['__event.test2']); - unset($_SERVER['__event.test1']); - unset($_SERVER['__event.test2']); + unset($_SERVER['__event.test1'], $_SERVER['__event.test2']); } public function testNestedEvent() diff --git a/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php b/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php index 9720273fa8bb..e2e85801bc29 100644 --- a/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php +++ b/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php @@ -11,8 +11,7 @@ class LoadEnvironmentVariablesTest extends TestCase { protected function tearDown(): void { - unset($_ENV['FOO']); - unset($_SERVER['FOO']); + unset($_ENV['FOO'], $_SERVER['FOO']); putenv('FOO'); m::close(); } diff --git a/tests/Integration/Routing/CompiledRouteCollectionTest.php b/tests/Integration/Routing/CompiledRouteCollectionTest.php index e474e8a461c4..09edb7d7feba 100644 --- a/tests/Integration/Routing/CompiledRouteCollectionTest.php +++ b/tests/Integration/Routing/CompiledRouteCollectionTest.php @@ -39,8 +39,7 @@ protected function tearDown(): void { parent::tearDown(); - unset($this->routeCollection); - unset($this->router); + unset($this->routeCollection, $this->router); } /** diff --git a/tests/Pipeline/PipelineTest.php b/tests/Pipeline/PipelineTest.php index da7038fb9ef5..f057e2c765f6 100644 --- a/tests/Pipeline/PipelineTest.php +++ b/tests/Pipeline/PipelineTest.php @@ -28,8 +28,7 @@ public function testPipelineBasicUsage() $this->assertSame('foo', $_SERVER['__test.pipe.one']); $this->assertSame('foo', $_SERVER['__test.pipe.two']); - unset($_SERVER['__test.pipe.one']); - unset($_SERVER['__test.pipe.two']); + unset($_SERVER['__test.pipe.one'], $_SERVER['__test.pipe.two']); } public function testPipelineUsageWithObjects() From 5df09b142c0c0effb643d206c38cd06ed4e33a30 Mon Sep 17 00:00:00 2001 From: Michel Bardelmeijer Date: Fri, 19 Mar 2021 15:00:44 +0100 Subject: [PATCH 401/443] Add WSREP communication link failure for lost connection detection (#36668) --- 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 a0bad6718017..191eefedc891 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -51,6 +51,7 @@ protected function causedByLostConnection(Throwable $e) 'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.', 'Temporary failure in name resolution', 'SSL: Broken pipe', + 'SQLSTATE[08S01]: Communication link failure', ]); } } From 0de4d79afd6f287028d7914d5dc4eeb26f89f2ff Mon Sep 17 00:00:00 2001 From: Philo Hermans Date: Fri, 19 Mar 2021 15:01:24 +0100 Subject: [PATCH 402/443] Add prohibited validation rule (#36667) --- .../Concerns/ValidatesAttributes.php | 13 ++++++++ src/Illuminate/Validation/Validator.php | 1 + tests/Validation/ValidationValidatorTest.php | 30 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 431b860bc20b..fb19d47f288d 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1434,6 +1434,19 @@ public function validateRequiredIf($attribute, $value, $parameters) return true; } + /** + * Validate that an attribute does not exist. + * + * @param string $attribute + * @param mixed $value + * @param mixed $parameters + * @return bool + */ + public function validateProhibited($attribute, $value) + { + return false; + } + /** * Validate that an attribute does not exist when another attribute has a given value. * diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 74f471aa32fa..2311b7357718 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -227,6 +227,7 @@ class Validator implements ValidatorContract 'RequiredWithAll', 'RequiredWithout', 'RequiredWithoutAll', + 'Prohibited', 'ProhibitedIf', 'ProhibitedUnless', 'Same', diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 435113cca55b..f850e55dbfbf 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1190,6 +1190,36 @@ public function testRequiredUnless() $this->assertSame('The last field is required unless first is in taylor, sven.', $v->messages()->first('last')); } + public function testProhibited() + { + $trans = $this->getIlluminateArrayTranslator(); + + $v = new Validator($trans, [], ['name' => 'prohibited']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['last' => 'bar'], ['name' => 'prohibited']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['name' => 'foo'], ['name' => 'prohibited']); + $this->assertTrue($v->fails()); + + $file = new File('', false); + $v = new Validator($trans, ['name' => $file], ['name' => 'prohibited']); + $this->assertTrue($v->fails()); + + $file = new File(__FILE__, false); + $v = new Validator($trans, ['name' => $file], ['name' => 'prohibited']); + $this->assertTrue($v->fails()); + + $file = new File(__FILE__, false); + $file2 = new File(__FILE__, false); + $v = new Validator($trans, ['files' => [$file, $file2]], ['files.0' => 'prohibited', 'files.1' => 'prohibited']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['files' => [$file, $file2]], ['files' => 'prohibited']); + $this->assertTrue($v->fails()); + } + public function testProhibitedIf() { $trans = $this->getIlluminateArrayTranslator(); From 1ac5370b6cfae469be49c14586c64fcda523aef9 Mon Sep 17 00:00:00 2001 From: Chris Gooding Date: Fri, 19 Mar 2021 14:02:08 +0000 Subject: [PATCH 403/443] Fixes the issue when using cache:clear with PhpRedis and a clustered Redis instance, by updating the PhpRedisConnection flushdb method to use the already open/configured clients. (#36665) --- .../Redis/Connections/PhpRedisConnection.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index 0c4015df9880..7e9af99ff29e 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -484,14 +484,8 @@ public function flushdb() return $this->command('flushdb'); } - foreach ($this->client->_masters() as [$host, $port]) { - $redis = tap(new Redis)->connect($host, $port); - - if (isset($this->config['password']) && ! empty($this->config['password'])) { - $redis->auth($this->config['password']); - } - - $redis->flushDb(); + foreach ($this->client->_masters() as $master) { + $this->client->flushDb($master); } } From 72ea328b456ea570f8823c69f511583aa6234170 Mon Sep 17 00:00:00 2001 From: gilbertorussi <33965697+gilbertorussi@users.noreply.github.com> Date: Fri, 19 Mar 2021 11:53:18 -0300 Subject: [PATCH 404/443] Add strict option to distinct attribute validation (#36669) --- .../Validation/Concerns/ValidatesAttributes.php | 2 +- tests/Validation/ValidationValidatorTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index fb19d47f288d..8f88aa2cd8df 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -556,7 +556,7 @@ public function validateDistinct($attribute, $value, $parameters) return empty(preg_grep('/^'.preg_quote($value, '/').'$/iu', $data)); } - return ! in_array($value, array_values($data)); + return ! in_array($value, array_values($data), in_array('strict', $parameters)); } /** diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index f850e55dbfbf..d1d3d424dd59 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -2395,6 +2395,15 @@ public function testValidateDistinct() $v->messages()->setFormat(':message'); $this->assertSame('There is a duplication!', $v->messages()->first('foo.0')); $this->assertSame('There is a duplication!', $v->messages()->first('foo.1')); + + $v = new Validator($trans, ['foo' => ['0100', '100']], ['foo.*' => 'distinct'], ['foo.*.distinct' => 'There is a duplication!']); + $this->assertFalse($v->passes()); + $v->messages()->setFormat(':message'); + $this->assertSame('There is a duplication!', $v->messages()->first('foo.0')); + $this->assertSame('There is a duplication!', $v->messages()->first('foo.1')); + + $v = new Validator($trans, ['foo' => ['0100', '100']], ['foo.*' => 'distinct:strict']); + $this->assertTrue($v->passes()); } public function testValidateDistinctForTopLevelArrays() From 0ee9a4b7ba5cafd5ae5896c84b432aa06d9d097d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 19 Mar 2021 16:31:40 -0400 Subject: [PATCH 405/443] Expect custom themes to be in mail subdirectory --- src/Illuminate/Mail/Markdown.php | 4 ++-- tests/Mail/MailMarkdownTest.php | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Mail/Markdown.php b/src/Illuminate/Mail/Markdown.php index a506f837f59f..725247e4d00d 100644 --- a/src/Illuminate/Mail/Markdown.php +++ b/src/Illuminate/Mail/Markdown.php @@ -63,8 +63,8 @@ public function render($view, array $data = [], $inliner = null) 'mail', $this->htmlComponentPaths() )->make($view, $data)->render(); - if ($this->view->exists($this->theme)) { - $theme = $this->theme; + if ($this->view->exists($custom = Str::start($this->theme, 'mail.'))) { + $theme = $custom; } else { $theme = Str::contains($this->theme, '::') ? $this->theme diff --git a/tests/Mail/MailMarkdownTest.php b/tests/Mail/MailMarkdownTest.php index 7878174ac43b..19341fde67a0 100644 --- a/tests/Mail/MailMarkdownTest.php +++ b/tests/Mail/MailMarkdownTest.php @@ -20,7 +20,7 @@ public function testRenderFunctionReturnsHtml() $markdown = new Markdown($viewFactory); $viewFactory->shouldReceive('flushFinderCache')->once(); $viewFactory->shouldReceive('replaceNamespace')->once()->with('mail', $markdown->htmlComponentPaths())->andReturnSelf(); - $viewFactory->shouldReceive('exists')->with('default')->andReturn(false); + $viewFactory->shouldReceive('exists')->with('mail.default')->andReturn(false); $viewFactory->shouldReceive('make')->with('view', [])->andReturnSelf(); $viewFactory->shouldReceive('make')->with('mail::themes.default', [])->andReturnSelf(); $viewFactory->shouldReceive('render')->twice()->andReturn('', 'body {}'); @@ -37,9 +37,26 @@ public function testRenderFunctionReturnsHtmlWithCustomTheme() $markdown->theme('yaz'); $viewFactory->shouldReceive('flushFinderCache')->once(); $viewFactory->shouldReceive('replaceNamespace')->once()->with('mail', $markdown->htmlComponentPaths())->andReturnSelf(); - $viewFactory->shouldReceive('exists')->with('yaz')->andReturn(true); + $viewFactory->shouldReceive('exists')->with('mail.yaz')->andReturn(true); $viewFactory->shouldReceive('make')->with('view', [])->andReturnSelf(); - $viewFactory->shouldReceive('make')->with('yaz', [])->andReturnSelf(); + $viewFactory->shouldReceive('make')->with('mail.yaz', [])->andReturnSelf(); + $viewFactory->shouldReceive('render')->twice()->andReturn('', 'body {}'); + + $result = $markdown->render('view', []); + + $this->assertNotFalse(strpos($result, '')); + } + + public function testRenderFunctionReturnsHtmlWithCustomThemeWithMailPrefix() + { + $viewFactory = m::mock(Factory::class); + $markdown = new Markdown($viewFactory); + $markdown->theme('mail.yaz'); + $viewFactory->shouldReceive('flushFinderCache')->once(); + $viewFactory->shouldReceive('replaceNamespace')->once()->with('mail', $markdown->htmlComponentPaths())->andReturnSelf(); + $viewFactory->shouldReceive('exists')->with('mail.yaz')->andReturn(true); + $viewFactory->shouldReceive('make')->with('view', [])->andReturnSelf(); + $viewFactory->shouldReceive('make')->with('mail.yaz', [])->andReturnSelf(); $viewFactory->shouldReceive('render')->twice()->andReturn('', 'body {}'); $result = $markdown->render('view', []); From fc331f3c779252e5c0b201df7baf87aa0962cccb Mon Sep 17 00:00:00 2001 From: thecaliskan <13554944+thecaliskan@users.noreply.github.com> Date: Sun, 21 Mar 2021 14:21:55 +0300 Subject: [PATCH 406/443] Access Translator Json Paths --- src/Illuminate/Translation/FileLoader.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Illuminate/Translation/FileLoader.php b/src/Illuminate/Translation/FileLoader.php index 17f6e59f0b0e..8875c8057565 100755 --- a/src/Illuminate/Translation/FileLoader.php +++ b/src/Illuminate/Translation/FileLoader.php @@ -184,4 +184,14 @@ public function namespaces() { return $this->hints; } + + /** + * Get an array of all the registered paths to JSON translation files. + * + * @return array + */ + public function getJsonPaths() + { + return $this->jsonPaths; + } } From 76e86bd19e5c7c87adbb768ac08c00f6c7a8dfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20=C3=87al=C4=B1=C5=9Fkan?= Date: Sun, 21 Mar 2021 14:26:48 +0300 Subject: [PATCH 407/443] style ci fix --- src/Illuminate/Translation/FileLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Translation/FileLoader.php b/src/Illuminate/Translation/FileLoader.php index 8875c8057565..b2285a6eceb6 100755 --- a/src/Illuminate/Translation/FileLoader.php +++ b/src/Illuminate/Translation/FileLoader.php @@ -184,7 +184,7 @@ public function namespaces() { return $this->hints; } - + /** * Get an array of all the registered paths to JSON translation files. * From 8b01f7980d99ae1528eaf7ad21c657868ad942c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Dalmolin?= Date: Sun, 21 Mar 2021 09:14:49 -0300 Subject: [PATCH 408/443] Added Event::assertAttached to EventFake class --- .../Support/Testing/Fakes/EventFake.php | 33 +++++++++++++++++++ tests/Integration/Events/EventFakeTest.php | 30 +++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 88fcb84cea48..d21227ef6fdc 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -7,6 +7,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; +use ReflectionFunction; class EventFake implements Dispatcher { @@ -284,4 +285,36 @@ public function until($event, $payload = []) { return $this->dispatch($event, $payload, true); } + + /** + * Assert if an event has a listener attached to it. + * + * @param string $expectedEvent + * @param string $expectedListener + * @return void + */ + public function assertAttached($expectedEvent, $expectedListener) + { + foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) { + $reflection = new ReflectionFunction($listenerClosure); + $actualListener = $reflection->getStaticVariables()['listener']; + + if ($actualListener === $expectedListener) { + PHPUnit::assertTrue(true); + + return; + } + + if ($actualListener instanceof Closure && $expectedListener === Closure::class) { + PHPUnit::assertTrue(true); + + return; + } + } + + PHPUnit::assertTrue( + false, + sprintf('Event %s does not have the %s listener attached to it', $expectedEvent, print_r($expectedListener, true)) + ); + } } diff --git a/tests/Integration/Events/EventFakeTest.php b/tests/Integration/Events/EventFakeTest.php index b69b86e8c88e..411764685efb 100644 --- a/tests/Integration/Events/EventFakeTest.php +++ b/tests/Integration/Events/EventFakeTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Events; +use Closure; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Event; @@ -126,6 +127,20 @@ public function testNonFakedHaltedEventGetsProperlyDispatchedAndReturnsResponse( Event::assertNotDispatched(NonImportantEvent::class); } + + public function testAssertAttached() + { + Event::fake(); + Event::listen('event', 'listener'); + Event::subscribe(PostEventSubscriber::class); + Event::listen(function (NonImportantEvent $event) { + // do something + }); + + Event::assertAttached('event', 'listener'); + Event::assertAttached('post-created', [PostEventSubscriber::class, 'handlePostCreated']); + Event::assertAttached(NonImportantEvent::class, Closure::class); + } } class Post extends Model @@ -138,6 +153,21 @@ class NonImportantEvent // } +class PostEventSubscriber +{ + public function handlePostCreated($event) + { + } + + public function subscribe($events) + { + $events->listen( + 'post-created', + [PostEventSubscriber::class, 'handlePostCreated'] + ); + } +} + class PostObserver { public function saving(Post $post) From 2a66f57b43477798242a9d91a2cbebdd50489714 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 21 Mar 2021 08:37:37 -0500 Subject: [PATCH 409/443] add to tests - formatting --- .../Support/Testing/Fakes/EventFake.php | 64 +++++++++---------- tests/Integration/Events/EventFakeTest.php | 12 ++-- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index d21227ef6fdc..ed5014f15519 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -48,6 +48,38 @@ public function __construct(Dispatcher $dispatcher, $eventsToFake = []) $this->eventsToFake = Arr::wrap($eventsToFake); } + /** + * Assert if an event has a listener attached to it. + * + * @param string $expectedEvent + * @param string $expectedListener + * @return void + */ + public function assertListening($expectedEvent, $expectedListener) + { + foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) { + $actualListener = (new ReflectionFunction($listenerClosure)) + ->getStaticVariables()['listener']; + + if ($actualListener === $expectedListener || + ($actualListener instanceof Closure && + $expectedListener === Closure::class)) { + PHPUnit::assertTrue(true); + + return; + } + } + + PHPUnit::assertTrue( + false, + sprintf( + 'Event [%s] does not have the [%s] listener attached to it', + $expectedEvent, + print_r($expectedListener, true) + ) + ); + } + /** * Assert if an event was dispatched based on a truth-test callback. * @@ -285,36 +317,4 @@ public function until($event, $payload = []) { return $this->dispatch($event, $payload, true); } - - /** - * Assert if an event has a listener attached to it. - * - * @param string $expectedEvent - * @param string $expectedListener - * @return void - */ - public function assertAttached($expectedEvent, $expectedListener) - { - foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) { - $reflection = new ReflectionFunction($listenerClosure); - $actualListener = $reflection->getStaticVariables()['listener']; - - if ($actualListener === $expectedListener) { - PHPUnit::assertTrue(true); - - return; - } - - if ($actualListener instanceof Closure && $expectedListener === Closure::class) { - PHPUnit::assertTrue(true); - - return; - } - } - - PHPUnit::assertTrue( - false, - sprintf('Event %s does not have the %s listener attached to it', $expectedEvent, print_r($expectedListener, true)) - ); - } } diff --git a/tests/Integration/Events/EventFakeTest.php b/tests/Integration/Events/EventFakeTest.php index 411764685efb..bf5717b1e694 100644 --- a/tests/Integration/Events/EventFakeTest.php +++ b/tests/Integration/Events/EventFakeTest.php @@ -128,18 +128,22 @@ public function testNonFakedHaltedEventGetsProperlyDispatchedAndReturnsResponse( Event::assertNotDispatched(NonImportantEvent::class); } - public function testAssertAttached() + public function testAssertListening() { Event::fake(); Event::listen('event', 'listener'); + Event::listen('event', PostEventSubscriber::class); + Event::listen('event', [PostEventSubscriber::class, 'foo']); Event::subscribe(PostEventSubscriber::class); Event::listen(function (NonImportantEvent $event) { // do something }); - Event::assertAttached('event', 'listener'); - Event::assertAttached('post-created', [PostEventSubscriber::class, 'handlePostCreated']); - Event::assertAttached(NonImportantEvent::class, Closure::class); + Event::assertListening('event', 'listener'); + Event::assertListening('event', PostEventSubscriber::class); + Event::assertListening('event', [PostEventSubscriber::class, 'foo']); + Event::assertListening('post-created', [PostEventSubscriber::class, 'handlePostCreated']); + Event::assertListening(NonImportantEvent::class, Closure::class); } } From 40e8d25a61d9401fc5fed41e4f4582c0d0a12173 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 21 Mar 2021 08:42:27 -0500 Subject: [PATCH 410/443] formatting --- src/Illuminate/Translation/FileLoader.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Translation/FileLoader.php b/src/Illuminate/Translation/FileLoader.php index b2285a6eceb6..f359a8e5584d 100755 --- a/src/Illuminate/Translation/FileLoader.php +++ b/src/Illuminate/Translation/FileLoader.php @@ -165,24 +165,24 @@ public function addNamespace($namespace, $hint) } /** - * Add a new JSON path to the loader. + * Get an array of all the registered namespaces. * - * @param string $path - * @return void + * @return array */ - public function addJsonPath($path) + public function namespaces() { - $this->jsonPaths[] = $path; + return $this->hints; } /** - * Get an array of all the registered namespaces. + * Add a new JSON path to the loader. * - * @return array + * @param string $path + * @return void */ - public function namespaces() + public function addJsonPath($path) { - return $this->hints; + $this->jsonPaths[] = $path; } /** @@ -190,7 +190,7 @@ public function namespaces() * * @return array */ - public function getJsonPaths() + public function jsonPaths() { return $this->jsonPaths; } From 03a297f34db413fd6cdcbf59fb8b9b2752297ca2 Mon Sep 17 00:00:00 2001 From: Jacob Martin Date: Sun, 21 Mar 2021 06:46:59 -0700 Subject: [PATCH 411/443] [8.x] Throw exception when unable to create LockableFile (#36674) * fix: exception when unable to create file * lint * lint * Update LockableFile.php Co-authored-by: Taylor Otwell --- src/Illuminate/Filesystem/LockableFile.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Illuminate/Filesystem/LockableFile.php b/src/Illuminate/Filesystem/LockableFile.php index edb801f4847b..a095d4e9a9b5 100644 --- a/src/Illuminate/Filesystem/LockableFile.php +++ b/src/Illuminate/Filesystem/LockableFile.php @@ -2,6 +2,7 @@ namespace Illuminate\Filesystem; +use Exception; use Illuminate\Contracts\Filesystem\LockTimeoutException; class LockableFile @@ -65,6 +66,10 @@ protected function ensureDirectoryExists($path) protected function createResource($path, $mode) { $this->handle = @fopen($path, $mode); + + if (! $this->handle) { + throw new Exception('Unable to create lockable file: '.$path.'. Please ensure you have permission to create files in this location.'); + } } /** From 461c4488cad31479006711d40dcf848b3f956e1d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 21 Mar 2021 08:55:04 -0500 Subject: [PATCH 412/443] formatting --- src/Illuminate/Mail/Markdown.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Mail/Markdown.php b/src/Illuminate/Mail/Markdown.php index 725247e4d00d..9a1706d383b1 100644 --- a/src/Illuminate/Mail/Markdown.php +++ b/src/Illuminate/Mail/Markdown.php @@ -63,8 +63,8 @@ public function render($view, array $data = [], $inliner = null) 'mail', $this->htmlComponentPaths() )->make($view, $data)->render(); - if ($this->view->exists($custom = Str::start($this->theme, 'mail.'))) { - $theme = $custom; + if ($this->view->exists($customTheme = Str::start($this->theme, 'mail.'))) { + $theme = $customTheme; } else { $theme = Str::contains($this->theme, '::') ? $this->theme From f201b813322622a6c7952800e716e63e1662bf99 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 22 Mar 2021 16:16:58 +0100 Subject: [PATCH 413/443] [8.x] PHP 8.1 builds (#36700) * Ignore platform reqs * Prefer stable * Re-enable tests * Skip PHP 8.1 build failures * Update tests.yml --- .github/workflows/tests.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cd988a7d4a30..dc66377c3c6d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,6 +33,11 @@ jobs: matrix: php: ['7.3', '7.4', '8.0'] stability: [prefer-lowest, prefer-stable] + include: + - php: '8.1' + flags: "--ignore-platform-req=php" + stability: prefer-stable + name: PHP ${{ matrix.php }} - ${{ matrix.stability }} @@ -61,9 +66,10 @@ jobs: 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 ${{ matrix.flags }} - name: Execute tests + continue-on-error: ${{ matrix.php > 8 }} run: vendor/bin/phpunit --verbose env: DB_PORT: ${{ job.services.mysql.ports[3306] }} @@ -77,6 +83,10 @@ jobs: matrix: php: ['7.3', '7.4', '8.0'] stability: [prefer-lowest, prefer-stable] + include: + - php: '8.1' + flags: "--ignore-platform-req=php" + stability: prefer-stable name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - Windows @@ -110,7 +120,8 @@ jobs: 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 ${{ matrix.flags }} - name: Execute tests + continue-on-error: ${{ matrix.php > 8 }} run: vendor/bin/phpunit --verbose From baa48bf4e0b9a79fac8572ca16b5543444129796 Mon Sep 17 00:00:00 2001 From: matt-hullo <62615737+matt-hullo@users.noreply.github.com> Date: Mon, 22 Mar 2021 15:18:10 +0000 Subject: [PATCH 414/443] [8.x] Fix for #34592 artisan schema:dump error (#36698) * It mysqldump errors because "set-gtid-purged" isn't a valid option retry without it. * Update MySqlSchemaState.php Co-authored-by: Matt Davis Co-authored-by: Taylor Otwell --- src/Illuminate/Database/Schema/MySqlSchemaState.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Illuminate/Database/Schema/MySqlSchemaState.php b/src/Illuminate/Database/Schema/MySqlSchemaState.php index 68b6814a83cb..56a4ea455b5d 100644 --- a/src/Illuminate/Database/Schema/MySqlSchemaState.php +++ b/src/Illuminate/Database/Schema/MySqlSchemaState.php @@ -149,6 +149,12 @@ protected function executeDumpProcess(Process $process, $output, array $variable ), $output, $variables); } + if (Str::contains($e->getMessage(), ['set-gtid-purged'])) { + return $this->executeDumpProcess(Process::fromShellCommandLine( + str_replace(' --set-gtid-purged=OFF', '', $process->getCommandLine()) + ), $output, $variables); + } + throw $e; } From bb6e6f21e278d35ad478e128af94e0bc4d8d5f48 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Tue, 23 Mar 2021 11:06:13 -0400 Subject: [PATCH 415/443] Add Builder@lazy() and Builder@lazyById() methods (#36699) --- .../Database/Concerns/BuildsQueries.php | 72 +++++++++++ .../Database/DatabaseEloquentBuilderTest.php | 112 ++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 34af0405e723..b35cf60c40f5 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -8,6 +8,8 @@ use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; use Illuminate\Support\Collection; +use Illuminate\Support\LazyCollection; +use InvalidArgumentException; trait BuildsQueries { @@ -159,6 +161,76 @@ public function eachById(callable $callback, $count = 1000, $column = null, $ali }, $column, $alias); } + /** + * Query lazily, by chunks of the given size. + * + * @param int $chunkSize + * @return \Illuminate\Support\LazyCollection + */ + public function lazy($chunkSize = 1000) + { + if ($chunkSize < 1) { + throw new InvalidArgumentException('The chunk size should be at least 1'); + } + + $this->enforceOrderBy(); + + return LazyCollection::make(function () use ($chunkSize) { + $page = 1; + + while (true) { + $results = $this->forPage($page++, $chunkSize)->get(); + + foreach ($results as $result) { + yield $result; + } + + if ($results->count() < $chunkSize) { + return; + } + } + }); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs. + * + * @param int $count + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyById($chunkSize = 1000, $column = null, $alias = null) + { + if ($chunkSize < 1) { + throw new InvalidArgumentException('The chunk size should be at least 1'); + } + + $column = $column ?? $this->defaultKeyName(); + + $alias = $alias ?? $column; + + return LazyCollection::make(function () use ($chunkSize, $column, $alias) { + $lastId = null; + + while (true) { + $clone = clone $this; + + $results = $clone->forPageAfterId($chunkSize, $lastId, $column)->get(); + + foreach ($results as $result) { + yield $result; + } + + if ($results->count() < $chunkSize) { + return; + } + + $lastId = $results->last()->{$alias}; + } + }); + } + /** * Execute the query and get the first result. * diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index b4eec40cfc8a..0809f8e0fe98 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -382,6 +382,118 @@ public function testChunkPaginatesUsingIdWithCountZero() }, 'someIdField'); } + public function testLazyWithLastChunkComplete() + { + $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; + + $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('get')->times(3)->andReturn( + new Collection(['foo1', 'foo2']), + new Collection(['foo3', 'foo4']), + new Collection([]) + ); + + $this->assertEquals( + ['foo1', 'foo2', 'foo3', 'foo4'], + $builder->lazy(2)->all() + ); + } + + public function testLazyWithLastChunkPartial() + { + $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; + + $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); + $builder->shouldReceive('forPage')->once()->with(2, 2)->andReturnSelf(); + $builder->shouldReceive('get')->times(2)->andReturn( + new Collection(['foo1', 'foo2']), + new Collection(['foo3']) + ); + + $this->assertEquals( + ['foo1', 'foo2', 'foo3'], + $builder->lazy(2)->all() + ); + } + + public function testLazyIsLazy() + { + $builder = m::mock(Builder::class.'[forPage,get]', [$this->getMockQueryBuilder()]); + $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; + + $builder->shouldReceive('forPage')->once()->with(1, 2)->andReturnSelf(); + $builder->shouldReceive('get')->once()->andReturn(new Collection(['foo1', 'foo2'])); + + $this->assertEquals(['foo1', 'foo2'], $builder->lazy(2)->take(2)->all()); + } + + public function testLazyByIdWithLastChunkComplete() + { + $builder = m::mock(Builder::class.'[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('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(); + $builder->shouldReceive('get')->times(3)->andReturn($chunk1, $chunk2, $chunk3); + + $this->assertEquals( + [ + (object) ['someIdField' => 1], + (object) ['someIdField' => 2], + (object) ['someIdField' => 10], + (object) ['someIdField' => 11], + ], + $builder->lazyById(2, 'someIdField')->all() + ); + } + + public function testLazyByIdWithLastChunkPartial() + { + $builder = m::mock(Builder::class.'[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('forPageAfterId')->once()->with(2, 0, 'someIdField')->andReturnSelf(); + $builder->shouldReceive('forPageAfterId')->once()->with(2, 2, 'someIdField')->andReturnSelf(); + $builder->shouldReceive('get')->times(2)->andReturn($chunk1, $chunk2); + + $this->assertEquals( + [ + (object) ['someIdField' => 1], + (object) ['someIdField' => 2], + (object) ['someIdField' => 10], + ], + $builder->lazyById(2, 'someIdField')->all() + ); + } + + public function testLazyByIdIsLazy() + { + $builder = m::mock(Builder::class.'[forPageAfterId,get]', [$this->getMockQueryBuilder()]); + $builder->getQuery()->orders[] = ['column' => 'foobar', 'direction' => 'asc']; + + $chunk1 = new Collection([(object) ['someIdField' => 1], (object) ['someIdField' => 2]]); + $builder->shouldReceive('forPageAfterId')->once()->with(2, 0, 'someIdField')->andReturnSelf(); + $builder->shouldReceive('get')->once()->andReturn($chunk1); + + $this->assertEquals( + [ + (object) ['someIdField' => 1], + (object) ['someIdField' => 2], + ], + $builder->lazyById(2, 'someIdField')->take(2)->all() + ); + } + public function testPluckReturnsTheMutatedAttributesOfAModel() { $builder = $this->getBuilder(); From 664a9432bcceb67871c5c9252f920d28f21dfc23 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 23 Mar 2021 08:12:22 -0700 Subject: [PATCH 416/443] patch --- 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 5fa3b2bed350..4e4d6c1840d3 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.19'; + const VERSION = '6.20.20'; /** * The base path for the Laravel installation. From b3ef465c19d4a4853228d794bc961c32e87c5209 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 23 Mar 2021 16:28:30 +0100 Subject: [PATCH 417/443] Deprecate MocksApplicationServices trait (#36716) --- .../Foundation/Testing/Concerns/MocksApplicationServices.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php index 7fc360e76f75..66622950c766 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php +++ b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php @@ -8,6 +8,9 @@ use Illuminate\Support\Facades\Event; use Mockery; +/** + * @deprecated Will be removed in a future Laravel version. + */ trait MocksApplicationServices { /** From 8f48242a88e6a3baa10f9c9dc8d7ffb3fb872f98 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 23 Mar 2021 19:39:11 +0200 Subject: [PATCH 418/443] [8.x] update changelog --- CHANGELOG-8.x.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 399b85419411..c16cafb181d3 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,15 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.33.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.33.1...8.x) + + +## [v8.33.1 (2021-03-16)](https://github.com/laravel/framework/compare/v8.33.0...v8.33.1) + +### Added +- Added `Illuminate\Database\Connection::forgetRecordModificationState()` ([#36617](https://github.com/laravel/framework/pull/36617)) + +### Reverted +- Reverted "Container - detect circular dependencies" ([332844e](https://github.com/laravel/framework/commit/332844e5bde34f8db91aeca4d21cd4e0925d691e)) ## [v8.33.0 (2021-03-16)](https://github.com/laravel/framework/compare/v8.32.1...v8.33.0) From ab703aa6d5358c162df212d7924f17eaf26aaa73 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 23 Mar 2021 19:44:14 +0200 Subject: [PATCH 419/443] [6.x] update changelog --- CHANGELOG-6.x.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-6.x.md b/CHANGELOG-6.x.md index 226fdd550d8a..cc073b4d93fb 100644 --- a/CHANGELOG-6.x.md +++ b/CHANGELOG-6.x.md @@ -1,6 +1,15 @@ # Release Notes for 6.x -## [Unreleased](https://github.com/laravel/framework/compare/v6.20.19...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.20...6.x) + + +## [v6.20.20 (2021-03-23)](https://github.com/laravel/framework/compare/v6.20.19...v6.20.20) + +### Added +- Added WSREP communication link failure for lost connection detection ([#36668](https://github.com/laravel/framework/pull/36668)) + +### Fixed +- Fixes the issue using cache:clear with PhpRedis and a clustered Redis instance. ([#36665](https://github.com/laravel/framework/pull/36665)) ## [v6.20.19 (2021-03-16)](https://github.com/laravel/framework/compare/v6.20.18...v6.20.19) From 08815a1ba71c6fd850950305736fa4f5f5862aa0 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 23 Mar 2021 20:16:25 +0200 Subject: [PATCH 420/443] [8.x] update changelog --- CHANGELOG-8.x.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index c16cafb181d3..20db6d32bb76 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,38 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.33.1...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.34.0...8.x) + + +## [v8.34.0 (2021-03-23)](https://github.com/laravel/framework/compare/v8.33.1...v8.34.0) + +### Inspiring +- Added more inspiring quotes ([92b7bde](https://github.com/laravel/framework/commit/92b7bdeb4b8c40848fa276cfe1897c656302942f)) + +### Added +- Added WSREP communication link failure for lost connection detection ([#36668](https://github.com/laravel/framework/pull/36668)) +- Added "exclude-path" option to `route:list` command ([#36619](https://github.com/laravel/framework/pull/36619), [76e11ee](https://github.com/laravel/framework/commit/76e11ee97fc8068be1d55986b4524d4c329af387)) +- Added `Illuminate\Support\Str::remove()` and `Illuminate\Support\Stringable::remove()` methods ([#36639](https://github.com/laravel/framework/pull/36639), [7b0259f](https://github.com/laravel/framework/commit/7b0259faa46409513b75a8a0b512b3aacfcad944), [20e2470](https://github.com/laravel/framework/commit/20e24701e71f71a44b477b4311d0cb69f97906f1)) +- Added `Illuminate\Database\Eloquent\Relations\MorphPivot::getMorphType()` ([#36640](https://github.com/laravel/framework/pull/36640), [7e08215](https://github.com/laravel/framework/commit/7e08215f0d370c3c33beb7bba7e2c1ee2ac7aab5)) +- Added assertion to verify type of key in JSON ([#36638](https://github.com/laravel/framework/pull/36638)) +- Added prohibited validation rule ([#36667](https://github.com/laravel/framework/pull/36667)) +- Added strict comparison to distinct validation rule ([#36669](https://github.com/laravel/framework/pull/36669)) +- Added `Illuminate\Translation\FileLoader::getJsonPaths()` ([#36689](https://github.com/laravel/framework/pull/36689)) +- Added `Illuminate\Support\Testing\Fakes\EventFake::assertAttached()` ([#36690](https://github.com/laravel/framework/pull/36690)) +- Added `lazy()` and `lazyById()` methods to `Illuminate\Database\Concerns\BuildsQueries` ([#36699](https://github.com/laravel/framework/pull/36699)) + +### Fixed +- Fixes the issue using cache:clear with PhpRedis and a clustered Redis instance. ([#36665](https://github.com/laravel/framework/pull/36665)) +- Fix replacing required :input with null on PHP 8.1 in `Illuminate\Validation\Concerns\FormatsMessages::getDisplayableValue()` ([#36622](https://github.com/laravel/framework/pull/36622)) +- Fixed artisan schema:dump error ([#36698](https://github.com/laravel/framework/pull/36698)) + +### Changed +- Adjust Fluent Assertions ([#36620](https://github.com/laravel/framework/pull/36620)) +- Added timestamp reference to schedule:work artisan command output ([#36621](https://github.com/laravel/framework/pull/36621)) +- Expect custom markdown mailable themes to be in mail subdirectory ([#36673](https://github.com/laravel/framework/pull/36673)) +- Throw exception when unable to create LockableFile ([#36674](https://github.com/laravel/framework/pull/36674)) + +### Refactoring +- Always prefer typesafe string comparisons ([#36657](https://github.com/laravel/framework/pull/36657)) ## [v8.33.1 (2021-03-16)](https://github.com/laravel/framework/compare/v8.33.0...v8.33.1) From 24fafcad66127c217f6b1b6790265d41a6a0f636 Mon Sep 17 00:00:00 2001 From: JUNO_OKYO <5250117+J2TEAM@users.noreply.github.com> Date: Wed, 24 Mar 2021 23:08:18 +0700 Subject: [PATCH 421/443] Update changelog (#36724) --- CHANGELOG-8.x.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 20db6d32bb76..dd2fae605a22 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -10,7 +10,7 @@ ### Added - Added WSREP communication link failure for lost connection detection ([#36668](https://github.com/laravel/framework/pull/36668)) -- Added "exclude-path" option to `route:list` command ([#36619](https://github.com/laravel/framework/pull/36619), [76e11ee](https://github.com/laravel/framework/commit/76e11ee97fc8068be1d55986b4524d4c329af387)) +- Added "except-path" option to `route:list` command ([#36619](https://github.com/laravel/framework/pull/36619), [76e11ee](https://github.com/laravel/framework/commit/76e11ee97fc8068be1d55986b4524d4c329af387)) - Added `Illuminate\Support\Str::remove()` and `Illuminate\Support\Stringable::remove()` methods ([#36639](https://github.com/laravel/framework/pull/36639), [7b0259f](https://github.com/laravel/framework/commit/7b0259faa46409513b75a8a0b512b3aacfcad944), [20e2470](https://github.com/laravel/framework/commit/20e24701e71f71a44b477b4311d0cb69f97906f1)) - Added `Illuminate\Database\Eloquent\Relations\MorphPivot::getMorphType()` ([#36640](https://github.com/laravel/framework/pull/36640), [7e08215](https://github.com/laravel/framework/commit/7e08215f0d370c3c33beb7bba7e2c1ee2ac7aab5)) - Added assertion to verify type of key in JSON ([#36638](https://github.com/laravel/framework/pull/36638)) From c04fa172ab4488f297549aa8618b066835b78d26 Mon Sep 17 00:00:00 2001 From: Michael Grinspan Date: Wed, 24 Mar 2021 12:12:11 -0400 Subject: [PATCH 422/443] Remove useless loop (#36722) --- src/Illuminate/Support/Str.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 5207bbdb0dff..e8e9975b47d8 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -568,11 +568,9 @@ public static function replaceLast($search, $replace, $subject) */ public static function remove($search, $subject, $caseSensitive = true) { - foreach (Arr::wrap($search) as $s) { - $subject = $caseSensitive - ? str_replace($search, '', $subject) - : str_ireplace($search, '', $subject); - } + $subject = $caseSensitive + ? str_replace($search, '', $subject) + : str_ireplace($search, '', $subject); return $subject; } From de5f6a7ac9be7674820d24c1d5e9ababcaf00c3e Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Wed, 24 Mar 2021 17:15:57 +0100 Subject: [PATCH 423/443] [8.x] Make `ResponseSequence` macroable (#36719) * make ResponseSequence macroable * cs --- src/Illuminate/Http/Client/ResponseSequence.php | 3 +++ tests/Http/HttpClientTest.php | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/Illuminate/Http/Client/ResponseSequence.php b/src/Illuminate/Http/Client/ResponseSequence.php index 66d0ec6bbce4..0fb6fb021dd6 100644 --- a/src/Illuminate/Http/Client/ResponseSequence.php +++ b/src/Illuminate/Http/Client/ResponseSequence.php @@ -2,10 +2,13 @@ namespace Illuminate\Http\Client; +use Illuminate\Support\Traits\Macroable; use OutOfBoundsException; class ResponseSequence { + use Macroable; + /** * The responses in the sequence. * diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index d5be7aefaf25..63e07bfbf7e1 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -7,6 +7,7 @@ use Illuminate\Http\Client\Request; use Illuminate\Http\Client\RequestException; use Illuminate\Http\Client\Response; +use Illuminate\Http\Client\ResponseSequence; use Illuminate\Support\Collection; use Illuminate\Support\Str; use OutOfBoundsException; @@ -802,4 +803,13 @@ public function testCanDump() VarDumper::setHandler(null); } + + public function testResponseSequenceIsMacroable() + { + ResponseSequence::macro('customMethod', function () { + return 'yes!'; + }); + + $this->assertSame('yes!', $this->factory->fakeSequence()->customMethod()); + } } From f75e51084689330ba59ae09d1dd50ab507b10555 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 25 Mar 2021 15:54:04 +0100 Subject: [PATCH 424/443] [8.x] Allow lazy collection to be instantiated from a generator (#36738) * Allow lazy collection to be instantiated from any iterable * Fix only allow generator, not all iterables --- src/Illuminate/Collections/LazyCollection.php | 7 +++++- tests/Support/SupportLazyCollectionTest.php | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index fbf2dbe9c84c..8fcf035c9702 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -5,6 +5,7 @@ use ArrayIterator; use Closure; use DateTimeInterface; +use Generator; use Illuminate\Support\Traits\EnumeratesValues; use Illuminate\Support\Traits\Macroable; use IteratorAggregate; @@ -29,7 +30,7 @@ class LazyCollection implements Enumerable */ public function __construct($source = null) { - if ($source instanceof Closure || $source instanceof self) { + if ($source instanceof Closure || $source instanceof Generator || $source instanceof self) { $this->source = $source; } elseif (is_null($source)) { $this->source = static::empty(); @@ -1364,6 +1365,10 @@ public function count() */ protected function makeIterator($source) { + if ($source instanceof Generator) { + return $source; + } + if ($source instanceof IteratorAggregate) { return $source->getIterator(); } diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index c671830029e1..cbb509e54f2d 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -69,6 +69,31 @@ public function testCanCreateCollectionFromClosure() ], $data->all()); } + public function testCanCreateCollectionFromGenerator() + { + $iterable = function () { + yield 1; + yield 2; + yield 3; + }; + $data = LazyCollection::make($iterable()); + + $this->assertSame([1, 2, 3], $data->all()); + + $iterable = function () { + yield 'a' => 1; + yield 'b' => 2; + yield 'c' => 3; + }; + $data = LazyCollection::make($iterable()); + + $this->assertSame([ + 'a' => 1, + 'b' => 2, + 'c' => 3, + ], $data->all()); + } + public function testEager() { $source = [1, 2, 3, 4, 5]; From 5be0afe0f5a712a8256c0f6cfad6842c2bd779a1 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 25 Mar 2021 19:01:53 +0100 Subject: [PATCH 425/443] [6.x] DynamoDB in CI suite (#36749) * Set up DynamoDB testing * env variable * Random AWS keys * AWS endpoint * try different port * Try localhost * Dynamically create table * Add provider * uppercase * KeySchema * Update table * Apply fixes from StyleCI (#36746) * throughput * exception message * Switch env statement * Remove directory --- .github/workflows/tests.yml | 9 +++ src/Illuminate/Cache/CacheManager.php | 16 +---- src/Illuminate/Cache/CacheServiceProvider.php | 17 ++++- tests/Integration/Cache/DynamoDbStoreTest.php | 68 ++++++++++++++++--- 4 files changed, 85 insertions(+), 25 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1a81af4975b9..ffe3c5a7b2e4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,11 +63,20 @@ jobs: max_attempts: 5 command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress + - name: Setup DynamoDB Local + uses: rrainn/dynamodb-action@v2.0.0 + with: + port: 8888 + - name: Execute tests run: vendor/bin/phpunit --verbose env: DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_USERNAME: root + DYNAMODB_CACHE_TABLE: laravel_dynamodb_test + DYNAMODB_ENDPOINT: "http://localhost:8888" + AWS_ACCESS_KEY_ID: random_key + AWS_SECRET_ACCESS_KEY: random_secret windows_tests: runs-on: windows-latest diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index 33d1027bce1a..42bfc7271d59 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -2,12 +2,10 @@ namespace Illuminate\Cache; -use Aws\DynamoDb\DynamoDbClient; use Closure; use Illuminate\Contracts\Cache\Factory as FactoryContract; use Illuminate\Contracts\Cache\Store; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; -use Illuminate\Support\Arr; use InvalidArgumentException; /** @@ -226,21 +224,9 @@ protected function createDatabaseDriver(array $config) */ protected function createDynamodbDriver(array $config) { - $dynamoConfig = [ - 'region' => $config['region'], - 'version' => 'latest', - 'endpoint' => $config['endpoint'] ?? null, - ]; - - if ($config['key'] && $config['secret']) { - $dynamoConfig['credentials'] = Arr::only( - $config, ['key', 'secret', 'token'] - ); - } - return $this->repository( new DynamoDbStore( - new DynamoDbClient($dynamoConfig), + $this->app['cache.dynamodb.client'], $config['table'], $config['attributes']['key'] ?? 'key', $config['attributes']['value'] ?? 'value', diff --git a/src/Illuminate/Cache/CacheServiceProvider.php b/src/Illuminate/Cache/CacheServiceProvider.php index 46fa0ae2615c..90d1d019f4be 100755 --- a/src/Illuminate/Cache/CacheServiceProvider.php +++ b/src/Illuminate/Cache/CacheServiceProvider.php @@ -2,7 +2,9 @@ namespace Illuminate\Cache; +use Aws\DynamoDb\DynamoDbClient; use Illuminate\Contracts\Support\DeferrableProvider; +use Illuminate\Support\Arr; use Illuminate\Support\ServiceProvider; use Symfony\Component\Cache\Adapter\Psr16Adapter; @@ -30,6 +32,19 @@ public function register() $this->app->singleton('memcached.connector', function () { return new MemcachedConnector; }); + + $this->app->singleton('cache.dynamodb.client', function ($app) { + $config = $app['config']->get('cache.stores.dynamodb'); + + return new DynamoDbClient([ + 'region' => $config['region'], + 'version' => 'latest', + 'endpoint' => $config['endpoint'] ?? null, + 'credentials' => Arr::only( + $config, ['key', 'secret', 'token'] + ), + ]); + }); } /** @@ -40,7 +55,7 @@ public function register() public function provides() { return [ - 'cache', 'cache.store', 'cache.psr6', 'memcached.connector', + 'cache', 'cache.store', 'cache.psr6', 'memcached.connector', 'cache.dynamodb.client', ]; } } diff --git a/tests/Integration/Cache/DynamoDbStoreTest.php b/tests/Integration/Cache/DynamoDbStoreTest.php index 74897fbde8cb..f7aeae6a3deb 100644 --- a/tests/Integration/Cache/DynamoDbStoreTest.php +++ b/tests/Integration/Cache/DynamoDbStoreTest.php @@ -2,6 +2,8 @@ namespace Illuminate\Tests\Integration\Cache; +use Aws\DynamoDb\DynamoDbClient; +use Aws\Exception\AwsException; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; use Orchestra\Testbench\TestCase; @@ -13,11 +15,11 @@ class DynamoDbStoreTest extends TestCase { protected function setUp(): void { - parent::setUp(); - if (! env('DYNAMODB_CACHE_TABLE')) { $this->markTestSkipped('DynamoDB not configured.'); } + + parent::setUp(); } public function testItemsCanBeStoredAndRetrieved() @@ -74,15 +76,63 @@ public function testLocksCanBeAcquired() */ protected function getEnvironmentSetUp($app) { + if (! env('DYNAMODB_CACHE_TABLE')) { + $this->markTestSkipped('DynamoDB not configured.'); + } + $app['config']->set('cache.default', 'dynamodb'); - $app['config']->set('cache.stores.dynamodb', [ - 'driver' => 'dynamodb', - 'key' => env('AWS_ACCESS_KEY_ID'), - 'secret' => env('AWS_SECRET_ACCESS_KEY'), - 'region' => 'us-east-1', - 'table' => env('DYNAMODB_CACHE_TABLE', 'laravel_test'), - 'endpoint' => env('DYNAMODB_ENDPOINT'), + $config = $app['config']->get('cache.stores.dynamodb'); + + /** @var \Aws\DynamoDb\DynamoDbClient $client */ + $client = $app['cache.dynamodb.client']; + + if ($this->dynamoTableExists($client, $config['table'])) { + return; + } + + $client->createTable([ + 'TableName' => $config['table'], + 'KeySchema' => [ + [ + 'AttributeName' => $config['attributes']['key'] ?? 'key', + 'KeyType' => 'HASH', + ], + ], + 'AttributeDefinitions' => [ + [ + 'AttributeName' => $config['attributes']['key'] ?? 'key', + 'AttributeType' => 'S', + ], + ], + 'ProvisionedThroughput' => [ + 'ReadCapacityUnits' => 1, + 'WriteCapacityUnits' => 1, + ], ]); } + + /** + * Determine if the given DynamoDB table exists. + * + * @param \Aws\DynamoDb\DynamoDbClient $client + * @param string $table + * @return bool + */ + public function dynamoTableExists(DynamoDbClient $client, $table) + { + try { + $client->describeTable([ + 'TableName' => $table, + ]); + + return true; + } catch (AwsException $e) { + if (Str::contains($e->getAwsErrorMessage(), ['resource not found', 'Cannot do operations on a non-existent table'])) { + return false; + } + + throw $e; + } + } } From efba08c637bd39ecbb1a5279b3f43965e1807f5e Mon Sep 17 00:00:00 2001 From: Jitendra Date: Fri, 26 Mar 2021 20:18:48 +0530 Subject: [PATCH 426/443] Removed filter on username for redis configuration parameter. (#36762) Co-authored-by: dschobert --- src/Illuminate/Redis/RedisManager.php | 2 +- tests/Redis/RedisConnectorTest.php | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index b5d98203c180..8a6c88d1c2ba 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -192,7 +192,7 @@ protected function parseConnectionConfiguration($config) } return array_filter($parsed, function ($key) { - return ! in_array($key, ['driver', 'username'], true); + return ! in_array($key, ['driver'], true); }, ARRAY_FILTER_USE_KEY); } diff --git a/tests/Redis/RedisConnectorTest.php b/tests/Redis/RedisConnectorTest.php index 599fa2f2aad3..0203ed9d9b82 100644 --- a/tests/Redis/RedisConnectorTest.php +++ b/tests/Redis/RedisConnectorTest.php @@ -160,4 +160,27 @@ public function testScheme() $this->assertEquals("tcp://{$host}", $phpRedisClient->getHost()); $this->assertEquals($port, $phpRedisClient->getPort()); } + + public function testPredisConfigurationWithUsername() + { + $host = env('REDIS_HOST', '127.0.0.1'); + $port = env('REDIS_PORT', 6379); + $username = 'testuser'; + $password = 'testpw'; + + $predis = new RedisManager(new Application, 'predis', [ + 'default' => [ + 'host' => $host, + 'port' => $port, + 'username' => $username, + 'password' => $password, + 'database' => 5, + 'timeout' => 0.5, + ], + ]); + $predisClient = $predis->connection()->client(); + $parameters = $predisClient->getConnection()->getParameters(); + $this->assertEquals($username, $parameters->username); + $this->assertEquals($password, $parameters->password); + } } From 31c5e1f55f69ca7f78bb55c8f2c130493b922306 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 26 Mar 2021 23:03:14 +0800 Subject: [PATCH 427/443] Fixes missing `lazy()` and `lazyById()` on BelongsToMany and HasManyThrough relation query builder. (#36758) Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Relations/BelongsToMany.php | 58 +++++++- .../Eloquent/Relations/HasManyThrough.php | 28 ++++ ...abaseEloquentBelongsToManyLazyByIdTest.php | 134 ++++++++++++++++++ ...eEloquentHasManyThroughIntegrationTest.php | 46 ++++++ ...seEloquentHasOneThroughIntegrationTest.php | 19 +++ 5 files changed, 278 insertions(+), 7 deletions(-) create mode 100644 tests/Database/DatabaseEloquentBelongsToManyLazyByIdTest.php diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 9e7ed7a53a66..bc4d660a9b18 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -865,9 +865,7 @@ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'p */ public function chunk($count, callable $callback) { - $this->query->addSelect($this->shouldSelect()); - - return $this->query->chunk($count, function ($results, $page) use ($callback) { + return $this->prepareQueryBuilder()->chunk($count, function ($results, $page) use ($callback) { $this->hydratePivotRelation($results->all()); return $callback($results, $page); @@ -885,7 +883,7 @@ public function chunk($count, callable $callback) */ public function chunkById($count, callable $callback, $column = null, $alias = null) { - $this->query->addSelect($this->shouldSelect()); + $this->prepareQueryBuilder(); $column = $column ?? $this->getRelated()->qualifyColumn( $this->getRelatedKeyName() @@ -918,6 +916,44 @@ public function each(callable $callback, $count = 1000) }); } + /** + * Query lazily, by chunks of the given size. + * + * @param int $chunkSize + * @return \Illuminate\Support\LazyCollection + */ + public function lazy($chunkSize = 1000) + { + return $this->prepareQueryBuilder()->lazy($chunkSize)->map(function ($model) { + $this->hydratePivotRelation([$model]); + + return $model; + }); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs. + * + * @param int $count + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyById($chunkSize = 1000, $column = null, $alias = null) + { + $column = $column ?? $this->getRelated()->qualifyColumn( + $this->getRelatedKeyName() + ); + + $alias = $alias ?? $this->getRelatedKeyName(); + + return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias)->map(function ($model) { + $this->hydratePivotRelation([$model]); + + return $model; + }); + } + /** * Get a lazy collection for the given query. * @@ -925,15 +961,23 @@ public function each(callable $callback, $count = 1000) */ public function cursor() { - $this->query->addSelect($this->shouldSelect()); - - return $this->query->cursor()->map(function ($model) { + return $this->prepareQueryBuilder()->cursor()->map(function ($model) { $this->hydratePivotRelation([$model]); return $model; }); } + /** + * Prepare the query builder for query execution. + * + * @return \Illuminate\Database\Eloquent\Builder + */ + protected function prepareQueryBuilder() + { + return $this->query->addSelect($this->shouldSelect()); + } + /** * Hydrate the pivot table relationship on the models. * diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 6285cf230b7f..8b3a2992658a 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -501,6 +501,34 @@ public function each(callable $callback, $count = 1000) }); } + /** + * Query lazily, by chunks of the given size. + * + * @param int $chunkSize + * @return \Illuminate\Support\LazyCollection + */ + public function lazy($chunkSize = 1000) + { + return $this->prepareQueryBuilder()->lazy($chunkSize); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs. + * + * @param int $count + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyById($chunkSize = 1000, $column = null, $alias = null) + { + $column = $column ?? $this->getRelated()->getQualifiedKeyName(); + + $alias = $alias ?? $this->getRelated()->getKeyName(); + + return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias); + } + /** * Prepare the query builder for query execution. * diff --git a/tests/Database/DatabaseEloquentBelongsToManyLazyByIdTest.php b/tests/Database/DatabaseEloquentBelongsToManyLazyByIdTest.php new file mode 100644 index 000000000000..cbdf1ffbda19 --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManyLazyByIdTest.php @@ -0,0 +1,134 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + /** + * Setup the database schema. + * + * @return void + */ + public function createSchema() + { + $this->schema()->create('users', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + }); + + $this->schema()->create('articles', function ($table) { + $table->increments('aid'); + $table->string('title'); + }); + + $this->schema()->create('article_user', function ($table) { + $table->integer('article_id')->unsigned(); + $table->foreign('article_id')->references('aid')->on('articles'); + $table->integer('user_id')->unsigned(); + $table->foreign('user_id')->references('id')->on('users'); + }); + } + + public function testBelongsToLazyById() + { + $this->seedData(); + + $user = BelongsToManyLazyByIdTestTestUser::query()->first(); + $i = 0; + + $user->articles()->lazyById(1)->each(function ($model) use (&$i) { + $i++; + $this->assertEquals($i, $model->aid); + }); + + $this->assertSame(3, $i); + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + $this->schema()->drop('users'); + $this->schema()->drop('articles'); + $this->schema()->drop('article_user'); + } + + /** + * Helpers... + */ + protected function seedData() + { + $user = BelongsToManyLazyByIdTestTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + BelongsToManyLazyByIdTestTestArticle::query()->insert([ + ['aid' => 1, 'title' => 'Another title'], + ['aid' => 2, 'title' => 'Another title'], + ['aid' => 3, 'title' => 'Another title'], + ]); + + $user->articles()->sync([3, 1, 2]); + } + + /** + * Get a database connection instance. + * + * @return \Illuminate\Database\ConnectionInterface + */ + protected function connection() + { + return Eloquent::getConnectionResolver()->connection(); + } + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema() + { + return $this->connection()->getSchemaBuilder(); + } +} + +class BelongsToManyLazyByIdTestTestUser extends Eloquent +{ + protected $table = 'users'; + protected $fillable = ['id', 'email']; + public $timestamps = false; + + public function articles() + { + return $this->belongsToMany(BelongsToManyLazyByIdTestTestArticle::class, 'article_user', 'user_id', 'article_id'); + } +} + +class BelongsToManyLazyByIdTestTestArticle extends Eloquent +{ + protected $primaryKey = 'aid'; + protected $table = 'articles'; + protected $keyType = 'string'; + public $incrementing = false; + public $timestamps = false; + protected $fillable = ['aid', 'title']; +} diff --git a/tests/Database/DatabaseEloquentHasManyThroughIntegrationTest.php b/tests/Database/DatabaseEloquentHasManyThroughIntegrationTest.php index d1572adcaade..b4c207efa820 100644 --- a/tests/Database/DatabaseEloquentHasManyThroughIntegrationTest.php +++ b/tests/Database/DatabaseEloquentHasManyThroughIntegrationTest.php @@ -321,6 +321,52 @@ public function testEachReturnsCorrectModels() }); } + public function testLazyReturnsCorrectModels() + { + $this->seedData(); + $this->seedDataExtended(); + $country = HasManyThroughTestCountry::find(2); + + $country->posts()->lazy(10)->each(function ($post) { + $this->assertEquals([ + 'id', + 'user_id', + 'title', + 'body', + 'email', + 'created_at', + 'updated_at', + 'laravel_through_key', + ], array_keys($post->getAttributes())); + }); + } + + public function testLazyById() + { + $this->seedData(); + $this->seedDataExtended(); + $country = HasManyThroughTestCountry::find(2); + + $i = 0; + + $country->posts()->lazyById(2)->each(function ($post) use (&$i, &$count) { + $i++; + + $this->assertEquals([ + 'id', + 'user_id', + 'title', + 'body', + 'email', + 'created_at', + 'updated_at', + 'laravel_through_key', + ], array_keys($post->getAttributes())); + }); + + $this->assertEquals(6, $i); + } + public function testIntermediateSoftDeletesAreIgnored() { $this->seedData(); diff --git a/tests/Database/DatabaseEloquentHasOneThroughIntegrationTest.php b/tests/Database/DatabaseEloquentHasOneThroughIntegrationTest.php index 67b9824f98e3..0b2bf287bcdb 100644 --- a/tests/Database/DatabaseEloquentHasOneThroughIntegrationTest.php +++ b/tests/Database/DatabaseEloquentHasOneThroughIntegrationTest.php @@ -234,6 +234,25 @@ public function testEachReturnsCorrectModels() }); } + public function testLazyReturnsCorrectModels() + { + $this->seedData(); + $this->seedDataExtended(); + $position = HasOneThroughTestPosition::find(1); + + $position->contract()->lazy()->each(function ($contract) { + $this->assertEquals([ + 'id', + 'user_id', + 'title', + 'body', + 'email', + 'created_at', + 'updated_at', + 'laravel_through_key', ], array_keys($contract->getAttributes())); + }); + } + public function testIntermediateSoftDeletesAreIgnored() { $this->seedData(); From 006ba38124df6a8a651546a0301d604665b394b7 Mon Sep 17 00:00:00 2001 From: vdlp-mw <47185594+vdlp-mw@users.noreply.github.com> Date: Fri, 26 Mar 2021 16:54:12 +0100 Subject: [PATCH 428/443] Use qualified column names in pivot query (#36720) Co-authored-by: Menzo Wijmenga --- .../Eloquent/Relations/Concerns/InteractsWithPivotTable.php | 4 ++-- tests/Database/DatabaseEloquentMorphToManyTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index c6812b75a150..b0abf2848590 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -429,7 +429,7 @@ public function detach($ids = null, $touch = true) return 0; } - $query->whereIn($this->relatedPivotKey, (array) $ids); + $query->whereIn($this->getQualifiedRelatedPivotKeyName(), (array) $ids); } // Once we have all of the conditions set on the statement, we are ready @@ -544,7 +544,7 @@ public function newPivotQuery() $query->whereIn(...$arguments); } - return $query->where($this->foreignPivotKey, $this->parent->{$this->parentKey}); + return $query->where($this->getQualifiedForeignPivotKeyName(), $this->parent->{$this->parentKey}); } /** diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 0b4a7f511074..dac94e258c39 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -47,9 +47,9 @@ public function testDetachRemovesPivotTableRecord() $relation = $this->getMockBuilder(MorphToMany::class)->setMethods(['touchIfTouching'])->setConstructorArgs($this->getRelationArguments())->getMock(); $query = m::mock(stdClass::class); $query->shouldReceive('from')->once()->with('taggables')->andReturn($query); - $query->shouldReceive('where')->once()->with('taggable_id', 1)->andReturn($query); + $query->shouldReceive('where')->once()->with('taggables.taggable_id', 1)->andReturn($query); $query->shouldReceive('where')->once()->with('taggable_type', get_class($relation->getParent()))->andReturn($query); - $query->shouldReceive('whereIn')->once()->with('tag_id', [1, 2, 3]); + $query->shouldReceive('whereIn')->once()->with('taggables.tag_id', [1, 2, 3]); $query->shouldReceive('delete')->once()->andReturn(true); $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); @@ -63,7 +63,7 @@ public function testDetachMethodClearsAllPivotRecordsWhenNoIDsAreGiven() $relation = $this->getMockBuilder(MorphToMany::class)->setMethods(['touchIfTouching'])->setConstructorArgs($this->getRelationArguments())->getMock(); $query = m::mock(stdClass::class); $query->shouldReceive('from')->once()->with('taggables')->andReturn($query); - $query->shouldReceive('where')->once()->with('taggable_id', 1)->andReturn($query); + $query->shouldReceive('where')->once()->with('taggables.taggable_id', 1)->andReturn($query); $query->shouldReceive('where')->once()->with('taggable_type', get_class($relation->getParent()))->andReturn($query); $query->shouldReceive('whereIn')->never(); $query->shouldReceive('delete')->once()->andReturn(true); From a2b7c7ceca5ee9470a50c3f67f54047c595940a2 Mon Sep 17 00:00:00 2001 From: cod1k Date: Thu, 11 Mar 2021 15:11:48 +0200 Subject: [PATCH 429/443] illegal offset type fix --- .../Database/Eloquent/Relations/BelongsTo.php | 11 +++++---- .../Eloquent/Relations/BelongsToMany.php | 10 +++++--- .../Concerns/InteractsWithDictionary.php | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index ce7ba4421973..8714ee1e7e11 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -6,11 +6,12 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Concerns\ComparesRelatedModels; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; class BelongsTo extends Relation { - use ComparesRelatedModels, SupportsDefaultModels; + use ComparesRelatedModels, SupportsDefaultModels, InteractsWithDictionary; /** * The child model instance of the relation. @@ -174,15 +175,17 @@ public function match(array $models, Collection $results, $relation) $dictionary = []; foreach ($results as $result) { - $dictionary[$result->getAttribute($owner)] = $result; + $attribute = $this->dictionaryKey($result->getAttribute($owner)); + $dictionary[$attribute] = $result; } // Once we have the dictionary constructed, we can loop through all the parents // and match back onto their children using these keys of the dictionary and // the primary key of the children to map them onto the correct instances. foreach ($models as $model) { - if (isset($dictionary[$model->{$foreign}])) { - $model->setRelation($relation, $dictionary[$model->{$foreign}]); + $attribute = $this->dictionaryKey($model->{$foreign}); + if (isset($dictionary[$attribute])) { + $model->setRelation($relation, $dictionary[$attribute]); } } diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index bc4d660a9b18..4f2dceaec31d 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -8,12 +8,14 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable; use Illuminate\Support\Str; use InvalidArgumentException; class BelongsToMany extends Relation { - use Concerns\InteractsWithPivotTable; + use InteractsWithPivotTable, InteractsWithDictionary; /** * The intermediate table for the relation. @@ -277,7 +279,8 @@ public function match(array $models, Collection $results, $relation) // children back to their parent using the dictionary and the keys on the // the parent models. Then we will return the hydrated models back out. foreach ($models as $model) { - if (isset($dictionary[$key = $model->{$this->parentKey}])) { + $key = $this->dictionaryKey($model->{$this->parentKey}); + if (isset($dictionary[$key])) { $model->setRelation( $relation, $this->related->newCollection($dictionary[$key]) ); @@ -301,7 +304,8 @@ protected function buildDictionary(Collection $results) $dictionary = []; foreach ($results as $result) { - $dictionary[$result->{$this->accessor}->{$this->foreignPivotKey}][] = $result; + $value = $this->dictionaryKey($result->{$this->accessor}->{$this->foreignPivotKey}); + $dictionary[$value][] = $result; } return $dictionary; diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php new file mode 100644 index 000000000000..9f70681fbe3e --- /dev/null +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php @@ -0,0 +1,24 @@ +__toString(); + } + throw new InvalidArgumentException('Attribute value is an object without __toString method'); + } + + return $attribute; + } +} From 7694d29782fdf3b69134fdd99165f74919522f34 Mon Sep 17 00:00:00 2001 From: cod1k Date: Thu, 25 Mar 2021 00:34:25 +0200 Subject: [PATCH 430/443] refactoring + spreading to other relations types --- src/Illuminate/Database/Eloquent/Relations/BelongsTo.php | 4 ++-- .../Database/Eloquent/Relations/BelongsToMany.php | 4 ++-- .../Relations/Concerns/InteractsWithDictionary.php | 6 +++--- .../Database/Eloquent/Relations/HasManyThrough.php | 4 +++- .../Database/Eloquent/Relations/HasOneOrMany.php | 7 +++++-- .../Database/Eloquent/Relations/HasOneThrough.php | 5 +++-- src/Illuminate/Database/Eloquent/Relations/MorphTo.php | 8 ++++++-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index 8714ee1e7e11..44ede71a4c3a 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -175,7 +175,7 @@ public function match(array $models, Collection $results, $relation) $dictionary = []; foreach ($results as $result) { - $attribute = $this->dictionaryKey($result->getAttribute($owner)); + $attribute = $this->getDictionaryKey($result->getAttribute($owner)); $dictionary[$attribute] = $result; } @@ -183,7 +183,7 @@ public function match(array $models, Collection $results, $relation) // and match back onto their children using these keys of the dictionary and // the primary key of the children to map them onto the correct instances. foreach ($models as $model) { - $attribute = $this->dictionaryKey($model->{$foreign}); + $attribute = $this->getDictionaryKey($model->{$foreign}); if (isset($dictionary[$attribute])) { $model->setRelation($relation, $dictionary[$attribute]); } diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 4f2dceaec31d..b354ab5c5f92 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -279,7 +279,7 @@ public function match(array $models, Collection $results, $relation) // children back to their parent using the dictionary and the keys on the // the parent models. Then we will return the hydrated models back out. foreach ($models as $model) { - $key = $this->dictionaryKey($model->{$this->parentKey}); + $key = $this->getDictionaryKey($model->{$this->parentKey}); if (isset($dictionary[$key])) { $model->setRelation( $relation, $this->related->newCollection($dictionary[$key]) @@ -304,7 +304,7 @@ protected function buildDictionary(Collection $results) $dictionary = []; foreach ($results as $result) { - $value = $this->dictionaryKey($result->{$this->accessor}->{$this->foreignPivotKey}); + $value = $this->getDictionaryKey($result->{$this->accessor}->{$this->foreignPivotKey}); $dictionary[$value][] = $result; } diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php index 9f70681fbe3e..9619533a91ee 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php @@ -2,7 +2,7 @@ namespace Illuminate\Database\Eloquent\Relations\Concerns; -use InvalidArgumentException; +use Doctrine\Instantiator\Exception\InvalidArgumentException; trait InteractsWithDictionary { @@ -10,13 +10,13 @@ trait InteractsWithDictionary * @param mixed $attribute * @return mixed */ - protected function dictionaryKey($attribute) + protected function getDictionaryKey($attribute) { if (is_object($attribute)) { if (method_exists($attribute, '__toString')) { return $attribute->__toString(); } - throw new InvalidArgumentException('Attribute value is an object without __toString method'); + throw new InvalidArgumentException('Attribute value is an object without __toString method'); //I would prefer to throw an exception instead of "silent" and unintended behaviour } return $attribute; diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 8b3a2992658a..efe9b4bd47a5 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -7,10 +7,12 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; use Illuminate\Database\Eloquent\SoftDeletes; class HasManyThrough extends Relation { + use InteractsWithDictionary; /** * The "through" parent model instance. * @@ -193,7 +195,7 @@ public function match(array $models, Collection $results, $relation) // link them up with their children using the keyed dictionary to make the // matching very convenient and easy work. Then we'll just return them. foreach ($models as $model) { - if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { + if (isset($dictionary[$key = $this->getDictionaryKey($model->getAttribute($this->localKey))])) { $model->setRelation( $relation, $this->related->newCollection($dictionary[$key]) ); diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index f09133c8bf6c..3d6964b48854 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -5,9 +5,11 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; abstract class HasOneOrMany extends Relation { + use InteractsWithDictionary; /** * The foreign key of the parent model. * @@ -141,7 +143,7 @@ protected function matchOneOrMany(array $models, Collection $results, $relation, // link them up with their children using the keyed dictionary to make the // matching very convenient and easy work. Then we'll just return them. foreach ($models as $model) { - if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { + if (isset($dictionary[$key = $this->getDictionaryKey($model->getAttribute($this->localKey))])) { $model->setRelation( $relation, $this->getRelationValue($dictionary, $key, $type) ); @@ -177,7 +179,8 @@ protected function buildDictionary(Collection $results) $foreign = $this->getForeignKeyName(); return $results->mapToDictionary(function ($result) use ($foreign) { - return [$result->{$foreign} => $result]; + $dictionaryKey = $this->getDictionaryKey($result->{$foreign}); + return [$dictionaryKey => $result]; })->all(); } diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php index a48c3186214a..ce47ae2eb1b8 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php @@ -4,11 +4,12 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; class HasOneThrough extends HasManyThrough { - use SupportsDefaultModels; + use SupportsDefaultModels, InteractsWithDictionary; /** * Get the results of the relationship. @@ -52,7 +53,7 @@ public function match(array $models, Collection $results, $relation) // link them up with their children using the keyed dictionary to make the // matching very convenient and easy work. Then we'll just return them. foreach ($models as $model) { - if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { + if (isset($dictionary[$key = $this->getDictionaryKey($model->getAttribute($this->localKey))])) { $value = $dictionary[$key]; $model->setRelation( $relation, reset($value) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index 8a6c7a2cbca8..011554bf47ff 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -6,9 +6,11 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary; class MorphTo extends BelongsTo { + use InteractsWithDictionary; /** * The type of the polymorphic relation. * @@ -97,7 +99,9 @@ protected function buildDictionary(Collection $models) { foreach ($models as $model) { if ($model->{$this->morphType}) { - $this->dictionary[$model->{$this->morphType}][$model->{$this->foreignKey}][] = $model; + $morphTypeKey = $this->getDictionaryKey($model->{$this->morphType}); + $foreignKeyKey = $this->getDictionaryKey($model->{$this->foreignKey}); + $this->dictionary[$morphTypeKey][$foreignKeyKey][] = $model; } } } @@ -207,7 +211,7 @@ public function match(array $models, Collection $results, $relation) protected function matchToMorphParents($type, Collection $results) { foreach ($results as $result) { - $ownerKey = ! is_null($this->ownerKey) ? $result->{$this->ownerKey} : $result->getKey(); + $ownerKey = ! is_null($this->ownerKey) ? $this->getDictionaryKey($result->{$this->ownerKey}) : $result->getKey(); if (isset($this->dictionary[$type][$ownerKey])) { foreach ($this->dictionary[$type][$ownerKey] as $model) { From 3ed38719e244a53bf12a372837d363d75e0bbe16 Mon Sep 17 00:00:00 2001 From: cod1k Date: Thu, 25 Mar 2021 18:20:56 +0200 Subject: [PATCH 431/443] style fix --- src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 3d6964b48854..da6455c60904 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -180,6 +180,7 @@ protected function buildDictionary(Collection $results) return $results->mapToDictionary(function ($result) use ($foreign) { $dictionaryKey = $this->getDictionaryKey($result->{$foreign}); + return [$dictionaryKey => $result]; })->all(); } From 302f66683919a12be3e81708f9e1422bb6459b2f Mon Sep 17 00:00:00 2001 From: cod1k Date: Thu, 25 Mar 2021 18:21:06 +0200 Subject: [PATCH 432/443] tests --- ...tBelongsToManyWithCastedAttributesTest.php | 77 +++++++++++++++++++ .../DatabaseEloquentBelongsToTest.php | 17 +++- tests/Database/DatabaseEloquentHasOneTest.php | 12 ++- .../Database/DatabaseEloquentMorphToTest.php | 7 ++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php new file mode 100644 index 000000000000..458a4d6dd6a3 --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -0,0 +1,77 @@ +getRelation(); + $model1 = m::mock(Model::class); + $model1->shouldReceive('getAttribute')->with('parent_key')->andReturn(1); + $model1->shouldReceive('getAttribute')->with('foo')->passthru(); + $model1->shouldReceive('hasGetMutator')->andReturn(false); + $model1->shouldReceive('getCasts')->andReturn([]); + $model1->shouldReceive('getRelationValue', 'relationLoaded', 'setRelation')->passthru(); + + $model2 = m::mock(Model::class); + $model2->shouldReceive('getAttribute')->with('parent_key')->andReturn(2); + $model2->shouldReceive('getAttribute')->with('foo')->passthru(); + $model2->shouldReceive('hasGetMutator')->andReturn(false); + $model2->shouldReceive('getCasts')->andReturn([]); + $model2->shouldReceive('getRelationValue', 'relationLoaded', 'setRelation')->passthru(); + + $result1 = (object) [ + 'pivot' => (object) [ + 'foreign_key' => new class { + public function __toString() + { + return '1'; + } + }, + ], + ]; + + $models = $relation->match([$model1, $model2], Collection::wrap($result1), 'foo'); + self::assertNull($models[1]->foo); + self::assertEquals(1, $models[0]->foo->count()); + self::assertContains($result1, $models[0]->foo); + } + + protected function getRelation() + { + $builder = m::mock(Builder::class); + $related = m::mock(Model::class); + $related->shouldReceive('newCollection')->passthru(); + $builder->shouldReceive('getModel')->andReturn($related); + $related->shouldReceive('qualifyColumn'); + $builder->shouldReceive('join', 'where'); + + return new BelongsToMany( + $builder, + new EloquentBelongsToManyModelStub, + 'relation', + 'foreign_key', + 'id', + 'parent_key', + 'related_key' + ); + } +} + +class EloquentBelongsToManyModelStub extends Model +{ + public $foreign_key = 'foreign.value'; +} diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php index 1d77ba37c108..b8c00b572a5d 100755 --- a/tests/Database/DatabaseEloquentBelongsToTest.php +++ b/tests/Database/DatabaseEloquentBelongsToTest.php @@ -109,14 +109,29 @@ public function testModelsAreProperlyMatchedToParents() $result1->shouldReceive('getAttribute')->with('id')->andReturn(1); $result2 = m::mock(stdClass::class); $result2->shouldReceive('getAttribute')->with('id')->andReturn(2); + $result3 = m::mock(stdClass::class); + $result3->shouldReceive('getAttribute')->with('id')->andReturn(new class { + public function __toString() + { + return '3'; + } + }); $model1 = new EloquentBelongsToModelStub; $model1->foreign_key = 1; $model2 = new EloquentBelongsToModelStub; $model2->foreign_key = 2; - $models = $relation->match([$model1, $model2], new Collection([$result1, $result2]), 'foo'); + $model3 = new EloquentBelongsToModelStub; + $model3->foreign_key = new class { + public function __toString() + { + return '3'; + } + }; + $models = $relation->match([$model1, $model2, $model3], new Collection([$result1, $result2, $result3]), 'foo'); $this->assertEquals(1, $models[0]->foo->getAttribute('id')); $this->assertEquals(2, $models[1]->foo->getAttribute('id')); + $this->assertEquals('3', $models[2]->foo->getAttribute('id')); } public function testAssociateMethodSetsForeignKeyOnModel() diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index 0e35d679784d..cac4c84ca53b 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -160,6 +160,13 @@ public function testModelsAreProperlyMatchedToParents() $result1->foreign_key = 1; $result2 = new EloquentHasOneModelStub; $result2->foreign_key = 2; + $result3 = new EloquentHasOneModelStub; + $result3->foreign_key = new class { + public function __toString() + { + return '4'; + } + }; $model1 = new EloquentHasOneModelStub; $model1->id = 1; @@ -167,12 +174,15 @@ public function testModelsAreProperlyMatchedToParents() $model2->id = 2; $model3 = new EloquentHasOneModelStub; $model3->id = 3; + $model4 = new EloquentHasOneModelStub; + $model4->id = 4; - $models = $relation->match([$model1, $model2, $model3], new Collection([$result1, $result2]), 'foo'); + $models = $relation->match([$model1, $model2, $model3, $model4], new Collection([$result1, $result2, $result3]), 'foo'); $this->assertEquals(1, $models[0]->foo->foreign_key); $this->assertEquals(2, $models[1]->foo->foreign_key); $this->assertNull($models[2]->foo); + $this->assertEquals('4', $models[3]->foo->foreign_key); } public function testRelationCountQueryCanBeBuilt() diff --git a/tests/Database/DatabaseEloquentMorphToTest.php b/tests/Database/DatabaseEloquentMorphToTest.php index 0b0741de406c..6895d3a656de 100644 --- a/tests/Database/DatabaseEloquentMorphToTest.php +++ b/tests/Database/DatabaseEloquentMorphToTest.php @@ -26,6 +26,12 @@ public function testLookupDictionaryIsProperlyConstructed() $one = (object) ['morph_type' => 'morph_type_1', 'foreign_key' => 'foreign_key_1'], $two = (object) ['morph_type' => 'morph_type_1', 'foreign_key' => 'foreign_key_1'], $three = (object) ['morph_type' => 'morph_type_2', 'foreign_key' => 'foreign_key_2'], + $four = (object) ['morph_type' => 'morph_type_2', 'foreign_key' => new class { + public function __toString() + { + return 'foreign_key_2'; + } + }], ]); $dictionary = $relation->getDictionary(); @@ -40,6 +46,7 @@ public function testLookupDictionaryIsProperlyConstructed() 'morph_type_2' => [ 'foreign_key_2' => [ $three, + $four, ], ], ], $dictionary); From 9d49b7d3ad22f0c4989fcfa60afb3ef24778e8a7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 26 Mar 2021 09:04:42 -0700 Subject: [PATCH 433/443] formatting --- src/Illuminate/Database/Eloquent/Relations/BelongsTo.php | 6 +++++- .../Database/Eloquent/Relations/BelongsToMany.php | 4 +++- .../Relations/Concerns/InteractsWithDictionary.php | 7 +++++-- .../Database/Eloquent/Relations/HasManyThrough.php | 1 + .../Database/Eloquent/Relations/HasOneOrMany.php | 5 ++--- .../Database/Eloquent/Relations/HasOneThrough.php | 2 +- src/Illuminate/Database/Eloquent/Relations/MorphTo.php | 2 ++ 7 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index 44ede71a4c3a..a98cba0ad375 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -11,7 +11,9 @@ class BelongsTo extends Relation { - use ComparesRelatedModels, SupportsDefaultModels, InteractsWithDictionary; + use ComparesRelatedModels, + InteractsWithDictionary, + SupportsDefaultModels; /** * The child model instance of the relation. @@ -176,6 +178,7 @@ public function match(array $models, Collection $results, $relation) foreach ($results as $result) { $attribute = $this->getDictionaryKey($result->getAttribute($owner)); + $dictionary[$attribute] = $result; } @@ -184,6 +187,7 @@ public function match(array $models, Collection $results, $relation) // the primary key of the children to map them onto the correct instances. foreach ($models as $model) { $attribute = $this->getDictionaryKey($model->{$foreign}); + if (isset($dictionary[$attribute])) { $model->setRelation($relation, $dictionary[$attribute]); } diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index b354ab5c5f92..d85030b9a132 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -15,7 +15,7 @@ class BelongsToMany extends Relation { - use InteractsWithPivotTable, InteractsWithDictionary; + use InteractsWithDictionary, InteractsWithPivotTable; /** * The intermediate table for the relation. @@ -280,6 +280,7 @@ public function match(array $models, Collection $results, $relation) // the parent models. Then we will return the hydrated models back out. foreach ($models as $model) { $key = $this->getDictionaryKey($model->{$this->parentKey}); + if (isset($dictionary[$key])) { $model->setRelation( $relation, $this->related->newCollection($dictionary[$key]) @@ -305,6 +306,7 @@ protected function buildDictionary(Collection $results) foreach ($results as $result) { $value = $this->getDictionaryKey($result->{$this->accessor}->{$this->foreignPivotKey}); + $dictionary[$value][] = $result; } diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php index 9619533a91ee..9e2186150630 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithDictionary.php @@ -7,7 +7,9 @@ trait InteractsWithDictionary { /** - * @param mixed $attribute + * Get a dictionary key attribute - casting it to a string if necessary. + * + * @param mixed $attribute * @return mixed */ protected function getDictionaryKey($attribute) @@ -16,7 +18,8 @@ protected function getDictionaryKey($attribute) if (method_exists($attribute, '__toString')) { return $attribute->__toString(); } - throw new InvalidArgumentException('Attribute value is an object without __toString method'); //I would prefer to throw an exception instead of "silent" and unintended behaviour + + throw new InvalidArgumentException('Model attribute value is an object but does not have a __toString method.'); } return $attribute; diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index efe9b4bd47a5..9ea307562ca1 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -13,6 +13,7 @@ class HasManyThrough extends Relation { use InteractsWithDictionary; + /** * The "through" parent model instance. * diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index da6455c60904..18b0f8fc9256 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -10,6 +10,7 @@ abstract class HasOneOrMany extends Relation { use InteractsWithDictionary; + /** * The foreign key of the parent model. * @@ -179,9 +180,7 @@ protected function buildDictionary(Collection $results) $foreign = $this->getForeignKeyName(); return $results->mapToDictionary(function ($result) use ($foreign) { - $dictionaryKey = $this->getDictionaryKey($result->{$foreign}); - - return [$dictionaryKey => $result]; + return [$this->getDictionaryKey($result->{$foreign}) => $result]; })->all(); } diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php index ce47ae2eb1b8..ed9c7baa4dc3 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneThrough.php @@ -9,7 +9,7 @@ class HasOneThrough extends HasManyThrough { - use SupportsDefaultModels, InteractsWithDictionary; + use InteractsWithDictionary, SupportsDefaultModels; /** * Get the results of the relationship. diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index 011554bf47ff..53d25cb4470a 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -11,6 +11,7 @@ class MorphTo extends BelongsTo { use InteractsWithDictionary; + /** * The type of the polymorphic relation. * @@ -101,6 +102,7 @@ protected function buildDictionary(Collection $models) if ($model->{$this->morphType}) { $morphTypeKey = $this->getDictionaryKey($model->{$this->morphType}); $foreignKeyKey = $this->getDictionaryKey($model->{$this->foreignKey}); + $this->dictionary[$morphTypeKey][$foreignKeyKey][] = $model; } } From 90fbaa7ec53410508cd73c09e3f788e458dd8b92 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 26 Mar 2021 11:39:16 -0700 Subject: [PATCH 434/443] Octane Prep (#36777) * set container instance on route when matched * allow container to be set on router * add setApplication method to http kernel * add flushQueuedCookies method * remove old auth.loaded binding * add authentication and authorization container reset methods * add new pagination state class for easy refreshing of pagination state resolvers * support resetting state on broadcast manager * add support for resetting mailer state * add base manager support for resetting state - for notification channel manager * add container accessors to pipeline hub * add methods for container state reset on queue manager * add container accessors to validation factory --- src/Illuminate/Auth/Access/Gate.php | 13 +++++++ src/Illuminate/Auth/AuthManager.php | 25 +++++++++++++ src/Illuminate/Auth/AuthServiceProvider.php | 36 ++++++------------ .../Broadcasting/BroadcastManager.php | 35 ++++++++++++++++++ src/Illuminate/Cookie/CookieJar.php | 12 ++++++ src/Illuminate/Foundation/Http/Kernel.php | 13 +++++++ src/Illuminate/Mail/MailManager.php | 35 ++++++++++++++++++ .../Pagination/PaginationServiceProvider.php | 22 +---------- src/Illuminate/Pagination/PaginationState.php | 37 +++++++++++++++++++ src/Illuminate/Pipeline/Hub.php | 23 ++++++++++++ src/Illuminate/Queue/Queue.php | 10 +++++ src/Illuminate/Queue/QueueManager.php | 27 ++++++++++++++ src/Illuminate/Routing/Router.php | 15 ++++++++ src/Illuminate/Support/Manager.php | 33 +++++++++++++++++ src/Illuminate/Validation/Factory.php | 23 ++++++++++++ 15 files changed, 314 insertions(+), 45 deletions(-) create mode 100644 src/Illuminate/Pagination/PaginationState.php diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 0497a8e344b8..0bcc0e35844d 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -800,4 +800,17 @@ public function policies() { return $this->policies; } + + /** + * Set the container instance used by the gate. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return $this + */ + public function setContainer(Container $container) + { + $this->container = $container; + + return $this; + } } diff --git a/src/Illuminate/Auth/AuthManager.php b/src/Illuminate/Auth/AuthManager.php index ebbd7f5f1ac5..823b96ca319f 100755 --- a/src/Illuminate/Auth/AuthManager.php +++ b/src/Illuminate/Auth/AuthManager.php @@ -295,6 +295,31 @@ public function hasResolvedGuards() return count($this->guards) > 0; } + /** + * Forget all of the resolved guard instances. + * + * @return $this + */ + public function forgetGuards() + { + $this->guards = []; + + return $this; + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return $this + */ + public function setApplication($app) + { + $this->app = $app; + + return $this; + } + /** * Dynamically call the default driver instance. * diff --git a/src/Illuminate/Auth/AuthServiceProvider.php b/src/Illuminate/Auth/AuthServiceProvider.php index 7a6b41212784..9c17edfa1c6f 100755 --- a/src/Illuminate/Auth/AuthServiceProvider.php +++ b/src/Illuminate/Auth/AuthServiceProvider.php @@ -35,11 +35,6 @@ public function register() protected function registerAuthenticator() { $this->app->singleton('auth', function ($app) { - // Once the authentication service has actually been requested by the developer - // we will set a variable in the application indicating such. This helps us - // know that we need to set any queued cookies in the after event later. - $app['auth.loaded'] = true; - return new AuthManager($app); }); @@ -55,11 +50,9 @@ protected function registerAuthenticator() */ protected function registerUserResolver() { - $this->app->bind( - AuthenticatableContract::class, function ($app) { - return call_user_func($app['auth']->userResolver()); - } - ); + $this->app->bind(AuthenticatableContract::class, function ($app) { + return call_user_func($app['auth']->userResolver()); + }); } /** @@ -83,15 +76,13 @@ protected function registerAccessGate() */ protected function registerRequirePassword() { - $this->app->bind( - RequirePassword::class, function ($app) { - return new RequirePassword( - $app[ResponseFactory::class], - $app[UrlGenerator::class], - $app['config']->get('auth.password_timeout') - ); - } - ); + $this->app->bind(RequirePassword::class, function ($app) { + return new RequirePassword( + $app[ResponseFactory::class], + $app[UrlGenerator::class], + $app['config']->get('auth.password_timeout') + ); + }); } /** @@ -116,11 +107,8 @@ protected function registerRequestRebindHandler() protected function registerEventRebindHandler() { $this->app->rebinding('events', function ($app, $dispatcher) { - if (! $app->resolved('auth')) { - return; - } - - if ($app['auth']->hasResolvedGuards() === false) { + if (! $app->resolved('auth') || + $app['auth']->hasResolvedGuards() === false) { return; } diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index e5ec7346e813..833a19948b8a 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -334,6 +334,41 @@ public function extend($driver, Closure $callback) return $this; } + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + */ + public function getApplication() + { + return $this->app; + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return $this + */ + public function setApplication($app) + { + $this->app = $app; + + return $this; + } + + /** + * Forget all of the resolved driver instances. + * + * @return $this + */ + public function forgetDrivers() + { + $this->drivers = []; + + return $this; + } + /** * Dynamically call the default driver instance. * diff --git a/src/Illuminate/Cookie/CookieJar.php b/src/Illuminate/Cookie/CookieJar.php index fe0cb9ad7f18..df938b24b3d1 100755 --- a/src/Illuminate/Cookie/CookieJar.php +++ b/src/Illuminate/Cookie/CookieJar.php @@ -214,4 +214,16 @@ public function getQueuedCookies() { return Arr::flatten($this->queued); } + + /** + * Flush the cookies which have been queued for the next request. + * + * @return $this + */ + public function flushQueuedCookies() + { + $this->queued = []; + + return $this; + } } diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index ea64ce94255c..368bb5fa0471 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -445,4 +445,17 @@ public function getApplication() { return $this->app; } + + /** + * Set the Laravel application instance. + * + * @param \Illuminate\Contracts\Foundation\Application + * @return $this + */ + public function setApplication(Application $app) + { + $this->app = $app; + + return $this; + } } diff --git a/src/Illuminate/Mail/MailManager.php b/src/Illuminate/Mail/MailManager.php index 8786414d8bdf..7437e699c5e0 100644 --- a/src/Illuminate/Mail/MailManager.php +++ b/src/Illuminate/Mail/MailManager.php @@ -472,6 +472,41 @@ public function extend($driver, Closure $callback) return $this; } + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + */ + public function getApplication() + { + return $this->app; + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return $this + */ + public function setApplication($app) + { + $this->app = $app; + + return $this; + } + + /** + * Forget all of the resolved mailer instances. + * + * @return $this + */ + public function forgetMailers() + { + $this->mailers = []; + + return $this; + } + /** * Dynamically call the default driver instance. * diff --git a/src/Illuminate/Pagination/PaginationServiceProvider.php b/src/Illuminate/Pagination/PaginationServiceProvider.php index 6510f2f261fd..e94cebd6caf7 100755 --- a/src/Illuminate/Pagination/PaginationServiceProvider.php +++ b/src/Illuminate/Pagination/PaginationServiceProvider.php @@ -29,26 +29,6 @@ public function boot() */ public function register() { - Paginator::viewFactoryResolver(function () { - return $this->app['view']; - }); - - Paginator::currentPathResolver(function () { - return $this->app['request']->url(); - }); - - Paginator::currentPageResolver(function ($pageName = 'page') { - $page = $this->app['request']->input($pageName); - - if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { - return (int) $page; - } - - return 1; - }); - - Paginator::queryStringResolver(function () { - return $this->app['request']->query(); - }); + PaginationState::resolveUsing($this->app); } } diff --git a/src/Illuminate/Pagination/PaginationState.php b/src/Illuminate/Pagination/PaginationState.php new file mode 100644 index 000000000000..f71ea13bde94 --- /dev/null +++ b/src/Illuminate/Pagination/PaginationState.php @@ -0,0 +1,37 @@ +url(); + }); + + Paginator::currentPageResolver(function ($pageName = 'page') use ($app) { + $page = $app['request']->input($pageName); + + if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { + return (int) $page; + } + + return 1; + }); + + Paginator::queryStringResolver(function () use ($app) { + return $app['request']->query(); + }); + } +} diff --git a/src/Illuminate/Pipeline/Hub.php b/src/Illuminate/Pipeline/Hub.php index 87331a57b2c6..91e9b3f306b8 100644 --- a/src/Illuminate/Pipeline/Hub.php +++ b/src/Illuminate/Pipeline/Hub.php @@ -71,4 +71,27 @@ public function pipe($object, $pipeline = null) $this->pipelines[$pipeline], new Pipeline($this->container), $object ); } + + /** + * Get the container instance used by the hub. + * + * @return \Illuminate\Contracts\Container\Container + */ + public function getContainer() + { + return $this->container; + } + + /** + * Set the container instance used by the hub. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return $this + */ + public function setContainer(Container $container) + { + $this->container = $container; + + return $this; + } } diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 08a390622602..52bd32e924e8 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -369,6 +369,16 @@ public function setConnectionName($name) return $this; } + /** + * Get the container instance being used by the connection. + * + * @return \Illuminate\Container\Container + */ + public function getContainer() + { + return $this->container; + } + /** * Set the IoC container instance. * diff --git a/src/Illuminate/Queue/QueueManager.php b/src/Illuminate/Queue/QueueManager.php index d19a16a750ae..624836637c02 100755 --- a/src/Illuminate/Queue/QueueManager.php +++ b/src/Illuminate/Queue/QueueManager.php @@ -246,6 +246,33 @@ public function getName($connection = null) return $connection ?: $this->getDefaultDriver(); } + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + */ + public function getApplication() + { + return $this->app; + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return $this + */ + public function setApplication($app) + { + $this->app = $app; + + foreach ($this->connections as $connection) { + $connection->setContainer($app); + } + + return $this; + } + /** * Dynamically pass calls to the default connection. * diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index dfdb7ae7332e..1aa62f0c64a5 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -646,6 +646,8 @@ protected function findRoute($request) { $this->current = $route = $this->routes->match($request); + $route->setContainer($this->container); + $this->container->instance(Route::class, $route); return $route; @@ -1291,6 +1293,19 @@ public static function uniqueMiddleware(array $middleware) return $result; } + /** + * Set the container instance used by the router. + * + * @param \Illuminate\Container\Container $container + * @return $this + */ + public function setContainer(Container $container) + { + $this->container = $container; + + return $this; + } + /** * Dynamically handle calls into the router instance. * diff --git a/src/Illuminate/Support/Manager.php b/src/Illuminate/Support/Manager.php index 0150cc3c9637..e5f832d79428 100755 --- a/src/Illuminate/Support/Manager.php +++ b/src/Illuminate/Support/Manager.php @@ -144,6 +144,39 @@ public function getDrivers() return $this->drivers; } + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + */ + public function getContainer() + { + return $this->container; + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return $this + */ + public function setContainer(Container $container) + { + $this->container = $container; + + return $this; + } + + /** + * Forget all of the resolved driver instances. + * + * @return $this + */ + public function forgetDrivers() + { + $this->drivers = []; + } + /** * Dynamically call the default driver instance. * diff --git a/src/Illuminate/Validation/Factory.php b/src/Illuminate/Validation/Factory.php index cd2ff7066450..e9f75d738803 100755 --- a/src/Illuminate/Validation/Factory.php +++ b/src/Illuminate/Validation/Factory.php @@ -280,4 +280,27 @@ public function setPresenceVerifier(PresenceVerifierInterface $presenceVerifier) { $this->verifier = $presenceVerifier; } + + /** + * Get the container instance used by the validation factory. + * + * @return \Illuminate\Contracts\Container\Container + */ + public function getContainer() + { + return $this->container; + } + + /** + * Set the container instance used by the validation factory. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return $this + */ + public function setContainer(Container $container) + { + $this->container = $container; + + return $this; + } } From 545875f22257c2d448cbe3f65eead78221895475 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 26 Mar 2021 19:49:31 +0000 Subject: [PATCH 435/443] Ensure the compiled view directory exists --- src/Illuminate/View/Compilers/BladeCompiler.php | 8 +++++--- src/Illuminate/View/Compilers/Compiler.php | 13 +++++++++++++ tests/View/ViewBladeCompilerTest.php | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 5a530184e20e..391624720a9d 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -153,9 +153,11 @@ public function compile($path = null) $contents = $this->appendFilePath($contents); } - $this->files->put( - $this->getCompiledPath($this->getPath()), $contents - ); + $compiledPath = $this->getCompiledPath($this->getPath()); + + $this->ensureCompiledDirectoryExists($compiledPath); + + $this->files->put($compiledPath, $contents); } } diff --git a/src/Illuminate/View/Compilers/Compiler.php b/src/Illuminate/View/Compilers/Compiler.php index 08648ad17b87..8895693568e6 100755 --- a/src/Illuminate/View/Compilers/Compiler.php +++ b/src/Illuminate/View/Compilers/Compiler.php @@ -71,4 +71,17 @@ public function isExpired($path) return $this->files->lastModified($path) >= $this->files->lastModified($compiled); } + + /** + * Create the file compiled directory if necessary. + * + * @param string $path + * @return void + */ + protected function ensureCompiledDirectoryExists($path) + { + if (! $this->files->exists(dirname($path))) { + $this->files->makeDirectory(dirname($path), 0777, true, true); + } + } } diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index d74405747c02..fc959e184bcf 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -49,6 +49,17 @@ 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('put')->once()->with(__DIR__.'/'.sha1('foo').'.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(false); + $files->shouldReceive('makeDirectory')->once()->with(__DIR__, 0777, true, true); $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); } @@ -57,6 +68,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('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); $this->assertSame('foo', $compiler->getPath()); @@ -73,6 +85,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('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); // set path before compilation $compiler->setPath('foo'); @@ -103,6 +116,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('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', $compiled); $compiler->compile('foo'); @@ -157,6 +171,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('put')->once()->with(__DIR__.'/'.sha1('').'.php', 'Hello World'); $compiler->setPath(''); $compiler->compile(); @@ -166,6 +181,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('put')->once()->with(__DIR__.'/'.sha1(null).'.php', 'Hello World'); $compiler->setPath(null); $compiler->compile(); From a274fc7fec03bd0ce7bdec826e2688e44fc081e2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 29 Mar 2021 07:54:36 -0500 Subject: [PATCH 436/443] formatting --- src/Illuminate/View/Compilers/BladeCompiler.php | 6 +++--- src/Illuminate/View/Compilers/Compiler.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 391624720a9d..14f8aefb4f49 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -153,9 +153,9 @@ public function compile($path = null) $contents = $this->appendFilePath($contents); } - $compiledPath = $this->getCompiledPath($this->getPath()); - - $this->ensureCompiledDirectoryExists($compiledPath); + $this->ensureCompiledDirectoryExists( + $compiledPath = $this->getCompiledPath($this->getPath()) + ); $this->files->put($compiledPath, $contents); } diff --git a/src/Illuminate/View/Compilers/Compiler.php b/src/Illuminate/View/Compilers/Compiler.php index 8895693568e6..2a943e0f6309 100755 --- a/src/Illuminate/View/Compilers/Compiler.php +++ b/src/Illuminate/View/Compilers/Compiler.php @@ -73,7 +73,7 @@ public function isExpired($path) } /** - * Create the file compiled directory if necessary. + * Create the compiled file directory if necessary. * * @param string $path * @return void From 2a73861c28202838d1f8b0c080d7b7dfb8dc90d9 Mon Sep 17 00:00:00 2001 From: Simon Bennett Date: Tue, 30 Mar 2021 14:39:44 +0100 Subject: [PATCH 437/443] [8.x] Explicitly set unit of sleep of retry function (#36810) * Explicitly set unit of sleep or retry functon * Update helpers.php Co-authored-by: Taylor Otwell --- src/Illuminate/Support/helpers.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 660c34af55a2..85486f6bbc55 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -216,13 +216,13 @@ function preg_replace_array($pattern, array $replacements, $subject) * * @param int $times * @param callable $callback - * @param int $sleep + * @param int $sleepMilliseconds * @param callable|null $when * @return mixed * * @throws \Exception */ - function retry($times, callable $callback, $sleep = 0, $when = null) + function retry($times, callable $callback, $sleepMilliseconds = 0, $when = null) { $attempts = 0; @@ -237,8 +237,8 @@ function retry($times, callable $callback, $sleep = 0, $when = null) throw $e; } - if ($sleep) { - usleep($sleep * 1000); + if ($sleepMilliseconds) { + usleep($sleepMilliseconds * 1000); } goto beginning; From 36c1f18d0c2e65de0b206c02e308aa35de8a0f63 Mon Sep 17 00:00:00 2001 From: Lairg Date: Tue, 30 Mar 2021 15:46:30 +0200 Subject: [PATCH 438/443] Added months() to Wormhole (#36808) --- src/Illuminate/Foundation/Testing/Wormhole.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/Wormhole.php b/src/Illuminate/Foundation/Testing/Wormhole.php index d660fe026a75..6258f6de2e11 100644 --- a/src/Illuminate/Foundation/Testing/Wormhole.php +++ b/src/Illuminate/Foundation/Testing/Wormhole.php @@ -102,6 +102,19 @@ public function weeks($callback = null) return $this->handleCallback($callback); } + /** + * Travel forward the given number of months. + * + * @param callable|null $callback + * @return mixed + */ + public function months($callback = null) + { + Carbon::setTestNow(Carbon::now()->addMonths($this->value)); + + return $this->handleCallback($callback); + } + /** * Travel forward the given number of years. * From 7c4b97f0ed0eb805be89028679c048ff59f56df2 Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Tue, 30 Mar 2021 09:48:41 -0400 Subject: [PATCH 439/443] Fix doesntExpectOutput() always causing a failed test (#36806) On what should be a passing test when the doesntExpectOutput() arg hasn't been output, PHPUnit's tearDown() call to Mockery::close() will throw any exception. Mockery\Exception\InvalidCountException: Method doWrite($output, ) from Mockery_0_Symfony_Component_Console_Output_BufferedOutput should be called exactly 1 times but called 0 times. During a successful test run, it _should_ be called 0 times. Remove once() to allow the `andReturnUsing()` callback to be invoked one or many times. And add integration test coverage to PendingCommand. --- src/Illuminate/Testing/PendingCommand.php | 1 - .../Testing/ArtisanCommandTest.php | 132 ++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Testing/ArtisanCommandTest.php diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index e0f4417f607a..7b90444bddd2 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -329,7 +329,6 @@ private function createABufferedOutputMock() foreach ($this->test->unexpectedOutput as $output => $displayed) { $mock->shouldReceive('doWrite') - ->once() ->ordered() ->with($output, Mockery::any()) ->andReturnUsing(function () use ($output) { diff --git a/tests/Integration/Testing/ArtisanCommandTest.php b/tests/Integration/Testing/ArtisanCommandTest.php new file mode 100644 index 000000000000..82e827732597 --- /dev/null +++ b/tests/Integration/Testing/ArtisanCommandTest.php @@ -0,0 +1,132 @@ +ask('What is your name?'); + + $language = $this->choice('Which language do you prefer?', [ + 'PHP', + 'Ruby', + 'Python', + ]); + + $this->line("Your name is $name and you prefer $language."); + }); + + Artisan::command('slim', function () { + $this->line($this->ask('Who?')); + $this->line($this->ask('What?')); + $this->line($this->ask('Huh?')); + }); + } + + public function test_console_command_that_passes() + { + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'PHP') + ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.') + ->doesntExpectOutput('Your name is Taylor Otwell and you prefer Ruby.') + ->assertExitCode(0); + } + + public function test_console_command_that_passes_with_repeating_output() + { + $this->artisan('slim') + ->expectsQuestion('Who?', 'Taylor') + ->expectsQuestion('What?', 'Taylor') + ->expectsQuestion('Huh?', 'Taylor') + ->expectsOutput('Taylor') + ->doesntExpectOutput('Otwell') + ->expectsOutput('Taylor') + ->expectsOutput('Taylor') + ->assertExitCode(0); + } + + public function test_console_command_that_fails_from_unexpected_output() + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Output "Your name is Taylor Otwell and you prefer PHP." was printed.'); + + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'PHP') + ->doesntExpectOutput('Your name is Taylor Otwell and you prefer PHP.') + ->assertExitCode(0); + } + + public function test_console_command_that_fails_from_missing_output() + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Output "Your name is Taylor Otwell and you prefer PHP." was not printed.'); + + $this->ignoringMockOnceExceptions(function () { + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'Ruby') + ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.') + ->assertExitCode(0); + }); + } + + public function test_console_command_that_fails_from_exit_code_mismatch() + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Expected status code 1 but received 0.'); + + $this->artisan('survey') + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsQuestion('Which language do you prefer?', 'PHP') + ->assertExitCode(1); + } + + public function test_console_command_that_fails_from_unordered_output() + { + $this->expectException(InvalidOrderException::class); + + $this->ignoringMockOnceExceptions(function () { + $this->artisan('slim') + ->expectsQuestion('Who?', 'Taylor') + ->expectsQuestion('What?', 'Danger') + ->expectsQuestion('Huh?', 'Otwell') + ->expectsOutput('Taylor') + ->expectsOutput('Otwell') + ->expectsOutput('Danger') + ->assertExitCode(0); + }); + } + + /** + * Don't allow Mockery's InvalidCountException to be reported. Mocks setup + * in PendingCommand cause PHPUnit tearDown() to later throw the exception. + * + * @param callable $callback + * @return void + */ + protected function ignoringMockOnceExceptions(callable $callback) + { + try { + $callback(); + } finally { + try { + Mockery::close(); + } catch (InvalidCountException $e) { + // Ignore mock exception from PendingCommand::expectsOutput(). + } + } + } +} From 89d7683ddc3b7bf630391e267873f3b6e7710c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sel=C3=A7uk=20=C3=87ukur?= <5716652+selcukcukur@users.noreply.github.com> Date: Tue, 30 Mar 2021 16:58:56 +0300 Subject: [PATCH 440/443] #36536 issue fix (#36801) The use of whereHasMorph in a whereHas callback generates a wrong sql statements. Correction of this incorrectly constructed statement has been applied. --- .../Database/Eloquent/Concerns/QueriesRelationships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 4fbc2f90ebd1..7456fc6e4a6f 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -223,7 +223,7 @@ public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boole }; } - $query->where($this->query->from.'.'.$relation->getMorphType(), '=', (new $type)->getMorphClass()) + $query->where($this->qualifyColumn($relation->getMorphType()), '=', (new $type)->getMorphClass()) ->whereHas($belongsTo, $callback, $operator, $count); }); } From 35e339bffda785ae0cee11c66a17644a9fa096d1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 30 Mar 2021 09:08:57 -0500 Subject: [PATCH 441/443] patch --- 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 4e4d6c1840d3..a4f66d94d1f6 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.20'; + const VERSION = '6.20.21'; /** * The base path for the Laravel installation. From 8e1f620febb4d500f79f71be5b99697f2ae79a05 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 30 Mar 2021 23:33:10 +0200 Subject: [PATCH 442/443] Fix setting DynamoDB credentials (#36822) --- src/Illuminate/Cache/CacheServiceProvider.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Cache/CacheServiceProvider.php b/src/Illuminate/Cache/CacheServiceProvider.php index 90d1d019f4be..b8208eb4f549 100755 --- a/src/Illuminate/Cache/CacheServiceProvider.php +++ b/src/Illuminate/Cache/CacheServiceProvider.php @@ -36,14 +36,19 @@ public function register() $this->app->singleton('cache.dynamodb.client', function ($app) { $config = $app['config']->get('cache.stores.dynamodb'); - return new DynamoDbClient([ + $dynamoConfig = [ 'region' => $config['region'], 'version' => 'latest', 'endpoint' => $config['endpoint'] ?? null, - 'credentials' => Arr::only( + ]; + + if ($config['key'] && $config['secret']) { + $dynamoConfig['credentials'] = Arr::only( $config, ['key', 'secret', 'token'] - ), - ]); + ); + } + + return new DynamoDbClient($dynamoConfig); }); } From f4d2beff6f1793909e1db4f2204800183b4f1719 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 30 Mar 2021 16:33:47 -0500 Subject: [PATCH 443/443] version --- 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 a4f66d94d1f6..34bbb83f924a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -31,7 +31,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '6.20.21'; + const VERSION = '6.20.22'; /** * The base path for the Laravel installation.