From ab0aead7c2c9633effe0dba5229565a159ba4af4 Mon Sep 17 00:00:00 2001 From: Quynh Xuan Nguyen Date: Mon, 2 Nov 2020 10:46:23 +0700 Subject: [PATCH 001/599] Fix PendingRequest docblock --- src/Illuminate/Http/Client/PendingRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 08587e1e1fd9..304151cacae0 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -87,7 +87,7 @@ class PendingRequest /** * The callbacks that should execute before the request is sent. * - * @var array + * @var \Illuminate\Support\Collection */ protected $beforeSendingCallbacks; From 93f6d565a07045baa0e4b941ae1f733cd5984d65 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 3 Nov 2020 08:12:58 -0600 Subject: [PATCH 002/599] 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 ded34a078d06..7633b00d5b12 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.29.2'; + const VERSION = '7.29.3'; /** * The base path for the Laravel installation. From 9643cb43e2d3dc36444778fa66817d80f810c097 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 4 Nov 2020 20:59:09 +0200 Subject: [PATCH 003/599] [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 2e01e8407b79..587179aad013 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,8 +1,21 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.28.4...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.29.0...7.x) +## [v7.29.0 (2020-10-29)](https://github.com/laravel/framework/compare/v7.28.4...v7.29.0) + +### Added +- Full PHP 8.0 Support ([#34884](https://github.com/laravel/framework/pull/34884), [28bb76e](https://github.com/laravel/framework/commit/28bb76efbcfc5fee57307ffa062b67ff709240dc), [#33388](https://github.com/laravel/framework/pull/33388)) +- Added `Illuminate\Support\Reflector::isCallable()` ([#34994](https://github.com/laravel/framework/pull/34994), [8c16891](https://github.com/laravel/framework/commit/8c16891c6e7a4738d63788f4447614056ab5136e), [31917ab](https://github.com/laravel/framework/commit/31917abcfa0db6ec6221bb07fc91b6e768ff5ec8), [11cfa4d](https://github.com/laravel/framework/commit/11cfa4d4c92bf2f023544d58d51b35c5d31dece0), [#34999](https://github.com/laravel/framework/pull/34999)) + +### Changed +- Bump minimum PHP version to v7.2.5 ([#34928](https://github.com/laravel/framework/pull/34928)) + +### Fixed +- Fixed ambigious column on many to many with select load ([5007986](https://github.com/laravel/framework/commit/500798623d100a9746b2931ae6191cb756521f05)) + + ## [v7.28.4 (2020-10-06)](https://github.com/laravel/framework/compare/v7.28.3...v7.28.4) ### Fixed From 19a261ad4f4648d5000c83c4406059c0f597ebc7 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 4 Nov 2020 21:02:21 +0200 Subject: [PATCH 004/599] [7.x] update changelog --- CHANGELOG-7.x.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index 587179aad013..2f5b85ea2816 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,13 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.29.0...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.29.1...7.x) + + +## [v7.29.1 (2020-10-29)](https://github.com/laravel/framework/compare/v7.29.0...v7.29.1) + +### Fixed +- Fixed alias usage in `Eloquent` ([6091048](https://github.com/laravel/framework/commit/609104806b8b639710268c75c22f43034c2b72db)) +- Fixed `Illuminate\Support\Reflector::isCallable()` ([a90f344](https://github.com/laravel/framework/commit/a90f344c66f0a5bb1d718f8bbd20c257d4de9e02)) ## [v7.29.0 (2020-10-29)](https://github.com/laravel/framework/compare/v7.28.4...v7.29.0) From 282e1dec8600197c4b6c0983cebfeb298b8d59c9 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 4 Nov 2020 21:04:43 +0200 Subject: [PATCH 005/599] [7.x] update changelog --- CHANGELOG-7.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index 2f5b85ea2816..7df9aa3980cb 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,12 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.29.1...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.29.2...7.x) + + +## [v7.29.2 (2020-10-29)](https://github.com/laravel/framework/compare/v7.29.1...v7.29.2) + +### Fixed +- [Add some fixes](https://github.com/laravel/framework/compare/v7.29.1...v7.29.2) ## [v7.29.1 (2020-10-29)](https://github.com/laravel/framework/compare/v7.29.0...v7.29.1) From bced05ea1f9548b0745f20dd6ee72a7fbb8858f6 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Thu, 5 Nov 2020 20:25:58 +0200 Subject: [PATCH 006/599] [7.x] update changelog --- CHANGELOG-7.x.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-7.x.md b/CHANGELOG-7.x.md index 7df9aa3980cb..8f668e3793ae 100644 --- a/CHANGELOG-7.x.md +++ b/CHANGELOG-7.x.md @@ -1,6 +1,12 @@ # Release Notes for 7.x -## [Unreleased](https://github.com/laravel/framework/compare/v7.29.2...7.x) +## [Unreleased](https://github.com/laravel/framework/compare/v7.29.3...7.x) + + +## [v7.29.3 (2020-11-03)](https://github.com/laravel/framework/compare/v7.29.2...v7.29.3) + +### Fixed +- Added php 8 support for Illuminate Testing 7.x ([#35045](https://github.com/laravel/framework/pull/35045)) ## [v7.29.2 (2020-10-29)](https://github.com/laravel/framework/compare/v7.29.1...v7.29.2) From 4e52a606e91619f6082ed8d46f8d64f9d4dbd0b2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 10:34:38 -0600 Subject: [PATCH 007/599] add convenient progress bar method --- .../Console/Concerns/InteractsWithIO.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Illuminate/Console/Concerns/InteractsWithIO.php b/src/Illuminate/Console/Concerns/InteractsWithIO.php index 045d9abf5dcb..1a0bdfa432de 100644 --- a/src/Illuminate/Console/Concerns/InteractsWithIO.php +++ b/src/Illuminate/Console/Concerns/InteractsWithIO.php @@ -2,6 +2,7 @@ namespace Illuminate\Console\Concerns; +use Closure; use Illuminate\Console\OutputStyle; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Str; @@ -237,6 +238,38 @@ public function table($headers, $rows, $tableStyle = 'default', array $columnSty $table->render(); } + /** + * Execute a given callback while advancing a progress bar. + * + * @param iterable|int $totalSteps + * @param \Closure $callback + * @return mixed|void + */ + public function withProgressBar($totalSteps = 0, Closure $callback) + { + $bar = $this->output->createProgressBar( + is_iterable($totalSteps) ? count($totalSteps) : $totalSteps + ); + + $bar->start(); + + if (is_iterable($totalSteps)) { + foreach ($totalSteps as $value) { + $callback($value, $bar); + + $bar->advance(); + } + } else { + $callback($bar); + } + + $bar->finish(); + + if (is_iterable($totalSteps)) { + return $totalSteps; + } + } + /** * Write a string as information output. * From 7f3101bf6e8a0f048a243a55be7fc79eb359b609 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 12:46:23 -0600 Subject: [PATCH 008/599] add alias for call silent --- src/Illuminate/Console/Concerns/CallsCommands.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Concerns/CallsCommands.php b/src/Illuminate/Console/Concerns/CallsCommands.php index e060c5562606..11a69060c742 100644 --- a/src/Illuminate/Console/Concerns/CallsCommands.php +++ b/src/Illuminate/Console/Concerns/CallsCommands.php @@ -29,7 +29,7 @@ public function call($command, array $arguments = []) } /** - * Call another console command silently. + * Call another console command without output. * * @param \Symfony\Component\Console\Command\Command|string $command * @param array $arguments @@ -40,6 +40,18 @@ public function callSilent($command, array $arguments = []) return $this->runCommand($command, $arguments, new NullOutput); } + /** + * Call another console command without output. + * + * @param \Symfony\Component\Console\Command\Command|string $command + * @param array $arguments + * @return int + */ + public function callWithoutOutput($command, array $arguments = []) + { + return $this->callSilent($command, $arguments); + } + /** * Run the given the console command. * From 029443349294e3b6e7bebfe9c23a51a9821ec497 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 12:47:08 -0600 Subject: [PATCH 009/599] rename method --- src/Illuminate/Console/Concerns/CallsCommands.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Concerns/CallsCommands.php b/src/Illuminate/Console/Concerns/CallsCommands.php index 11a69060c742..7e69b9b7891d 100644 --- a/src/Illuminate/Console/Concerns/CallsCommands.php +++ b/src/Illuminate/Console/Concerns/CallsCommands.php @@ -47,7 +47,7 @@ public function callSilent($command, array $arguments = []) * @param array $arguments * @return int */ - public function callWithoutOutput($command, array $arguments = []) + public function callSilently($command, array $arguments = []) { return $this->callSilent($command, $arguments); } From 72306bebce1a5c41f324b86045ed6dc87a5f3129 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Wed, 18 Nov 2020 00:52:02 +0530 Subject: [PATCH 010/599] [8.x] Add option to release unique job locks before processing --- src/Illuminate/Queue/CallQueuedHandler.php | 4 ++++ tests/Integration/Queue/UniqueJobTest.php | 26 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index 8647e39bc758..61126c775834 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -59,6 +59,10 @@ public function call(Job $job, array $data) return $this->handleModelNotFound($job, $e); } + if ($command->uniqueUntilStart ?? false) { + $this->ensureUniqueJobLockIsReleased($command); + } + $this->dispatchThroughMiddleware($job, $command); if (! $job->isReleased()) { diff --git a/tests/Integration/Queue/UniqueJobTest.php b/tests/Integration/Queue/UniqueJobTest.php index a6f2c1a5143b..374d2f7efce8 100644 --- a/tests/Integration/Queue/UniqueJobTest.php +++ b/tests/Integration/Queue/UniqueJobTest.php @@ -143,6 +143,23 @@ public function testLockIsNotReleasedForJobReleases() $this->assertTrue($this->app->get(Cache::class)->lock($this->getLockKey($job), 10)->get()); } + public function testLockCanBeReleasedBeforeProcessing() + { + UniqueUntilStartTestJob::$handled = false; + + dispatch($job = new UniqueUntilStartTestJob); + + $this->assertFalse($this->app->get(Cache::class)->lock($this->getLockKey($job), 10)->get()); + + $this->artisan('queue:work', [ + 'connection' => 'database', + '--once' => true, + ]); + + $this->assertTrue($job::$handled); + $this->assertTrue($this->app->get(Cache::class)->lock($this->getLockKey($job), 10)->get()); + } + protected function getLockKey($job) { return 'laravel_unique_job:'.(is_string($job) ? $job : get_class($job)); @@ -197,3 +214,12 @@ class UniqueTestRetryJob extends UniqueTestFailJob public $connection = 'database'; } + +class UniqueUntilStartTestJob extends UniqueTestJob +{ + public $tries = 2; + + public $connection = 'database'; + + public $uniqueUntilStart = true; +} From acb4b77adc6e257e132e3b036abe1ec88885cfb7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 13:39:50 -0600 Subject: [PATCH 011/599] Disable CSRF on broadcast route This route does not particularly warrant or require CSRF protection and doing so increases the complication of setting up Laravel Echo in SPA environments. --- src/Illuminate/Broadcasting/BroadcastManager.php | 2 +- .../Broadcasting/Broadcasters/Broadcaster.php | 2 +- .../Broadcasting/Broadcasters/PusherBroadcaster.php | 5 +++-- .../Broadcasting/Broadcasters/RedisBroadcaster.php | 5 +++-- src/Illuminate/Routing/Router.php | 13 ++++++++++++- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index e3bdb03aaca1..22917d8bc795 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -70,7 +70,7 @@ public function routes(array $attributes = null) $router->match( ['get', 'post'], '/broadcasting/auth', '\\'.BroadcastController::class.'@authenticate' - ); + )->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]); }); } diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index d39258ff5b51..e48b15195741 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -317,7 +317,7 @@ protected function retrieveChannelOptions($channel) } /** - * Check if channel name from request match a pattern from registered channels. + * Check if the channel name from the request matches a pattern from registered channels. * * @param string $channel * @param string $pattern diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 68daf9da4b26..94c95c4501ac 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -42,8 +42,9 @@ public function auth($request) { $channelName = $this->normalizeChannelName($request->channel_name); - if ($this->isGuardedChannel($request->channel_name) && - ! $this->retrieveUser($request, $channelName)) { + if (empty($request->channel_name) || + ($this->isGuardedChannel($request->channel_name) && + ! $this->retrieveUser($request, $channelName))) { throw new AccessDeniedHttpException; } diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index 18cb0fef3cdb..2fea183fb6a0 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -60,8 +60,9 @@ public function auth($request) str_replace($this->prefix, '', $request->channel_name) ); - if ($this->isGuardedChannel($request->channel_name) && - ! $this->retrieveUser($request, $channelName)) { + if (empty($request->channel_name) || + ($this->isGuardedChannel($request->channel_name) && + ! $this->retrieveUser($request, $channelName))) { throw new AccessDeniedHttpException; } diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c4e4c9fc588e..1828e52105fd 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -21,6 +21,7 @@ use Illuminate\Support\Traits\Macroable; use JsonSerializable; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; +use ReflectionClass; use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; @@ -708,7 +709,17 @@ public function gatherRouteMiddleware(Route $route) $middleware = collect($route->gatherMiddleware())->map(function ($name) { return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups); })->flatten()->reject(function ($name) use ($excluded) { - return in_array($name, $excluded, true); + if (empty($excluded)) { + return false; + } elseif (in_array($name, $excluded, true)) { + return true; + } + + $reflection = new ReflectionClass($name); + + return collect($excluded)->contains(function ($exclude) use ($reflection) { + return $reflection->isSubclassOf($exclude); + }); })->values(); return $this->sortMiddleware($middleware); From e0f3f8e8241e1ea34a3a3b8c543871cdc00290bf Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 15:13:05 -0600 Subject: [PATCH 012/599] add ably broadcaster --- .../Broadcasting/BroadcastManager.php | 13 ++ .../Broadcasters/AblyBroadcaster.php | 200 ++++++++++++++++++ tests/Broadcasting/AblyBroadcasterTest.php | 149 +++++++++++++ 3 files changed, 362 insertions(+) create mode 100644 src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php create mode 100644 tests/Broadcasting/AblyBroadcasterTest.php diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 22917d8bc795..59ba97c54be8 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -2,7 +2,9 @@ namespace Illuminate\Broadcasting; +use Ably\AblyRest; use Closure; +use Illuminate\Broadcasting\Broadcasters\AblyBroadcaster; use Illuminate\Broadcasting\Broadcasters\LogBroadcaster; use Illuminate\Broadcasting\Broadcasters\NullBroadcaster; use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster; @@ -220,6 +222,17 @@ protected function createPusherDriver(array $config) return new PusherBroadcaster($pusher); } + /** + * Create an instance of the driver. + * + * @param array $config + * @return \Illuminate\Contracts\Broadcasting\Broadcaster + */ + protected function createAblyDriver(array $config) + { + return new AblyBroadcaster(new AblyRest($config['key'])); + } + /** * Create an instance of the driver. * diff --git a/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php new file mode 100644 index 000000000000..7857c26dce3f --- /dev/null +++ b/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php @@ -0,0 +1,200 @@ +ably = $ably; + } + + /** + * Authenticate the incoming request for a given channel. + * + * @param \Illuminate\Http\Request $request + * @return mixed + * + * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function auth($request) + { + $channelName = $this->normalizeChannelName($request->channel_name); + + if (empty($request->channel_name) || + ($this->isGuardedChannel($request->channel_name) && + ! $this->retrieveUser($request, $channelName))) { + throw new AccessDeniedHttpException; + } + + return parent::verifyUserCanAccessChannel( + $request, $channelName + ); + } + + /** + * Return the valid authentication response. + * + * @param \Illuminate\Http\Request $request + * @param mixed $result + * @return mixed + */ + public function validAuthenticationResponse($request, $result) + { + if (Str::startsWith($request->channel_name, 'private')) { + $signature = $this->generateAblySignature( + $request->channel_name, $request->socket_id + ); + + return ['auth' => $this->getPublicToken().':'.$signature]; + } + + $channelName = $this->normalizeChannelName($request->channel_name); + + $signature = $this->generateAblySignature( + $request->channel_name, + $request->socket_id, + $userData = array_filter([ + 'user_id' => $this->retrieveUser($request, $channelName)->getAuthIdentifier(), + 'user_info' => $result, + ]) + ); + + return [ + 'auth' => $this->getPublicToken().':'.$signature, + 'channel_data' => json_encode($userData), + ]; + } + + /** + * Generate the signature needed for Ably authentication headers. + * + * @param string $channelName + * @param string $socketId + * @param array|null $userData + * @return string + */ + public function generateAblySignature($channelName, $socketId, $userData = null) + { + return hash_hmac( + 'sha256', + sprintf('%s:%s%s', $socketId, $channelName, $userData ? ':'.json_encode($userData) : ''), + $this->getPrivateToken(), + ); + } + + /** + * Broadcast the given event. + * + * @param array $channels + * @param string $event + * @param array $payload + * @return void + */ + public function broadcast(array $channels, $event, array $payload = []) + { + foreach ($this->formatChannels($channels) as $channel) { + $this->ably->channels->get($channel)->publish($event, $payload); + } + } + + /** + * Return true if channel is protected by authentication. + * + * @param string $channel + * @return bool + */ + public function isGuardedChannel($channel) + { + return Str::startsWith($channel, ['private-', 'presence-']); + } + + /** + * Remove prefix from channel name. + * + * @param string $channel + * @return string + */ + public function normalizeChannelName($channel) + { + if ($this->isGuardedChannel($channel)) { + return Str::startsWith($channel, 'private-') + ? Str::replaceFirst('private-', '', $channel) + : Str::replaceFirst('presence-', '', $channel); + } + + return $channel; + } + + /** + * Format the channel array into an array of strings. + * + * @param array $channels + * @return array + */ + protected function formatChannels(array $channels) + { + return array_map(function ($channel) { + $channel = (string) $channel; + + if (Str::startsWith($channel, ['private-', 'presence-'])) { + return Str::startsWith($channel, 'private-') + ? Str::replaceFirst('private-', 'private:', $channel) + : Str::replaceFirst('presence-', 'presence:', $channel); + } + + return 'public:'.$channel; + }, $channels); + } + + /** + * Get the public token value from the Ably key. + * + * @return mixed + */ + protected function getPublicToken() + { + return Str::before($this->ably->options->key, ':'); + } + + /** + * Get the private token value from the Ably key. + * + * @return mixed + */ + protected function getPrivateToken() + { + return Str::after($this->ably->options->key, ':'); + } + + /** + * Get the underlying Ably SDK instance. + * + * @return \Ably\AblyRest + */ + public function getAbly() + { + return $this->ably; + } +} diff --git a/tests/Broadcasting/AblyBroadcasterTest.php b/tests/Broadcasting/AblyBroadcasterTest.php new file mode 100644 index 000000000000..81e172d1e2d4 --- /dev/null +++ b/tests/Broadcasting/AblyBroadcasterTest.php @@ -0,0 +1,149 @@ +ably = m::mock('Ably\AblyRest'); + $this->ably->options = (object) ['key' => 'abcd:efgh']; + + $this->broadcaster = m::mock(AblyBroadcaster::class, [$this->ably])->makePartial(); + } + + public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue() + { + $this->broadcaster->channel('test', function () { + return true; + }); + + $this->broadcaster->shouldReceive('validAuthenticationResponse') + ->once(); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('private-test') + ); + } + + public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenCallbackReturnFalse() + { + $this->expectException(AccessDeniedHttpException::class); + + $this->broadcaster->channel('test', function () { + return false; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('private-test') + ); + } + + public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenRequestUserNotFound() + { + $this->expectException(AccessDeniedHttpException::class); + + $this->broadcaster->channel('test', function () { + return true; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithoutUserForChannel('private-test') + ); + } + + public function testAuthCallValidAuthenticationResponseWithPresenceChannelWhenCallbackReturnAnArray() + { + $returnData = [1, 2, 3, 4]; + $this->broadcaster->channel('test', function () use ($returnData) { + return $returnData; + }); + + $this->broadcaster->shouldReceive('validAuthenticationResponse') + ->once(); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('presence-test') + ); + } + + public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenCallbackReturnNull() + { + $this->expectException(AccessDeniedHttpException::class); + + $this->broadcaster->channel('test', function () { + // + }); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('presence-test') + ); + } + + public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenRequestUserNotFound() + { + $this->expectException(AccessDeniedHttpException::class); + + $this->broadcaster->channel('test', function () { + return [1, 2, 3, 4]; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithoutUserForChannel('presence-test') + ); + } + + /** + * @param string $channel + * @return \Illuminate\Http\Request + */ + protected function getMockRequestWithUserForChannel($channel) + { + $request = m::mock(Request::class); + $request->channel_name = $channel; + $request->socket_id = 'abcd.1234'; + + $request->shouldReceive('input') + ->with('callback', false) + ->andReturn(false); + + $user = m::mock('User'); + $user->shouldReceive('getAuthIdentifier') + ->andReturn(42); + + $request->shouldReceive('user') + ->andReturn($user); + + return $request; + } + + /** + * @param string $channel + * @return \Illuminate\Http\Request + */ + protected function getMockRequestWithoutUserForChannel($channel) + { + $request = m::mock(Request::class); + $request->channel_name = $channel; + + $request->shouldReceive('user') + ->andReturn(null); + + return $request; + } +} From 5d58b0fddbe81e6e6589b294c48a71ce095183e3 Mon Sep 17 00:00:00 2001 From: imanghafoori Date: Tue, 17 Nov 2020 23:52:52 +0330 Subject: [PATCH 013/599] add table name as default morph type --- .../Eloquent/Concerns/HasRelationships.php | 4 ++++ .../Database/Eloquent/Relations/Relation.php | 17 +++++++++++++++++ tests/Database/DatabaseEloquentModelTest.php | 17 +++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 60022736b58d..049f3b294365 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -731,6 +731,10 @@ public function getMorphClass() return array_search(static::class, $morphMap, true); } + if (Relation::$tableNameAsMorphType) { + return $this->getTable(); + } + return static::class; } diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 6bdb6f7a7487..eee7f48ea757 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -55,6 +55,13 @@ abstract class Relation */ public static $morphMap = []; + /** + * Indicates if the morph relation type should default to table name. + * + * @var bool + */ + public static $tableNameAsMorphType = false; + /** * Create a new relation instance. * @@ -341,6 +348,16 @@ public static function morphMap(array $map = null, $merge = true) return static::$morphMap; } + /** + * Changes the default morph type to table name. + * + * @return void + */ + public static function tableNameAsMorphType() + { + self::$tableNameAsMorphType = true; + } + /** * Builds a table-keyed array from model class names. * diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 9884ed69f9a2..2d3f3e10ebdf 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1200,6 +1200,23 @@ public function testCorrectMorphClassIsReturned() } } + public function testCorrectMorphClassIsReturnedOnChangingDefault() + { + Relation::tableNameAsMorphType(); + Relation::morphMap(['alias' => EloquentModelCamelStub::class]); + Relation::morphMap(['alias2' => 'AnotherModel']); + $model = new EloquentModelStub; + $model2 = new EloquentModelCamelStub; + + try { + $this->assertEquals('stub', $model->getMorphClass()); + $this->assertEquals('alias', $model2->getMorphClass()); + } finally { + Relation::morphMap([], false); + Relation::$tableNameAsMorphType = false; + } + } + public function testHasManyCreatesProperRelation() { $model = new EloquentModelStub; From 6381aa994756429156b7376e98606458b052b1d7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 15:47:57 -0600 Subject: [PATCH 014/599] pass entire configuration --- src/Illuminate/Broadcasting/BroadcastManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 59ba97c54be8..e5ec7346e813 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -230,7 +230,7 @@ protected function createPusherDriver(array $config) */ protected function createAblyDriver(array $config) { - return new AblyBroadcaster(new AblyRest($config['key'])); + return new AblyBroadcaster(new AblyRest($config)); } /** From 169fd2b5156650a067aa77a38681875d2a6c5e57 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 20:55:13 -0600 Subject: [PATCH 015/599] remove optional value --- src/Illuminate/Console/Concerns/InteractsWithIO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Concerns/InteractsWithIO.php b/src/Illuminate/Console/Concerns/InteractsWithIO.php index 1a0bdfa432de..69d295c1efb1 100644 --- a/src/Illuminate/Console/Concerns/InteractsWithIO.php +++ b/src/Illuminate/Console/Concerns/InteractsWithIO.php @@ -245,7 +245,7 @@ public function table($headers, $rows, $tableStyle = 'default', array $columnSty * @param \Closure $callback * @return mixed|void */ - public function withProgressBar($totalSteps = 0, Closure $callback) + public function withProgressBar($totalSteps, Closure $callback) { $bar = $this->output->createProgressBar( is_iterable($totalSteps) ? count($totalSteps) : $totalSteps From 518e9aee12bf8d20dc7ee2f60150519e13266edb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 17 Nov 2020 21:06:43 -0600 Subject: [PATCH 016/599] formatting --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index eee7f48ea757..97ee55de772b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -349,7 +349,7 @@ public static function morphMap(array $map = null, $merge = true) } /** - * Changes the default morph type to table name. + * Specifies that the morph types should be table names. * * @return void */ From 2a6e9d32277f7083109f2ecceba7840de93760df Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Wed, 18 Nov 2020 12:37:15 +0530 Subject: [PATCH 017/599] Ensure unique job lock is released only once in lifecycle --- src/Illuminate/Queue/CallQueuedHandler.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index 61126c775834..1fae8564d575 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -29,6 +29,13 @@ class CallQueuedHandler */ protected $container; + /** + * Indicates if the unique job lock has been released. + * + * @var bool + */ + protected $uniqueLockReleased = false; + /** * Create a new handler instance. * @@ -171,7 +178,7 @@ protected function ensureSuccessfulBatchJobIsRecorded($command) */ protected function ensureUniqueJobLockIsReleased($command) { - if (! $command instanceof ShouldBeUnique) { + if (! ($command instanceof ShouldBeUnique) || $this->uniqueLockReleased) { return; } @@ -186,6 +193,8 @@ protected function ensureUniqueJobLockIsReleased($command) $cache->lock( 'laravel_unique_job:'.get_class($command).$uniqueId )->forceRelease(); + + $this->uniqueLockReleased = true; } /** From a7e785240bc6b9e44693c5587d6cb40539d67f3a Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 18 Nov 2020 14:47:40 +0100 Subject: [PATCH 018/599] Allow overriding the MySQL server version for database queuedriver (#35263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Christian Frøystad --- src/Illuminate/Queue/DatabaseQueue.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index c18de9cc16f3..89fb91cb3038 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -233,7 +233,7 @@ protected function getNextAvailableJob($queue) protected function getLockForPopping() { $databaseEngine = $this->database->getPdo()->getAttribute(PDO::ATTR_DRIVER_NAME); - $databaseVersion = $this->database->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); + $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', '>=')) { From 3f6bb3b6b660d6d42bfd34de3301aa4650bca5df Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 18 Nov 2020 07:48:18 -0600 Subject: [PATCH 019/599] easily set a null driver (#35262) if the passed `$name` is `null` or `'null'`, we'll build up a config with a null driver, so the user does not have to define it in the config file. --- src/Illuminate/Cache/CacheManager.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index f100d11efad6..352ea6f50cc0 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -314,7 +314,11 @@ protected function getPrefix(array $config) */ protected function getConfig($name) { - return $this->app['config']["cache.stores.{$name}"]; + if (! is_null($name) && $name !== 'null') { + return $this->app['config']["cache.stores.{$name}"]; + } + + return ['driver' => 'null']; } /** From c35d76eb3bb4e6f6c64a82b68ab8666a7a292a48 Mon Sep 17 00:00:00 2001 From: Marvin Quezon Date: Wed, 18 Nov 2020 21:51:32 +0800 Subject: [PATCH 020/599] [8.x] Adds an ability for the Wormhole class to take us back to the present. (#35261) * Adds an ability for the Wormhole to take us back to the present. * Fixes styling. --- .../Testing/Concerns/InteractsWithTime.php | 4 +-- .../Foundation/Testing/Wormhole.php | 12 +++++++++ tests/Foundation/Testing/WormholeTest.php | 25 +++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/Foundation/Testing/WormholeTest.php diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php index d6413a528062..184a2441ce86 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTime.php @@ -44,8 +44,6 @@ public function travelTo(DateTimeInterface $date, $callback = null) */ public function travelBack() { - Carbon::setTestNow(); - - return Carbon::now(); + return Wormhole::back(); } } diff --git a/src/Illuminate/Foundation/Testing/Wormhole.php b/src/Illuminate/Foundation/Testing/Wormhole.php index 59512981e6ad..d660fe026a75 100644 --- a/src/Illuminate/Foundation/Testing/Wormhole.php +++ b/src/Illuminate/Foundation/Testing/Wormhole.php @@ -115,6 +115,18 @@ public function years($callback = null) return $this->handleCallback($callback); } + /** + * Travel back to the current time. + * + * @return \DateTimeInterface + */ + public static function back() + { + Carbon::setTestNow(); + + return Carbon::now(); + } + /** * Handle the given optional execution callback. * diff --git a/tests/Foundation/Testing/WormholeTest.php b/tests/Foundation/Testing/WormholeTest.php new file mode 100644 index 000000000000..baf41f059132 --- /dev/null +++ b/tests/Foundation/Testing/WormholeTest.php @@ -0,0 +1,25 @@ +addDays(10); + + // Travel in time.. + (new Wormhole(10))->days(); + + // 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.. + $this->assertEquals($present->format('Y-m-d'), Wormhole::back()->format('Y-m-d')); + } +} From b53f13ef6c8625176defcb83d2fb8d4d5887d068 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 18 Nov 2020 07:57:08 -0600 Subject: [PATCH 021/599] add interface --- .../Contracts/Queue/ShouldBeUniqueUntilProcessing.php | 8 ++++++++ src/Illuminate/Queue/CallQueuedHandler.php | 5 +++-- tests/Integration/Queue/UniqueJobTest.php | 5 ++--- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src/Illuminate/Contracts/Queue/ShouldBeUniqueUntilProcessing.php diff --git a/src/Illuminate/Contracts/Queue/ShouldBeUniqueUntilProcessing.php b/src/Illuminate/Contracts/Queue/ShouldBeUniqueUntilProcessing.php new file mode 100644 index 000000000000..510cab96f43a --- /dev/null +++ b/src/Illuminate/Contracts/Queue/ShouldBeUniqueUntilProcessing.php @@ -0,0 +1,8 @@ +handleModelNotFound($job, $e); } - if ($command->uniqueUntilStart ?? false) { + if ($command instanceof ShouldBeUniqueUntilProcessing) { $this->ensureUniqueJobLockIsReleased($command); } @@ -178,7 +179,7 @@ protected function ensureSuccessfulBatchJobIsRecorded($command) */ protected function ensureUniqueJobLockIsReleased($command) { - if (! ($command instanceof ShouldBeUnique) || $this->uniqueLockReleased) { + if (! $command instanceof ShouldBeUnique || $this->uniqueLockReleased) { return; } diff --git a/tests/Integration/Queue/UniqueJobTest.php b/tests/Integration/Queue/UniqueJobTest.php index 374d2f7efce8..f463eb58881e 100644 --- a/tests/Integration/Queue/UniqueJobTest.php +++ b/tests/Integration/Queue/UniqueJobTest.php @@ -5,6 +5,7 @@ use Illuminate\Bus\Queueable; use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Queue\ShouldBeUnique; +use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\Schema\Blueprint; use Illuminate\Foundation\Bus\Dispatchable; @@ -215,11 +216,9 @@ class UniqueTestRetryJob extends UniqueTestFailJob public $connection = 'database'; } -class UniqueUntilStartTestJob extends UniqueTestJob +class UniqueUntilStartTestJob extends UniqueTestJob implements ShouldBeUniqueUntilProcessing { public $tries = 2; public $connection = 'database'; - - public $uniqueUntilStart = true; } From e90889d91215bc40b9a60c6dbd14cee3a54d9bed Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 18 Nov 2020 14:36:08 +0000 Subject: [PATCH 022/599] [6.x] Set minimum Guzzle version for PHP 8 CI (#35267) * Set minimum Guzzle version for PHP 8 CI * Fixed typos * Corrected min supported aws sdk --- .github/workflows/tests.yml | 16 ++++++++++++++++ composer.json | 4 ++-- src/Illuminate/Mail/composer.json | 2 +- src/Illuminate/Queue/composer.json | 2 +- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4559e4bc8fd7..02cdf62a88dd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,6 +50,14 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Set Minimum Guzzle Version + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update + if: matrix.php >= 8 + - name: Install dependencies uses: nick-invision/retry@v1 with: @@ -94,6 +102,14 @@ jobs: - name: Setup problem matchers run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Set Minimum Guzzle Version + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer require guzzlehttp/guzzle:^7.2 --no-interaction --no-update + if: matrix.php >= 8 + - name: Install dependencies uses: nick-invision/retry@v1 with: diff --git a/composer.json b/composer.json index 8a164cf352b1..e32e059170fe 100644 --- a/composer.json +++ b/composer.json @@ -77,7 +77,7 @@ "tightenco/collect": "<5.5.33" }, "require-dev": { - "aws/aws-sdk-php": "^3.0", + "aws/aws-sdk-php": "^3.155", "doctrine/dbal": "^2.6", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^6.3.1|^7.0.1", @@ -119,7 +119,7 @@ "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", "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/Mail/composer.json b/src/Illuminate/Mail/composer.json index 7bff13f3beb9..dfe6100d24c7 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -35,7 +35,7 @@ } }, "suggest": { - "aws/aws-sdk-php": "Required to use the SES mail driver (^3.0).", + "aws/aws-sdk-php": "Required to use the SES mail driver (^3.155).", "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.3.1|^7.0.1).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index b6e9238c3c0a..8e1616012c48 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -40,7 +40,7 @@ "suggest": { "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", - "aws/aws-sdk-php": "Required to use the SQS queue driver and DynamoDb failed job storage (^3.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver and DynamoDb failed job storage (^3.155).", "illuminate/redis": "Required to use the Redis queue driver (^6.0).", "pda/pheanstalk": "Required to use the Beanstalk queue driver (^4.0)." }, From d09bf019c5f44e9577a7ed75de4c7f86ec4fb7fa Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Wed, 18 Nov 2020 20:36:26 +0530 Subject: [PATCH 023/599] [8.x] Ensure ShouldBeUniqueUntilProcessing job lock is released once (#35270) * [8.x] Ensure unique lock is released once * Update CallQueuedHandler.php Co-authored-by: Taylor Otwell --- src/Illuminate/Queue/CallQueuedHandler.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index cc3d8934ca4a..adb7b19e11b9 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -30,13 +30,6 @@ class CallQueuedHandler */ protected $container; - /** - * Indicates if the unique job lock has been released. - * - * @var bool - */ - protected $uniqueLockReleased = false; - /** * Create a new handler instance. * @@ -73,7 +66,7 @@ public function call(Job $job, array $data) $this->dispatchThroughMiddleware($job, $command); - if (! $job->isReleased()) { + if (! $job->isReleased() && ! $command instanceof ShouldBeUniqueUntilProcessing) { $this->ensureUniqueJobLockIsReleased($command); } @@ -179,7 +172,7 @@ protected function ensureSuccessfulBatchJobIsRecorded($command) */ protected function ensureUniqueJobLockIsReleased($command) { - if (! $command instanceof ShouldBeUnique || $this->uniqueLockReleased) { + if (! $command instanceof ShouldBeUnique) { return; } @@ -194,8 +187,6 @@ protected function ensureUniqueJobLockIsReleased($command) $cache->lock( 'laravel_unique_job:'.get_class($command).$uniqueId )->forceRelease(); - - $this->uniqueLockReleased = true; } /** @@ -237,7 +228,10 @@ public function failed(array $data, $e, string $uuid) { $command = unserialize($data['command']); - $this->ensureUniqueJobLockIsReleased($command); + if (! $command instanceof ShouldBeUniqueUntilProcessing) { + $this->ensureUniqueJobLockIsReleased($command); + } + $this->ensureFailedBatchJobIsRecorded($uuid, $command, $e); $this->ensureChainCatchCallbacksAreInvoked($uuid, $command, $e); From 664e87f0d36635495f19c17eee3f51082be660b5 Mon Sep 17 00:00:00 2001 From: iamgergo Date: Wed, 18 Nov 2020 16:38:29 +0100 Subject: [PATCH 024/599] [8.x] Support delaying notifications by channel --- src/Illuminate/Notifications/NotificationSender.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index 1d6c424b1512..d3f95433be9a 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -202,7 +202,9 @@ protected function queueNotification($notifiables, $notification) (new SendQueuedNotifications($notifiable, $notification, [$channel])) ->onConnection($notification->connection) ->onQueue($queue) - ->delay($notification->delay) + ->delay( + is_array($notification->delay) ? $notification->delay[$channel] ?? null : $notification->delay + ) ->through( array_merge( method_exists($notification, 'middleware') ? $notification->middleware() : [], From 498272fe3fe859b9f77558df74d52b2937822654 Mon Sep 17 00:00:00 2001 From: Piotr Krzempek Date: Wed, 18 Nov 2020 19:14:22 +0100 Subject: [PATCH 025/599] added sortByMany method to Arr helper --- src/Illuminate/Collections/Arr.php | 56 ++++++++++++++++++++++++++++++ tests/Support/SupportArrTest.php | 53 ++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index be75b1dad85e..e473337f8845 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -678,4 +678,60 @@ public static function wrap($value) return is_array($value) ? $value : [$value]; } + + /** + * Sort giiven array by many properties. + * + * @param array $array + * @param array $comparisons + * @return array + */ + public static function sortByMany($array, $comparisons = []) + { + usort($array, function($a, $b) use($comparisons) { + + foreach($comparisons as $cmp) + { + // destruct comparison array to variables + // with order set by default to 1 + [$prop, $ascending] = static::wrap($cmp) + [1 => true]; + $result = 0; + + if(is_callable($prop)) { + $result = $prop($a, $b); + } + else { + $values = [static::get($a, $prop), static::get($b, $prop)]; + + if(!$ascending) { + $values = array_reverse($values); + } + + $result = static::compareValues(...$values); + } + + // if result is 0, values are equal + // so we have to order items by next comparison + if($result === 0) { + continue; + } + + return $result; + } + }); + + return $array; + } + + /** + * Compare two values + * + * @param mixed $a + * @param mixed $b + * @return int + */ + protected static function compareValues($a, $b) + { + return $a <=> $b; + } } diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 1b4a280ca5a0..e50922930d11 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -903,4 +903,57 @@ public function testWrap() $this->assertEquals([$obj], Arr::wrap($obj)); $this->assertSame($obj, Arr::wrap($obj)[0]); } + + public function testSortByMany() + { + $unsorted = [ + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]], + ['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]], + ['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]], + ]; + + // sort using keys + $sorted = array_values(Arr::sortByMany($unsorted, [ + 'name', + 'age', + 'meta.key', + ])); + $this->assertEquals([ + ['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]], + ['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]], + ], $sorted); + + // sort with order + $sortedWithOrder = array_values(Arr::sortByMany($unsorted, [ + 'name', + ['age', false], + ['meta.key', true], + ])); + $this->assertEquals([ + ['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]], + ['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]], + ], $sortedWithOrder); + + // sort using callable + $sortedWithCallable = array_values(Arr::sortByMany($unsorted, [ + function($a, $b) { + return $a['name'] <=> $b['name']; + }, + function($a, $b) { + return $b['age'] <=> $a['age']; + }, + ['meta.key', true], + ])); + $this->assertEquals([ + ['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]], + ['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]], + ['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]], + ], $sortedWithCallable); + } } From 21621c7c70fdf9dcc2bc56e705f9d97e99c0aa57 Mon Sep 17 00:00:00 2001 From: Piotr Krzempek Date: Wed, 18 Nov 2020 19:19:31 +0100 Subject: [PATCH 026/599] removed unused local compareValues method from Arr helper --- src/Illuminate/Collections/Arr.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index e473337f8845..7c287d4c81ed 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -707,7 +707,7 @@ public static function sortByMany($array, $comparisons = []) $values = array_reverse($values); } - $result = static::compareValues(...$values); + $result = $values[0] <=> $values[1]; } // if result is 0, values are equal @@ -722,16 +722,4 @@ public static function sortByMany($array, $comparisons = []) return $array; } - - /** - * Compare two values - * - * @param mixed $a - * @param mixed $b - * @return int - */ - protected static function compareValues($a, $b) - { - return $a <=> $b; - } } From 31e080c7d3f5614dab498467b2b9114f24a09c7a Mon Sep 17 00:00:00 2001 From: Daniil Zobov Date: Wed, 18 Nov 2020 22:23:18 +0300 Subject: [PATCH 027/599] Rename qualifyColumn to qualifyPivotColumn in BelongsToMany & MorphToMany (#35276) --- .../Eloquent/Relations/BelongsToMany.php | 16 ++++++++-------- .../Database/Eloquent/Relations/MorphToMany.php | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index e5d700e59bd8..d15b70ddccbe 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -362,7 +362,7 @@ public function wherePivot($column, $operator = null, $value = null, $boolean = { $this->pivotWheres[] = func_get_args(); - return $this->where($this->qualifyColumn($column), $operator, $value, $boolean); + return $this->where($this->qualifyPivotColumn($column), $operator, $value, $boolean); } /** @@ -376,7 +376,7 @@ public function wherePivot($column, $operator = null, $value = null, $boolean = */ public function wherePivotBetween($column, array $values, $boolean = 'and', $not = false) { - return $this->whereBetween($this->qualifyColumn($column), $values, $boolean, $not); + return $this->whereBetween($this->qualifyPivotColumn($column), $values, $boolean, $not); } /** @@ -429,7 +429,7 @@ public function wherePivotIn($column, $values, $boolean = 'and', $not = false) { $this->pivotWhereIns[] = func_get_args(); - return $this->whereIn($this->qualifyColumn($column), $values, $boolean, $not); + return $this->whereIn($this->qualifyPivotColumn($column), $values, $boolean, $not); } /** @@ -524,7 +524,7 @@ public function wherePivotNull($column, $boolean = 'and', $not = false) { $this->pivotWhereNulls[] = func_get_args(); - return $this->whereNull($this->qualifyColumn($column), $boolean, $not); + return $this->whereNull($this->qualifyPivotColumn($column), $boolean, $not); } /** @@ -810,7 +810,7 @@ protected function aliasedPivotColumns() $defaults = [$this->foreignPivotKey, $this->relatedPivotKey]; return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { - return $this->qualifyColumn($column).' as pivot_'.$column; + return $this->qualifyPivotColumn($column).' as pivot_'.$column; })->unique()->all(); } @@ -1230,7 +1230,7 @@ public function getForeignPivotKeyName() */ public function getQualifiedForeignPivotKeyName() { - return $this->qualifyColumn($this->foreignPivotKey); + return $this->qualifyPivotColumn($this->foreignPivotKey); } /** @@ -1250,7 +1250,7 @@ public function getRelatedPivotKeyName() */ public function getQualifiedRelatedPivotKeyName() { - return $this->qualifyColumn($this->relatedPivotKey); + return $this->qualifyPivotColumn($this->relatedPivotKey); } /** @@ -1339,7 +1339,7 @@ public function getPivotColumns() * @param string $column * @return string */ - public function qualifyColumn($column) + public function qualifyPivotColumn($column) { return Str::contains($column, '.') ? $column diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index ec456816004c..c2d574558224 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -68,7 +68,7 @@ protected function addWhereConstraints() { parent::addWhereConstraints(); - $this->query->where($this->qualifyColumn($this->morphType), $this->morphClass); + $this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass); return $this; } @@ -83,7 +83,7 @@ public function addEagerConstraints(array $models) { parent::addEagerConstraints($models); - $this->query->where($this->qualifyColumn($this->morphType), $this->morphClass); + $this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass); } /** @@ -111,7 +111,7 @@ protected function baseAttachRecord($id, $timed) public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where( - $this->qualifyColumn($this->morphType), $this->morphClass + $this->qualifyPivotColumn($this->morphType), $this->morphClass ); } @@ -173,7 +173,7 @@ protected function aliasedPivotColumns() $defaults = [$this->foreignPivotKey, $this->relatedPivotKey, $this->morphType]; return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { - return $this->qualifyColumn($column).' as pivot_'.$column; + return $this->qualifyPivotColumn($column).' as pivot_'.$column; })->unique()->all(); } From abea927eddfebd82b77a9e7db9b347b4597cdef0 Mon Sep 17 00:00:00 2001 From: Tom Witkowski Date: Wed, 18 Nov 2020 20:28:32 +0100 Subject: [PATCH 028/599] check if AsPivot trait is used (#35271) --- src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index d15b70ddccbe..b54340ec2559 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot; use Illuminate\Support\Str; use InvalidArgumentException; @@ -177,7 +178,7 @@ protected function resolveTableName($table) return $table; } - if ($model instanceof Pivot) { + if (in_array(AsPivot::class, class_uses_recursive($model))) { $this->using($table); } From 325a335ccf45426eabb27131ed48aa6114434c99 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 18 Nov 2020 17:08:04 -0600 Subject: [PATCH 029/599] fix rendering of notifications with config custom theme --- src/Illuminate/Mail/Markdown.php | 10 ++++++++++ src/Illuminate/Notifications/Messages/MailMessage.php | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Mail/Markdown.php b/src/Illuminate/Mail/Markdown.php index 3effcf92bf57..a506f837f59f 100644 --- a/src/Illuminate/Mail/Markdown.php +++ b/src/Illuminate/Mail/Markdown.php @@ -174,4 +174,14 @@ public function theme($theme) return $this; } + + /** + * Get the theme currently being used by the renderer. + * + * @return string + */ + public function getTheme() + { + return $this->theme; + } } diff --git a/src/Illuminate/Notifications/Messages/MailMessage.php b/src/Illuminate/Notifications/Messages/MailMessage.php index ec67001d2580..08e79d0fa0f5 100644 --- a/src/Illuminate/Notifications/Messages/MailMessage.php +++ b/src/Illuminate/Notifications/Messages/MailMessage.php @@ -312,10 +312,10 @@ public function render() ); } - return Container::getInstance() - ->make(Markdown::class) - ->theme($this->theme ?: 'default') - ->render($this->markdown, $this->data()); + $markdown = Container::getInstance()->make(Markdown::class); + + return $markdown->theme($this->theme ?: $markdown->getTheme()) + ->render($this->markdown, $this->data()); } /** From 174c0e545312a13c49bef36c9e9e98ac384dcf87 Mon Sep 17 00:00:00 2001 From: Piiotr Krzempek Date: Thu, 19 Nov 2020 11:43:17 +0100 Subject: [PATCH 030/599] style fix --- src/Illuminate/Collections/Arr.php | 15 ++++++--------- tests/Support/SupportArrTest.php | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 7c287d4c81ed..11c53cdb0712 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -688,22 +688,19 @@ public static function wrap($value) */ public static function sortByMany($array, $comparisons = []) { - usort($array, function($a, $b) use($comparisons) { - - foreach($comparisons as $cmp) - { + usort($array, function ($a, $b) use ($comparisons) { + foreach ($comparisons as $cmp) { // destruct comparison array to variables // with order set by default to 1 [$prop, $ascending] = static::wrap($cmp) + [1 => true]; $result = 0; - if(is_callable($prop)) { + if (is_callable($prop)) { $result = $prop($a, $b); - } - else { + } else { $values = [static::get($a, $prop), static::get($b, $prop)]; - if(!$ascending) { + if (! $ascending) { $values = array_reverse($values); } @@ -712,7 +709,7 @@ public static function sortByMany($array, $comparisons = []) // if result is 0, values are equal // so we have to order items by next comparison - if($result === 0) { + if ($result === 0) { continue; } diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index e50922930d11..73871670e35b 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -941,10 +941,10 @@ public function testSortByMany() // sort using callable $sortedWithCallable = array_values(Arr::sortByMany($unsorted, [ - function($a, $b) { + function ($a, $b) { return $a['name'] <=> $b['name']; }, - function($a, $b) { + function ($a, $b) { return $b['age'] <=> $a['age']; }, ['meta.key', true], From 23ba4ed7d7f793e1d2013ecdfbd6e100e863f5c1 Mon Sep 17 00:00:00 2001 From: Lennart Carstens-Behrens Date: Thu, 19 Nov 2020 15:10:44 +0100 Subject: [PATCH 031/599] Fixed BroadcastException in PusherBroadcaster (#35290) --- src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 68daf9da4b26..c39abbd6f61b 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -120,7 +120,7 @@ public function broadcast(array $channels, $event, array $payload = []) throw new BroadcastException( ! empty($response['body']) - ? sprintf('Pusher error: %s.', $response['status']) + ? sprintf('Pusher error: %s.', $response['body']) : 'Failed to connect to Pusher.' ); } From 7a7ca4a150962989370e44baeed9238f8fa301ab Mon Sep 17 00:00:00 2001 From: "Dimitar \"Arruor\" Nikov" Date: Thu, 19 Nov 2020 14:11:14 +0000 Subject: [PATCH 032/599] Fix deprecated \Symfony\Component\HttpFoundation\Response::create() in convertExceptionToResponse() (#35289) --- src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 52e4c40ea732..924046b8b340 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -465,7 +465,7 @@ protected function prepareResponse($request, Throwable $e) */ protected function convertExceptionToResponse(Throwable $e) { - return SymfonyResponse::create( + return new SymfonyResponse( $this->renderExceptionContent($e), $this->isHttpException($e) ? $e->getStatusCode() : 500, $this->isHttpException($e) ? $e->getHeaders() : [] From 6b8285a2ca4514d2e280ce4eabaa8fe57abee282 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Thu, 19 Nov 2020 15:13:52 +0100 Subject: [PATCH 033/599] Add broker method to Password facade doc blocks (#35284) --- src/Illuminate/Support/Facades/Password.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Password.php b/src/Illuminate/Support/Facades/Password.php index b62f1908a35b..1903af244d78 100755 --- a/src/Illuminate/Support/Facades/Password.php +++ b/src/Illuminate/Support/Facades/Password.php @@ -12,6 +12,7 @@ * @method static void deleteToken(\Illuminate\Contracts\Auth\CanResetPassword $user) * @method static bool tokenExists(\Illuminate\Contracts\Auth\CanResetPassword $user, string $token) * @method static \Illuminate\Auth\Passwords\TokenRepositoryInterface getRepository() + * @method static \Illuminate\Contracts\Auth\PasswordBroker broker(string|null $name = null) * * @see \Illuminate\Auth\Passwords\PasswordBroker */ From 1a552b765cf1f3ce5b6d24e9942fe74edbaa81b0 Mon Sep 17 00:00:00 2001 From: Serge Byishimo Date: Thu, 19 Nov 2020 16:14:32 +0200 Subject: [PATCH 034/599] added array doc block for aggr. functions (#35283) --- .../Database/Eloquent/Concerns/QueriesRelationships.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 4271fcc28586..065e1b4fbcd7 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -442,7 +442,7 @@ public function withCount($relations) /** * Add subselect queries to include the max of the relation's column. * - * @param string $relation + * @param string|array $relation * @param string $column * @return $this */ @@ -454,7 +454,7 @@ public function withMax($relation, $column) /** * Add subselect queries to include the min of the relation's column. * - * @param string $relation + * @param string|array $relation * @param string $column * @return $this */ @@ -466,7 +466,7 @@ public function withMin($relation, $column) /** * Add subselect queries to include the sum of the relation's column. * - * @param string $relation + * @param string|array $relation * @param string $column * @return $this */ @@ -478,7 +478,7 @@ public function withSum($relation, $column) /** * Add subselect queries to include the average of the relation's column. * - * @param string $relation + * @param string|array $relation * @param string $column * @return $this */ From 27b4a7665efdfcf8b37ca021029cf1f6160db3b2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 19 Nov 2020 08:18:26 -0600 Subject: [PATCH 035/599] Formatting --- src/Illuminate/Notifications/NotificationSender.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index d3f95433be9a..98fb2fe56d9a 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -202,8 +202,9 @@ protected function queueNotification($notifiables, $notification) (new SendQueuedNotifications($notifiable, $notification, [$channel])) ->onConnection($notification->connection) ->onQueue($queue) - ->delay( - is_array($notification->delay) ? $notification->delay[$channel] ?? null : $notification->delay + ->delay(is_array($notification->delay) ? + ($notification->delay[$channel] ?? null) + : $notification->delay ) ->through( array_merge( From 53eb307fea077299d409adf3ba0307a8fda4c4d1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 19 Nov 2020 09:26:20 -0600 Subject: [PATCH 036/599] allow sorting on multiple criteria --- src/Illuminate/Collections/Arr.php | 43 +------------------ src/Illuminate/Collections/Collection.php | 50 ++++++++++++++++++++++- tests/Support/SupportArrTest.php | 6 +-- 3 files changed, 53 insertions(+), 46 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 11c53cdb0712..9d08ae2c8c24 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -604,7 +604,7 @@ public static function shuffle($array, $seed = null) * Sort the array using the given callback or "dot" notation. * * @param array $array - * @param callable|string|null $callback + * @param callable|array|string|null $callback * @return array */ public static function sort($array, $callback = null) @@ -678,45 +678,4 @@ public static function wrap($value) return is_array($value) ? $value : [$value]; } - - /** - * Sort giiven array by many properties. - * - * @param array $array - * @param array $comparisons - * @return array - */ - public static function sortByMany($array, $comparisons = []) - { - usort($array, function ($a, $b) use ($comparisons) { - foreach ($comparisons as $cmp) { - // destruct comparison array to variables - // with order set by default to 1 - [$prop, $ascending] = static::wrap($cmp) + [1 => true]; - $result = 0; - - if (is_callable($prop)) { - $result = $prop($a, $b); - } else { - $values = [static::get($a, $prop), static::get($b, $prop)]; - - if (! $ascending) { - $values = array_reverse($values); - } - - $result = $values[0] <=> $values[1]; - } - - // if result is 0, values are equal - // so we have to order items by next comparison - if ($result === 0) { - continue; - } - - return $result; - } - }); - - return $array; - } } diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 15d17ce441fe..6a9e96f4ed54 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1110,13 +1110,17 @@ public function sortDesc($options = SORT_REGULAR) /** * Sort the collection using the given callback. * - * @param callable|string $callback + * @param callable|array|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { + if (is_array($callback)) { + return $this->sortByMany($callback); + } + $results = []; $callback = $this->valueRetriever($callback); @@ -1141,6 +1145,50 @@ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) return new static($results); } + /** + * Sort the collection using multiple comparisons. + * + * @param array $comparisons + * @return static + */ + protected function sortByMany(array $comparisons = []) + { + $items = $this->items; + + usort($items, function ($a, $b) use ($comparisons) { + foreach ($comparisons as $comparison) { + $comparison = Arr::wrap($comparison); + + $prop = $comparison[0]; + + $ascending = Arr::get($comparison, 1, true) === true || + Arr::get($comparison, 1, true) === 'asc'; + + $result = 0; + + if (is_callable($prop)) { + $result = $prop($a, $b); + } else { + $values = [Arr::get($a, $prop), Arr::get($b, $prop)]; + + if (! $ascending) { + $values = array_reverse($values); + } + + $result = $values[0] <=> $values[1]; + } + + if ($result === 0) { + continue; + } + + return $result; + } + }); + + return new static($items); + } + /** * Sort the collection in descending order using the given callback. * diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 73871670e35b..7356c4378d03 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -914,7 +914,7 @@ public function testSortByMany() ]; // sort using keys - $sorted = array_values(Arr::sortByMany($unsorted, [ + $sorted = array_values(Arr::sort($unsorted, [ 'name', 'age', 'meta.key', @@ -927,7 +927,7 @@ public function testSortByMany() ], $sorted); // sort with order - $sortedWithOrder = array_values(Arr::sortByMany($unsorted, [ + $sortedWithOrder = array_values(Arr::sort($unsorted, [ 'name', ['age', false], ['meta.key', true], @@ -940,7 +940,7 @@ public function testSortByMany() ], $sortedWithOrder); // sort using callable - $sortedWithCallable = array_values(Arr::sortByMany($unsorted, [ + $sortedWithCallable = array_values(Arr::sort($unsorted, [ function ($a, $b) { return $a['name'] <=> $b['name']; }, From 17cf51113d74c1e64ddd272d16fe40b073b1907e Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Thu, 19 Nov 2020 17:02:53 +0100 Subject: [PATCH 037/599] Avoid no-op database query in Model::destroy() with empty ids --- src/Illuminate/Database/Eloquent/Model.php | 15 +++++++++----- tests/Database/DatabaseEloquentModelTest.php | 21 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index f6f90b544391..acede7c91308 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1061,22 +1061,27 @@ protected function insertAndSetId(Builder $query, $attributes) */ public static function destroy($ids) { - // We'll initialize a count here so we will return the total number of deletes - // for the operation. The developers can then check this number as a boolean - // type value or get this total count of records deleted for logging, etc. - $count = 0; - if ($ids instanceof BaseCollection) { $ids = $ids->all(); } $ids = is_array($ids) ? $ids : func_get_args(); + // Avoid a no-op database query by bailing early + if (count($ids) === 0) { + return 0; + } + // We will actually pull the models from the database table and call delete on // each of them individually so that their events get fired properly with a // correct set of attributes in case the developers wants to check these. $key = ($instance = new static)->getKeyName(); + // We'll initialize a count here so we will return the total number of deletes + // for the operation. The developers can then check this number as a boolean + // type value or get this total count of records deleted for logging, etc. + $count = 0; + foreach ($instance->whereIn($key, $ids)->get() as $model) { if ($model->delete()) { $count++; diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 2d3f3e10ebdf..b9f9758cd031 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -293,6 +293,16 @@ public function testDestroyMethodCallsQueryBuilderCorrectlyWithCollection() EloquentModelDestroyStub::destroy(new Collection([1, 2, 3])); } + public function testDestroyMethodCallsQueryBuilderCorrectlyWithMultipleArgs() + { + EloquentModelDestroyStub::destroy(1, 2, 3); + } + + public function testDestroyMethodCallsQueryBuilderCorrectlyWithEmptyIds() + { + EloquentModelEmptyDestroyStub::destroy([]); + } + public function testWithMethodCallsQueryBuilderCorrectly() { $result = EloquentModelWithStub::with('foo', 'bar'); @@ -2400,6 +2410,17 @@ public function newQuery() } } +class EloquentModelEmptyDestroyStub extends Model +{ + public function newQuery() + { + $mock = m::mock(Builder::class); + $mock->shouldReceive('whereIn')->never(); + + return $mock; + } +} + class EloquentModelHydrateRawStub extends Model { public static function hydrate(array $items, $connection = null) From 777e40a35193384fbc0f0be2c3900151a61df999 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Thu, 19 Nov 2020 17:11:50 +0100 Subject: [PATCH 038/599] Expect the returned count to be 0 --- tests/Database/DatabaseEloquentModelTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index b9f9758cd031..114c4ae6f5c2 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -300,7 +300,8 @@ public function testDestroyMethodCallsQueryBuilderCorrectlyWithMultipleArgs() public function testDestroyMethodCallsQueryBuilderCorrectlyWithEmptyIds() { - EloquentModelEmptyDestroyStub::destroy([]); + $count = EloquentModelEmptyDestroyStub::destroy([]); + $this->assertSame(0, $count); } public function testWithMethodCallsQueryBuilderCorrectly() From fe96aca26c3355cb2f0e297138dbae7b8232bf74 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 19 Nov 2020 10:58:25 -0600 Subject: [PATCH 039/599] formatting --- src/Illuminate/Database/Eloquent/Model.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index acede7c91308..528f9ca497a0 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1067,7 +1067,6 @@ public static function destroy($ids) $ids = is_array($ids) ? $ids : func_get_args(); - // Avoid a no-op database query by bailing early if (count($ids) === 0) { return 0; } @@ -1077,9 +1076,6 @@ public static function destroy($ids) // correct set of attributes in case the developers wants to check these. $key = ($instance = new static)->getKeyName(); - // We'll initialize a count here so we will return the total number of deletes - // for the operation. The developers can then check this number as a boolean - // type value or get this total count of records deleted for logging, etc. $count = 0; foreach ($instance->whereIn($key, $ids)->get() as $model) { From 318c226907707e6d82941e8449ab9527b789cd90 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 19 Nov 2020 11:43:32 -0600 Subject: [PATCH 040/599] add currentLocale method --- src/Illuminate/Foundation/Application.php | 10 ++++++++++ src/Illuminate/Support/Facades/App.php | 1 + 2 files changed, 11 insertions(+) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 17f6788e65e9..c09ea70157ec 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -1181,6 +1181,16 @@ public function getLocale() return $this['config']->get('app.locale'); } + /** + * Get the current application locale. + * + * @return string + */ + public function currentLocale() + { + return $this->getLocale(); + } + /** * Get the current application fallback locale. * diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index dcf59e75e42f..63d8709143d7 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -27,6 +27,7 @@ * @method static string getCachedRoutesPath() * @method static string getCachedServicesPath() * @method static string getLocale() + * @method static string currentLocale() * @method static string getNamespace() * @method static string resourcePath(string $path = '') * @method static string storagePath(string $path = '') From d05197039c4c78ad5ced48f85fe5a4ca39199fd4 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 17:04:18 +0530 Subject: [PATCH 041/599] [8.x] Add DB command to open the database CLI --- src/Illuminate/Database/Console/DbCommand.php | 195 ++++++++++++++++++ .../Providers/ArtisanServiceProvider.php | 12 ++ 2 files changed, 207 insertions(+) create mode 100644 src/Illuminate/Database/Console/DbCommand.php diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php new file mode 100644 index 000000000000..c8391a975ed7 --- /dev/null +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -0,0 +1,195 @@ +getConnection(); + + (new Process( + [$this->getCommand($connection), ...$this->getArgs($connection)], + null, $this->getEnv($connection) + ))->setTimeout(null)->setTty(true)->mustRun(function ($type, $buffer) { + $this->output->write($buffer); + }); + + return 0; + } + + /** + * Get the database connection configuration. + * + * @return array + */ + public function getConnection() + { + $connection = $this->laravel['config']['database.connections.'. + (($db = $this->option('database')) ?? $this->laravel['config']['database.default']) + ]; + + if (empty($connection)) { + throw new UnexpectedValueException("Invalid database connection: [{$db}]."); + } + + return $connection; + } + + /** + * Get the arguments for the database client command. + * + * @param array $connection + * @return string + */ + public function getArgs($connection) + { + $driver = ucfirst($connection['driver']); + + return $this->{"get{$driver}Args"}($connection); + } + + /** + * Get the environmental variables for the database client command. + * + * @param array $connection + * @return array|null + */ + public function getEnv($connection) + { + $driver = ucfirst($connection['driver']); + + if (method_exists($this, "get{$driver}Env")) { + return $this->{"get{$driver}Env"}($connection); + } + + return null; + } + + /** + * Get the database client command to run. + * + * @param array $connection + * @return string + */ + public function getCommand($connection) + { + return [ + 'mysql' => 'mysql', + 'pgsql' => 'psql', + 'sqlite' => 'sqlite3', + 'sqlsrv' => 'sqlcmd', + ][$connection['driver']]; + } + + /** + * Get the arguments for the mysql CLI. + * + * @param array $connection + * @return array + */ + protected function getMysqlArgs($connection) + { + return array_merge([ + '--host='.$connection['host'], + '--port='.$connection['port'], + '--user='.$connection['username'], + ], $this->buildOptionalArguments([ + 'password' => '--password='.$connection['password'], + 'unix_socket' => '--socket='.$connection['unix_socket'], + 'charset' => '--default-character-set='.$connection['charset'], + ], $connection), [$connection['database']]); + } + + /** + * Get the arguments for the pgsql CLI. + * + * @param array $connection + * @return array + */ + protected function getPgsqlArgs($connection) + { + return [$connection['database']]; + } + + /** + * Get the arguments for the sqlite CLI. + * + * @param array $connection + * @return array + */ + protected function getSqliteArgs($connection) + { + return [$connection['database']]; + } + + /** + * Get the arguments for the sqlite CLI. + * + * @param array $connection + * @return array + */ + protected function getSqlsrvArgs($connection) + { + return $this->buildOptionalArguments([ + 'database' => '-d '.$connection['database'], + 'username' => '-U '.$connection['username'], + 'password' => '-P '.$connection['password'], + 'host' => '-S tcp:'.$connection['host'] + .($connection['port'] ? ','.$connection['port'] : ''), + ], $connection); + } + + /** + * Get the environmental variables for the pgsql CLI. + * + * @param array $connection + * @return array|null + */ + protected function getpgsqlEnv($connection) + { + return array_merge(...$this->buildOptionalArguments([ + 'username' => ['PGUSER' => $connection['username']], + 'host' => ['PGHOST' => $connection['host']], + 'port' => ['PGPORT' => $connection['port']], + 'password' => ['PGPASSWORD' => $connection['password']], + ], $connection)); + } + + /** + * Build optional arguments based on the connection configuration. + * + * @param array $args + * @param array $connection + * @return array + */ + protected function buildOptionalArguments($args, $connection) + { + return array_values(array_filter($args, function ($key) use ($connection) { + return ! empty($connection[$key]); + }, ARRAY_FILTER_USE_KEY)); + } +} diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index dc82ba1df83c..7fee3cf38026 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -14,6 +14,7 @@ use Illuminate\Database\Console\Factories\FactoryMakeCommand; use Illuminate\Database\Console\Seeds\SeedCommand; use Illuminate\Database\Console\Seeds\SeederMakeCommand; +use Illuminate\Database\Console\DbCommand; use Illuminate\Database\Console\WipeCommand; use Illuminate\Foundation\Console\CastMakeCommand; use Illuminate\Foundation\Console\ChannelMakeCommand; @@ -88,6 +89,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'ClearResets' => 'command.auth.resets.clear', 'ConfigCache' => 'command.config.cache', 'ConfigClear' => 'command.config.clear', + 'Db' => DbCommand::class, 'DbWipe' => 'command.db.wipe', 'Down' => 'command.down', 'Environment' => 'command.environment', @@ -332,6 +334,16 @@ protected function registerControllerMakeCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerDbCommand() + { + $this->app->singleton(DbCommand::class); + } + /** * Register the command. * From 696a1d3537a67f484e51345a7a852607c2597714 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 17:29:12 +0530 Subject: [PATCH 042/599] fix styleci --- src/Illuminate/Database/Console/DbCommand.php | 2 +- src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index c8391a975ed7..cd5ba54be574 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -2,9 +2,9 @@ namespace Illuminate\Database\Console; -use UnexpectedValueException; use Illuminate\Console\Command; use Symfony\Component\Process\Process; +use UnexpectedValueException; class DbCommand extends Command { diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 7fee3cf38026..c4d31671075d 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -10,11 +10,11 @@ use Illuminate\Console\Scheduling\ScheduleRunCommand; use Illuminate\Console\Scheduling\ScheduleWorkCommand; use Illuminate\Contracts\Support\DeferrableProvider; +use Illuminate\Database\Console\DbCommand; use Illuminate\Database\Console\DumpCommand; use Illuminate\Database\Console\Factories\FactoryMakeCommand; use Illuminate\Database\Console\Seeds\SeedCommand; use Illuminate\Database\Console\Seeds\SeederMakeCommand; -use Illuminate\Database\Console\DbCommand; use Illuminate\Database\Console\WipeCommand; use Illuminate\Foundation\Console\CastMakeCommand; use Illuminate\Foundation\Console\ChannelMakeCommand; From 6d401d2cd43cc7a992486840aab7bfa304e566bf Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 17:44:51 +0530 Subject: [PATCH 043/599] fix php 7.3 compatibility with spread operator --- src/Illuminate/Database/Console/DbCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index cd5ba54be574..cb9774db2db6 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -32,7 +32,7 @@ public function handle() $connection = $this->getConnection(); (new Process( - [$this->getCommand($connection), ...$this->getArgs($connection)], + array_merge([$this->getCommand($connection)], $this->getArgs($connection)), null, $this->getEnv($connection) ))->setTimeout(null)->setTty(true)->mustRun(function ($type, $buffer) { $this->output->write($buffer); @@ -63,7 +63,7 @@ public function getConnection() * Get the arguments for the database client command. * * @param array $connection - * @return string + * @return array */ public function getArgs($connection) { From 3bf0ee51fa59a71bba16ba91e3bce45c88af6f5a Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 18:09:54 +0530 Subject: [PATCH 044/599] fix typo in docblock --- src/Illuminate/Database/Console/DbCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index cb9774db2db6..f158d249aa20 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -20,7 +20,7 @@ class DbCommand extends Command * * @var string */ - protected $description = 'Open the database CLI'; + protected $description = 'Drop into the database CLI.'; /** * Execute the console command. @@ -147,7 +147,7 @@ protected function getSqliteArgs($connection) } /** - * Get the arguments for the sqlite CLI. + * Get the arguments for the SQL Server CLI. * * @param array $connection * @return array From 1b348b47d2bde511a1d8ab92f8171e0eb971ad82 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 19:26:09 +0530 Subject: [PATCH 045/599] Change database option to argument and rename to connection --- src/Illuminate/Database/Console/DbCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index f158d249aa20..962839d8b095 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -13,7 +13,7 @@ class DbCommand extends Command * * @var string */ - protected $signature = 'db {--database= : The database connection to use}'; + protected $signature = 'db {connection? : The database connection to use}'; /** * The console command description. @@ -49,7 +49,7 @@ public function handle() public function getConnection() { $connection = $this->laravel['config']['database.connections.'. - (($db = $this->option('database')) ?? $this->laravel['config']['database.default']) + (($db = $this->argument('connection')) ?? $this->laravel['config']['database.default']) ]; if (empty($connection)) { From a6385ce2d7a33c76d58af919152c1dd911700af9 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 19:34:27 +0530 Subject: [PATCH 046/599] formatting --- src/Illuminate/Database/Console/DbCommand.php | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index 962839d8b095..d0460699dfed 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -65,7 +65,7 @@ public function getConnection() * @param array $connection * @return array */ - public function getArgs($connection) + public function getArgs(array $connection) { $driver = ucfirst($connection['driver']); @@ -78,7 +78,7 @@ public function getArgs($connection) * @param array $connection * @return array|null */ - public function getEnv($connection) + public function getEnv(array $connection) { $driver = ucfirst($connection['driver']); @@ -95,13 +95,13 @@ public function getEnv($connection) * @param array $connection * @return string */ - public function getCommand($connection) + public function getCommand(array $connection) { return [ - 'mysql' => 'mysql', - 'pgsql' => 'psql', - 'sqlite' => 'sqlite3', - 'sqlsrv' => 'sqlcmd', + 'mysql' => 'mysql', + 'pgsql' => 'psql', + 'sqlite' => 'sqlite3', + 'sqlsrv' => 'sqlcmd', ][$connection['driver']]; } @@ -111,16 +111,16 @@ public function getCommand($connection) * @param array $connection * @return array */ - protected function getMysqlArgs($connection) + protected function getMysqlArgs(array $connection) { return array_merge([ '--host='.$connection['host'], '--port='.$connection['port'], '--user='.$connection['username'], ], $this->buildOptionalArguments([ - 'password' => '--password='.$connection['password'], - 'unix_socket' => '--socket='.$connection['unix_socket'], - 'charset' => '--default-character-set='.$connection['charset'], + 'password' => '--password='.$connection['password'], + 'unix_socket' => '--socket='.$connection['unix_socket'], + 'charset' => '--default-character-set='.$connection['charset'], ], $connection), [$connection['database']]); } @@ -130,7 +130,7 @@ protected function getMysqlArgs($connection) * @param array $connection * @return array */ - protected function getPgsqlArgs($connection) + protected function getPgsqlArgs(array $connection) { return [$connection['database']]; } @@ -141,7 +141,7 @@ protected function getPgsqlArgs($connection) * @param array $connection * @return array */ - protected function getSqliteArgs($connection) + protected function getSqliteArgs(array $connection) { return [$connection['database']]; } @@ -152,14 +152,14 @@ protected function getSqliteArgs($connection) * @param array $connection * @return array */ - protected function getSqlsrvArgs($connection) + protected function getSqlsrvArgs(array $connection) { return $this->buildOptionalArguments([ - 'database' => '-d '.$connection['database'], - 'username' => '-U '.$connection['username'], - 'password' => '-P '.$connection['password'], - 'host' => '-S tcp:'.$connection['host'] - .($connection['port'] ? ','.$connection['port'] : ''), + 'database' => '-d '.$connection['database'], + 'username' => '-U '.$connection['username'], + 'password' => '-P '.$connection['password'], + 'host' => '-S tcp:'.$connection['host'] + .($connection['port'] ? ','.$connection['port'] : ''), ], $connection); } @@ -169,13 +169,13 @@ protected function getSqlsrvArgs($connection) * @param array $connection * @return array|null */ - protected function getpgsqlEnv($connection) + protected function getpgsqlEnv(array $connection) { return array_merge(...$this->buildOptionalArguments([ - 'username' => ['PGUSER' => $connection['username']], - 'host' => ['PGHOST' => $connection['host']], - 'port' => ['PGPORT' => $connection['port']], - 'password' => ['PGPASSWORD' => $connection['password']], + 'username' => ['PGUSER' => $connection['username']], + 'host' => ['PGHOST' => $connection['host']], + 'port' => ['PGPORT' => $connection['port']], + 'password' => ['PGPASSWORD' => $connection['password']], ], $connection)); } @@ -186,7 +186,7 @@ protected function getpgsqlEnv($connection) * @param array $connection * @return array */ - protected function buildOptionalArguments($args, $connection) + protected function buildOptionalArguments(array $args,array $connection) { return array_values(array_filter($args, function ($key) use ($connection) { return ! empty($connection[$key]); From e40ce91a438900e560880b4f2548fa46479f141b Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 19:35:48 +0530 Subject: [PATCH 047/599] styleci --- 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 d0460699dfed..7d60cf272d52 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -186,7 +186,7 @@ protected function getpgsqlEnv(array $connection) * @param array $connection * @return array */ - protected function buildOptionalArguments(array $args,array $connection) + protected function buildOptionalArguments(array $args, array $connection) { return array_values(array_filter($args, function ($key) use ($connection) { return ! empty($connection[$key]); From 94d0caad634badca3c23214bba2961daf76b88c8 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Fri, 20 Nov 2020 20:01:11 +0530 Subject: [PATCH 048/599] typo fix --- 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 7d60cf272d52..5a50049773bb 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -169,7 +169,7 @@ protected function getSqlsrvArgs(array $connection) * @param array $connection * @return array|null */ - protected function getpgsqlEnv(array $connection) + protected function getPgsqlEnv(array $connection) { return array_merge(...$this->buildOptionalArguments([ 'username' => ['PGUSER' => $connection['username']], From eefb3f11a76a701c3c672e1ce5bde6c02c52dc18 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 20 Nov 2020 15:50:15 -0600 Subject: [PATCH 049/599] move method --- src/Illuminate/Http/RedirectResponse.php | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index 7f256a399396..32bb5fcffb95 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -145,6 +145,21 @@ public function withErrors($provider, $key = 'default') return $this; } + /** + * Parse the given errors into an appropriate value. + * + * @param \Illuminate\Contracts\Support\MessageProvider|array|string $provider + * @return \Illuminate\Support\MessageBag + */ + protected function parseErrors($provider) + { + if ($provider instanceof MessageProvider) { + return $provider->getMessageBag(); + } + + return new MessageBag((array) $provider); + } + /** * Add a fragment identifier to the URL. * @@ -167,21 +182,6 @@ public function withoutFragment() return $this->setTargetUrl(Str::before($this->getTargetUrl(), '#')); } - /** - * Parse the given errors into an appropriate value. - * - * @param \Illuminate\Contracts\Support\MessageProvider|array|string $provider - * @return \Illuminate\Support\MessageBag - */ - protected function parseErrors($provider) - { - if ($provider instanceof MessageProvider) { - return $provider->getMessageBag(); - } - - return new MessageBag((array) $provider); - } - /** * Get the original response content. * From 29f97ddedc956ed3a00db97fcab671bb87274e5d Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 21 Nov 2020 14:40:38 +0000 Subject: [PATCH 050/599] Fixed bad merge --- src/Illuminate/Mail/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 8d5ddf3f2b51..433271509886 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -38,7 +38,7 @@ }, "suggest": { "aws/aws-sdk-php": "Required to use the SES mail driver (^3.155).", - "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.3.1|^7.0.1).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.5.5|^7.0.1).", "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, "config": { From 15b951421fee1d03d35f538b20fc25bb69edef5b Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 21 Nov 2020 16:20:14 +0000 Subject: [PATCH 051/599] Avoid deprecated response create method (#35310) --- src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 903c201d709f..98d888c56cf5 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -322,7 +322,7 @@ protected function prepareResponse($request, Exception $e) */ protected function convertExceptionToResponse(Exception $e) { - return SymfonyResponse::create( + return new SymfonyResponse( $this->renderExceptionContent($e), $this->isHttpException($e) ? $e->getStatusCode() : 500, $this->isHttpException($e) ? $e->getHeaders() : [] From 380ef43ee974545b1c6e7d41a782e9cfefaeb15c Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sat, 21 Nov 2020 13:26:54 -0300 Subject: [PATCH 052/599] Use --no-owner and --no-acl with pg_restore command (#35309) Co-authored-by: Sean Frankruyter Co-authored-by: Sean Frankruyter --- src/Illuminate/Database/Schema/PostgresSchemaState.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index 8349a0b53083..179db6189c55 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -25,7 +25,7 @@ public function dump(Connection $connection, $path) })->implode(' '); $this->makeProcess( - $this->baseDumpCommand().' --no-owner --file=$LARAVEL_LOAD_PATH '.$excludedTables + $this->baseDumpCommand().' --file=$LARAVEL_LOAD_PATH '.$excludedTables )->mustRun($this->output, array_merge($this->baseVariables($this->connection->getConfig()), [ 'LARAVEL_LOAD_PATH' => $path, ])); @@ -39,7 +39,7 @@ public function dump(Connection $connection, $path) */ public function load($path) { - $command = 'PGPASSWORD=$LARAVEL_LOAD_PASSWORD pg_restore --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 b559b3e7c4995ef468b35e8a6117ef24fdeca053 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 21 Nov 2020 13:47:39 -0600 Subject: [PATCH 053/599] formatting --- src/Illuminate/Database/Console/DbCommand.php | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index 5a50049773bb..a854fc6f0da0 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -13,14 +13,14 @@ class DbCommand extends Command * * @var string */ - protected $signature = 'db {connection? : The database connection to use}'; + protected $signature = 'db {connection? : The database connection that should be used}'; /** * The console command description. * * @var string */ - protected $description = 'Drop into the database CLI.'; + protected $description = 'Start a new database CLI session'; /** * Execute the console command. @@ -32,8 +32,9 @@ public function handle() $connection = $this->getConnection(); (new Process( - array_merge([$this->getCommand($connection)], $this->getArgs($connection)), - null, $this->getEnv($connection) + array_merge([$this->getCommand($connection)], $this->commandArguments($connection)), + null, + $this->commandEnvironment($connection) ))->setTimeout(null)->setTty(true)->mustRun(function ($type, $buffer) { $this->output->write($buffer); }); @@ -53,7 +54,7 @@ public function getConnection() ]; if (empty($connection)) { - throw new UnexpectedValueException("Invalid database connection: [{$db}]."); + throw new UnexpectedValueException("Invalid database connection [{$db}]."); } return $connection; @@ -65,25 +66,25 @@ public function getConnection() * @param array $connection * @return array */ - public function getArgs(array $connection) + public function commandArguments(array $connection) { $driver = ucfirst($connection['driver']); - return $this->{"get{$driver}Args"}($connection); + return $this->{"get{$driver}Arguments"}($connection); } /** - * Get the environmental variables for the database client command. + * Get the environment variables for the database client command. * * @param array $connection * @return array|null */ - public function getEnv(array $connection) + public function commandEnvironment(array $connection) { $driver = ucfirst($connection['driver']); if (method_exists($this, "get{$driver}Env")) { - return $this->{"get{$driver}Env"}($connection); + return $this->{"get{$driver}Environment"}($connection); } return null; @@ -106,18 +107,18 @@ public function getCommand(array $connection) } /** - * Get the arguments for the mysql CLI. + * Get the arguments for the MySQL CLI. * * @param array $connection * @return array */ - protected function getMysqlArgs(array $connection) + protected function getMysqlArguments(array $connection) { return array_merge([ '--host='.$connection['host'], '--port='.$connection['port'], '--user='.$connection['username'], - ], $this->buildOptionalArguments([ + ], $this->getOptionalArguments([ 'password' => '--password='.$connection['password'], 'unix_socket' => '--socket='.$connection['unix_socket'], 'charset' => '--default-character-set='.$connection['charset'], @@ -125,23 +126,23 @@ protected function getMysqlArgs(array $connection) } /** - * Get the arguments for the pgsql CLI. + * Get the arguments for the Postgres CLI. * * @param array $connection * @return array */ - protected function getPgsqlArgs(array $connection) + protected function getPgsqlArguments(array $connection) { return [$connection['database']]; } /** - * Get the arguments for the sqlite CLI. + * Get the arguments for the SQLite CLI. * * @param array $connection * @return array */ - protected function getSqliteArgs(array $connection) + protected function getSqliteArguments(array $connection) { return [$connection['database']]; } @@ -152,9 +153,9 @@ protected function getSqliteArgs(array $connection) * @param array $connection * @return array */ - protected function getSqlsrvArgs(array $connection) + protected function getSqlsrvArguments(array $connection) { - return $this->buildOptionalArguments([ + return $this->getOptionalArguments([ 'database' => '-d '.$connection['database'], 'username' => '-U '.$connection['username'], 'password' => '-P '.$connection['password'], @@ -164,14 +165,14 @@ protected function getSqlsrvArgs(array $connection) } /** - * Get the environmental variables for the pgsql CLI. + * Get the environment variables for the Postgres CLI. * * @param array $connection * @return array|null */ - protected function getPgsqlEnv(array $connection) + protected function getPgsqlEnvironment(array $connection) { - return array_merge(...$this->buildOptionalArguments([ + return array_merge(...$this->getOptionalArguments([ 'username' => ['PGUSER' => $connection['username']], 'host' => ['PGHOST' => $connection['host']], 'port' => ['PGPORT' => $connection['port']], @@ -180,13 +181,13 @@ protected function getPgsqlEnv(array $connection) } /** - * Build optional arguments based on the connection configuration. + * Get the optional arguments based on the connection configuration. * * @param array $args * @param array $connection * @return array */ - protected function buildOptionalArguments(array $args, array $connection) + protected function getOptionalArguments(array $args, array $connection) { return array_values(array_filter($args, function ($key) use ($connection) { return ! empty($connection[$key]); From 699a23f82c057cb9b2039ffb167dcd016fb7a857 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 22 Nov 2020 13:05:47 +0200 Subject: [PATCH 054/599] [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 0c83b176b52a..9c8471465064 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.3...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.4...6.x) + + +## [v6.20.4 (2020-11-17)](https://github.com/laravel/framework/compare/v6.20.3...v6.20.4) + +### Fixed +- Fixed pivot restoration ([#35218](https://github.com/laravel/framework/pull/35218)) ## [v6.20.3 (2020-11-10)](https://github.com/laravel/framework/compare/v6.20.2...v6.20.3) From 740a0faea40920cc1880737fc49580aeb0165150 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 22 Nov 2020 13:38:30 +0200 Subject: [PATCH 055/599] [8.x] update changelog --- CHANGELOG-8.x.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index aad10ecab5e7..8978d2a5a7a2 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,33 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.14.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.15.0...8.x) + + +## [v8.15.0 (2020-11-17)](https://github.com/laravel/framework/compare/v8.14.0...v8.15.0) + +### Added +- Added lock support for file and null cache drivers ([#35139](https://github.com/laravel/framework/pull/35139), [a345185](https://github.com/laravel/framework/commit/a3451859d1cff45fba423cf577d00f5b2b648c7a)) +- Added a `doesntExpectOutput` method for console command testing ([#35160](https://github.com/laravel/framework/pull/35160), [c90fc5f](https://github.com/laravel/framework/commit/c90fc5f6b8e91e3f6b0f2f3a74cad7d8a49bc71b)) +- Added support of MorphTo relationship eager loading constraints ([#35190](https://github.com/laravel/framework/pull/35190)) +- Added `Illuminate\Http\ResponseTrait::withoutCookie()` ([e9483c4](https://github.com/laravel/framework/commit/e9483c441d5f0c8598d438d6024db8b1a7aa55fe)) +- Use dynamic app namespace in Eloquent Factory instead of App\ string ([#35204](https://github.com/laravel/framework/pull/35204), [4885bd2](https://github.com/laravel/framework/commit/4885bd2d4ecf79de175d5308569ab0d608e8f55b)) +- Added `read` / `unread` scopes to database notifications ([#35215](https://github.com/laravel/framework/pull/35215)) +- Added `classBasename()` method to `Stringable` ([#35219](https://github.com/laravel/framework/pull/35219)) +- Added before resolving callbacks to container ([#35228](https://github.com/laravel/framework/pull/35228)) +- Adds the possibility of testing file upload content ([#35231](https://github.com/laravel/framework/pull/35231)) +- Added lost connection messages for MySQL persistent connections ([#35224](https://github.com/laravel/framework/pull/35224)) +- Added Support DBAL v3.0 ([#35236](https://github.com/laravel/framework/pull/35236)) + +### Fixed +- Update MySqlSchemaState.php to support MariaDB dump ([#35184](https://github.com/laravel/framework/pull/35184)) +- Fixed pivot and morphpivot fresh and refresh methods ([#35193](https://github.com/laravel/framework/pull/35193)) +- Fixed pivot restoration ([#35218](https://github.com/laravel/framework/pull/35218)) + +### Changed +- Updated `EmailVerificationRequest.php` to check if user is not already verified ([#35174](https://github.com/laravel/framework/pull/35174)) +- Make `Validator::parseNamedParameters()` public ([#35183](https://github.com/laravel/framework/pull/35183)) +- Ignore max attempts if retryUntil is set in `queue:work` ([#35214](https://github.com/laravel/framework/pull/35214)) +- Explode string channels on `Illuminate/Log/LogManager::createStackDriver()` ([e5b86f2](https://github.com/laravel/framework/commit/e5b86f2efec2959fb0e85ad5ee5de18f430643c4)) ## [v8.14.0 (2020-11-10)](https://github.com/laravel/framework/compare/v8.13.0...v8.14.0) From 935dc474c47b52bc4bd7b2e1445d0d71df029ed0 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Mon, 23 Nov 2020 06:47:39 +0530 Subject: [PATCH 056/599] [8.x] Fix generic DetectsLostConnection string (#35323) --- src/Illuminate/Database/DetectsLostConnections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php index 72132c164df7..36b46099983f 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -40,7 +40,7 @@ protected function causedByLostConnection(Throwable $e) 'Communication link failure', 'connection is no longer usable', 'Login timeout expired', - 'Connection refused', + 'SQLSTATE[HY000] [2002] Connection refused', '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', From 056a03391b2e5fc82480b158b52d2372eb1b528f Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Sun, 22 Nov 2020 22:18:13 -0300 Subject: [PATCH 057/599] [8.x] fix SQL Server command generation (#35317) * fix SQL Server command generation * style fixes from StyleCI --- src/Illuminate/Database/Console/DbCommand.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Console/DbCommand.php b/src/Illuminate/Database/Console/DbCommand.php index a854fc6f0da0..ee6633557017 100644 --- a/src/Illuminate/Database/Console/DbCommand.php +++ b/src/Illuminate/Database/Console/DbCommand.php @@ -155,13 +155,13 @@ protected function getSqliteArguments(array $connection) */ protected function getSqlsrvArguments(array $connection) { - return $this->getOptionalArguments([ - 'database' => '-d '.$connection['database'], - 'username' => '-U '.$connection['username'], - 'password' => '-P '.$connection['password'], - 'host' => '-S tcp:'.$connection['host'] - .($connection['port'] ? ','.$connection['port'] : ''), - ], $connection); + return array_merge(...$this->getOptionalArguments([ + 'database' => ['-d', $connection['database']], + 'username' => ['-U', $connection['username']], + 'password' => ['-P', $connection['password']], + 'host' => ['-S', 'tcp:'.$connection['host'] + .($connection['port'] ? ','.$connection['port'] : ''), ], + ], $connection)); } /** From ff794323d5bbd909aa49733b541c09175276f638 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Sun, 22 Nov 2020 19:20:25 -0600 Subject: [PATCH 058/599] [8.x] Create Collection `chunkInto` method (#35295) * create Collection `chunkInto` method this methods defines the number of chunks we would like to end up with. it fills all non-last chunks first, before placing the remainder in the final chunk. * rename to `splitIn` * rename to `splitIn` forgot the LazyCollection. --- src/Illuminate/Collections/Collection.php | 11 +++++++++++ src/Illuminate/Collections/LazyCollection.php | 11 +++++++++++ tests/Support/SupportCollectionTest.php | 16 ++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 6a9e96f4ed54..ae772b70cbac 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1041,6 +1041,17 @@ public function split($numberOfGroups) return $groups; } + /** + * Split a collection into a certain number of groups, and fill the first groups completely. + * + * @param int $numberOfGroups + * @return static + */ + public function splitIn($numberOfGroups) + { + return $this->chunk(ceil($this->count() / $numberOfGroups)); + } + /** * Chunk the collection into chunks of the given size. * diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 55b8d97d8540..2384948f951a 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1057,6 +1057,17 @@ public function chunk($size) }); } + /** + * Split a collection into a certain number of groups, and fill the first groups completely. + * + * @param int $numberOfGroups + * @return static + */ + public function splitIn($numberOfGroups) + { + return $this->chunk(ceil($this->count() / $numberOfGroups)); + } + /** * Chunk the collection into chunks with a callback. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 851fe930d474..6faf65a1a3c2 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -1645,6 +1645,22 @@ public function testChunkWhenGivenLessThanZero($collection) ); } + /** + * @dataProvider collectionClassProvider + */ + public function testSplitIn($collection) + { + $data = new $collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + $data = $data->splitIn(3); + + $this->assertInstanceOf($collection, $data); + $this->assertInstanceOf($collection, $data->first()); + $this->assertCount(3, $data); + $this->assertEquals([1, 2, 3, 4], $data->get(0)->values()->toArray()); + $this->assertEquals([5, 6, 7, 8], $data->get(1)->values()->toArray()); + $this->assertEquals([9, 10], $data->get(2)->values()->toArray()); + } + /** * @dataProvider collectionClassProvider */ From eea60910898110381873bfb0755e054d84b8b013 Mon Sep 17 00:00:00 2001 From: albanh Date: Mon, 23 Nov 2020 15:50:56 +0000 Subject: [PATCH 059/599] update batches migration so options is mediumText to allow a greater number of jobs in a batch (#35335) --- src/Illuminate/Queue/Console/stubs/batches.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Console/stubs/batches.stub b/src/Illuminate/Queue/Console/stubs/batches.stub index 50d1480aebdb..d4fa380c7624 100644 --- a/src/Illuminate/Queue/Console/stubs/batches.stub +++ b/src/Illuminate/Queue/Console/stubs/batches.stub @@ -20,7 +20,7 @@ class Create{{tableClassName}}Table extends Migration $table->integer('pending_jobs'); $table->integer('failed_jobs'); $table->text('failed_job_ids'); - $table->text('options')->nullable(); + $table->mediumText('options')->nullable(); $table->integer('cancelled_at')->nullable(); $table->integer('created_at'); $table->integer('finished_at')->nullable(); From 781fcbc654bd3945fb79900d8012743d6412181c Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 24 Nov 2020 14:00:19 +0100 Subject: [PATCH 060/599] Make DownCommand instance available to prerendered view Having the command instance available to the pre-rendered view gives the possibility to, eg. see if the retry option was set, so you can add a meta-refresh tag to your view. --- src/Illuminate/Foundation/Console/DownCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/DownCommand.php b/src/Illuminate/Foundation/Console/DownCommand.php index 94c5906531d6..1779ad630cf2 100644 --- a/src/Illuminate/Foundation/Console/DownCommand.php +++ b/src/Illuminate/Foundation/Console/DownCommand.php @@ -100,7 +100,7 @@ protected function prerenderView() { (new RegisterErrorViewPaths)(); - return view($this->option('render'))->render(); + return view($this->option('render'),['command' => $this])->render(); } /** From 8bbbe42052a33d87aae95393d642e5f5e5fe3422 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 24 Nov 2020 14:53:00 +0100 Subject: [PATCH 061/599] Update DownCommand.php --- src/Illuminate/Foundation/Console/DownCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/DownCommand.php b/src/Illuminate/Foundation/Console/DownCommand.php index 1779ad630cf2..4519fc1b3d81 100644 --- a/src/Illuminate/Foundation/Console/DownCommand.php +++ b/src/Illuminate/Foundation/Console/DownCommand.php @@ -100,7 +100,7 @@ protected function prerenderView() { (new RegisterErrorViewPaths)(); - return view($this->option('render'),['command' => $this])->render(); + return view($this->option('render'), ['command' => $this])->render(); } /** From eb3e262c870739a6e9705b851e0066b3473eed2b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 24 Nov 2020 08:48:34 -0600 Subject: [PATCH 062/599] fix route model binding on cached closure routes --- src/Illuminate/Routing/ImplicitRouteBinding.php | 1 - src/Illuminate/Routing/Route.php | 3 +-- src/Illuminate/Routing/RouteAction.php | 12 ++++++++++++ src/Illuminate/Routing/RouteSignatureParameters.php | 10 +++++++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Routing/ImplicitRouteBinding.php b/src/Illuminate/Routing/ImplicitRouteBinding.php index c6d1953462a6..0114f1ac7986 100644 --- a/src/Illuminate/Routing/ImplicitRouteBinding.php +++ b/src/Illuminate/Routing/ImplicitRouteBinding.php @@ -36,7 +36,6 @@ public static function resolveForRoute($container, $route) $instance = $container->make(Reflector::getParameterClassName($parameter)); $parent = $route->parentOfParameter($parameterName); - if ($parent instanceof UrlRoutable && in_array($parameterName, array_keys($route->bindingFields()))) { if (! $model = $parent->resolveChildRouteBinding( $parameterName, $parameterValue, $route->bindingFieldFor($parameterName) diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index f67756d353a0..37ba1aaa4236 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -238,8 +238,7 @@ protected function runCallable() */ protected function isSerializedClosure() { - return is_string($this->action['uses']) && - Str::startsWith($this->action['uses'], 'C:32:"Opis\\Closure\\SerializableClosure') !== false; + return RouteAction::containsSerializedClosure($this->action); } /** diff --git a/src/Illuminate/Routing/RouteAction.php b/src/Illuminate/Routing/RouteAction.php index 9d7eb76a85d8..5a8188e27bbd 100644 --- a/src/Illuminate/Routing/RouteAction.php +++ b/src/Illuminate/Routing/RouteAction.php @@ -94,4 +94,16 @@ protected static function makeInvokable($action) return $action.'@__invoke'; } + + /** + * Determine if the given array actions contains a serialized Closure. + * + * @param array $action + * @return bool + */ + public static function containsSerializedClosure(array $action) + { + return is_string($action['uses']) && + Str::startsWith($action['uses'], 'C:32:"Opis\\Closure\\SerializableClosure') !== false; + } } diff --git a/src/Illuminate/Routing/RouteSignatureParameters.php b/src/Illuminate/Routing/RouteSignatureParameters.php index bd7e932fb316..03d3137b511c 100644 --- a/src/Illuminate/Routing/RouteSignatureParameters.php +++ b/src/Illuminate/Routing/RouteSignatureParameters.php @@ -18,9 +18,13 @@ class RouteSignatureParameters */ public static function fromAction(array $action, $subClass = null) { - $parameters = is_string($action['uses']) - ? static::fromClassMethodString($action['uses']) - : (new ReflectionFunction($action['uses']))->getParameters(); + $callback = RouteAction::containsSerializedClosure($action) + ? unserialize($action['uses'])->getClosure() + : $action['uses']; + + $parameters = is_string($callback) + ? static::fromClassMethodString($callback) + : (new ReflectionFunction($callback))->getParameters(); return is_null($subClass) ? $parameters : array_filter($parameters, function ($p) use ($subClass) { return Reflector::isParameterSubclassOf($p, $subClass); From 10ad064e0041746350aa68b50afb13c2369677f9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 24 Nov 2020 08:51:21 -0600 Subject: [PATCH 063/599] add back spacing --- src/Illuminate/Routing/ImplicitRouteBinding.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Routing/ImplicitRouteBinding.php b/src/Illuminate/Routing/ImplicitRouteBinding.php index 0114f1ac7986..c6d1953462a6 100644 --- a/src/Illuminate/Routing/ImplicitRouteBinding.php +++ b/src/Illuminate/Routing/ImplicitRouteBinding.php @@ -36,6 +36,7 @@ public static function resolveForRoute($container, $route) $instance = $container->make(Reflector::getParameterClassName($parameter)); $parent = $route->parentOfParameter($parameterName); + if ($parent instanceof UrlRoutable && in_array($parameterName, array_keys($route->bindingFields()))) { if (! $model = $parent->resolveChildRouteBinding( $parameterName, $parameterValue, $route->bindingFieldFor($parameterName) From af49b8e48ff5200df4d72c1fe5925446bbb5f26c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 24 Nov 2020 16:16:10 +0100 Subject: [PATCH 064/599] [8.x] Tests for route closures (#35345) * Test RouteAction * Add RouteSignatureParameters test --- tests/Routing/RouteActionTest.php | 29 +++++++++++++++++++ .../Routing/RouteSignatureParametersTest.php | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/Routing/RouteActionTest.php create mode 100644 tests/Routing/RouteSignatureParametersTest.php diff --git a/tests/Routing/RouteActionTest.php b/tests/Routing/RouteActionTest.php new file mode 100644 index 000000000000..4b256ff68183 --- /dev/null +++ b/tests/Routing/RouteActionTest.php @@ -0,0 +1,29 @@ + serialize(new SerializableClosure(function (RouteActionUser $user) { + return $user; + }))]; + + $this->assertTrue(RouteAction::containsSerializedClosure($action)); + + $action = ['uses' => 'FooController@index']; + + $this->assertFalse(RouteAction::containsSerializedClosure($action)); + } +} + +class RouteActionUser extends Model +{ + // +} diff --git a/tests/Routing/RouteSignatureParametersTest.php b/tests/Routing/RouteSignatureParametersTest.php new file mode 100644 index 000000000000..8edee56cffd7 --- /dev/null +++ b/tests/Routing/RouteSignatureParametersTest.php @@ -0,0 +1,29 @@ + serialize(new SerializableClosure($callable = function (SignatureParametersUser $user) { + return $user; + }))]; + + $parameters = RouteSignatureParameters::fromAction($action); + + $this->assertContainsOnlyInstancesOf(ReflectionParameter::class, $parameters); + $this->assertSame('user', $parameters[0]->getName()); + } +} + +class SignatureParametersUser extends Model +{ + // +} From b4de11725cc1e4157938864961deeaa889b54d46 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 24 Nov 2020 16:29:10 +0100 Subject: [PATCH 065/599] Add test for implicit binding (#35346) --- tests/Routing/ImplicitRouteBindingTest.php | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/Routing/ImplicitRouteBindingTest.php diff --git a/tests/Routing/ImplicitRouteBindingTest.php b/tests/Routing/ImplicitRouteBindingTest.php new file mode 100644 index 000000000000..81b536f44d56 --- /dev/null +++ b/tests/Routing/ImplicitRouteBindingTest.php @@ -0,0 +1,35 @@ + function (ImplicitRouteBindingUser $user) { + return $user; + }]; + + $route = new Route('GET', '/test', $action); + $route->parameters = ['user' => new ImplicitRouteBindingUser]; + + $route->prepareForSerialization(); + + $container = Container::getInstance(); + + ImplicitRouteBinding::resolveForRoute($container, $route); + + $this->assertTrue(true); + } +} + +class ImplicitRouteBindingUser extends Model +{ + // +} From 1ba4354b0263a7f97d1de1323aab21f73b38dc4d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 24 Nov 2020 10:12:27 -0600 Subject: [PATCH 066/599] 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 51e84ad962dd..a0c436f2d2e3 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.4'; + const VERSION = '6.20.5'; /** * The base path for the Laravel installation. From 885937b49a44efec4da0d054400357da3066ac9e Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 24 Nov 2020 19:29:12 +0200 Subject: [PATCH 067/599] [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 9c8471465064..ae564658b926 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.4...6.x) +## [Unreleased](https://github.com/laravel/framework/compare/v6.20.5...6.x) + + +## [v6.20.5 (2020-11-24)](https://github.com/laravel/framework/compare/v6.20.4...v6.20.5) + +### Fixed +- Fixing BroadcastException message in PusherBroadcaster@broadcast ([#35290](https://github.com/laravel/framework/pull/35290)) +- Fixed generic DetectsLostConnection string ([#35323](https://github.com/laravel/framework/pull/35323)) + +### Changed +- Updated `aws/aws-sdk-php` suggest to `^3.155` ([#35267](https://github.com/laravel/framework/pull/35267)) ## [v6.20.4 (2020-11-17)](https://github.com/laravel/framework/compare/v6.20.3...v6.20.4) From 44a86637d2ef021c07b6847e785084b87cbcfba2 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 24 Nov 2020 20:32:33 +0200 Subject: [PATCH 068/599] [8.x] update changelog --- CHANGELOG-8.x.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md index 8978d2a5a7a2..55e5ebb05309 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -1,6 +1,39 @@ # Release Notes for 8.x -## [Unreleased](https://github.com/laravel/framework/compare/v8.15.0...8.x) +## [Unreleased](https://github.com/laravel/framework/compare/v8.16.0...8.x) + + +## [v8.16.0 (2020-11-17)](https://github.com/laravel/framework/compare/v8.15.0...v8.16.0) + +### Added +- Added `Illuminate\Console\Concerns\InteractsWithIO::withProgressBar()` ([4e52a60](https://github.com/laravel/framework/commit/4e52a606e91619f6082ed8d46f8d64f9d4dbd0b2), [169fd2b](https://github.com/laravel/framework/commit/169fd2b5156650a067aa77a38681875d2a6c5e57)) +- Added `Illuminate\Console\Concerns\CallsCommands::callSilently()` as alias for `callSilent()` ([7f3101b](https://github.com/laravel/framework/commit/7f3101bf6e8a0f048a243a55be7fc79eb359b609), [0294433](https://github.com/laravel/framework/commit/029443349294e3b6e7bebfe9c23a51a9821ec497)) +- Added option to release unique job locks before processing ([#35255](https://github.com/laravel/framework/pull/35255), [b53f13e](https://github.com/laravel/framework/commit/b53f13ef6c8625176defcb83d2fb8d4d5887d068)) +- Added ably broadcaster ([e0f3f8e](https://github.com/laravel/framework/commit/e0f3f8e8241e1ea34a3a3b8c543871cdc00290bf), [6381aa9](https://github.com/laravel/framework/commit/6381aa994756429156b7376e98606458b052b1d7)) +- Added ability to define table name as default morph type ([#35257](https://github.com/laravel/framework/pull/35257)) +- Allow overriding the MySQL server version for database queue driver ([#35263](https://github.com/laravel/framework/pull/35263)) +- Added `Illuminate\Foundation\Testing\Wormhole::back()` ([#35261](https://github.com/laravel/framework/pull/35261)) +- Support delaying notifications per channel ([#35273](https://github.com/laravel/framework/pull/35273)) +- Allow sorting on multiple criteria ([#35277](https://github.com/laravel/framework/pull/35277), [53eb307](https://github.com/laravel/framework/commit/53eb307fea077299d409adf3ba0307a8fda4c4d1)) +- Added `Illuminate/Database/Console/DbCommand.php` command ([#35304](https://github.com/laravel/framework/pull/35304), [b559b3e](https://github.com/laravel/framework/commit/b559b3e7c4995ef468b35e8a6117ef24fdeca053)) +- Added Collections `splitIn` methods ([#35295](https://github.com/laravel/framework/pull/35295)) + +### Fixed +- Fixed rendering of notifications with config custom theme ([325a335](https://github.com/laravel/framework/commit/325a335ccf45426eabb27131ed48aa6114434c99)) +- Fixing BroadcastException message in PusherBroadcaster@broadcast ([#35290](https://github.com/laravel/framework/pull/35290)) +- Fixed generic DetectsLostConnection string ([#35323](https://github.com/laravel/framework/pull/35323)) +- Fixed SQL Server command generation ([#35317](https://github.com/laravel/framework/pull/35317)) +- Fixed route model binding on cached closure routes ([eb3e262](https://github.com/laravel/framework/commit/eb3e262c870739a6e9705b851e0066b3473eed2b)) + +### Changed +- Disable CSRF on broadcast route ([acb4b77](https://github.com/laravel/framework/commit/acb4b77adc6e257e132e3b036abe1ec88885cfb7)) +- Easily set a null cache driver ([#35262](https://github.com/laravel/framework/pull/35262)) +- Updated `aws/aws-sdk-php` suggest to `^3.155` ([#35267](https://github.com/laravel/framework/pull/35267)) +- Ensure ShouldBeUniqueUntilProcessing job lock is released once ([#35270](https://github.com/laravel/framework/pull/35270)) +- Rename qualifyColumn to qualifyPivotColumn in BelongsToMany & MorphToMany ([#35276](https://github.com/laravel/framework/pull/35276)) +- Check if AsPivot trait is used instead of Pivot Model in `Illuminate\Database\Eloquent\Relations\BelongsToMany` ([#35271](https://github.com/laravel/framework/pull/35271)) +- Avoid no-op database query in Model::destroy() with empty ids ([#35294](https://github.com/laravel/framework/pull/35294)) +- Use --no-owner and --no-acl with pg_restore ([#35309](https://github.com/laravel/framework/pull/35309)) ## [v8.15.0 (2020-11-17)](https://github.com/laravel/framework/compare/v8.14.0...v8.15.0) From a0b8812ee35aef3310cc8bf3544a2e8d7bb68a4f Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 25 Nov 2020 09:19:50 +0100 Subject: [PATCH 069/599] Update DownCommand.php As per Taylor's comment, now only passing along the Down command's options to the pre-rendering view, instead of the entire command instance. --- src/Illuminate/Foundation/Console/DownCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/DownCommand.php b/src/Illuminate/Foundation/Console/DownCommand.php index 4519fc1b3d81..390039132608 100644 --- a/src/Illuminate/Foundation/Console/DownCommand.php +++ b/src/Illuminate/Foundation/Console/DownCommand.php @@ -100,7 +100,7 @@ protected function prerenderView() { (new RegisterErrorViewPaths)(); - return view($this->option('render'), ['command' => $this])->render(); + return view($this->option('render'), ['options' => $this->options()])->render(); } /** From c6e8357e19b10a800df8a67446f23310f4e83d1f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 25 Nov 2020 09:00:20 -0600 Subject: [PATCH 070/599] fix reflection exceptions --- src/Illuminate/Routing/Router.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 1828e52105fd..f1b61dc74dcf 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -715,10 +715,14 @@ public function gatherRouteMiddleware(Route $route) return true; } + if (! class_exists($name)) { + return false; + } + $reflection = new ReflectionClass($name); return collect($excluded)->contains(function ($exclude) use ($reflection) { - return $reflection->isSubclassOf($exclude); + return class_exists($exclude) && $reflection->isSubclassOf($exclude); }); })->values(); From f7dfc22e6c42e9ed4dda14c05814349af6943206 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 25 Nov 2020 09:01:02 -0600 Subject: [PATCH 071/599] 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 8d664a304c8d..ac87f53de5b5 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.16.0'; + const VERSION = '8.16.1'; /** * The base path for the Laravel installation. From 5535c6b4eb9e3217d974c41fb3f159d7498598ef Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 25 Nov 2020 17:13:24 +0200 Subject: [PATCH 072/599] transactions manager --- .../Database/DatabaseTransactionRecord.php | 73 ++++++++ .../Database/DatabaseTransactionsManager.php | 92 +++++++++ .../DatabaseTransactionsManagerTest.php | 174 ++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100755 src/Illuminate/Database/DatabaseTransactionRecord.php create mode 100755 src/Illuminate/Database/DatabaseTransactionsManager.php create mode 100755 tests/Database/DatabaseTransactionsManagerTest.php diff --git a/src/Illuminate/Database/DatabaseTransactionRecord.php b/src/Illuminate/Database/DatabaseTransactionRecord.php new file mode 100755 index 000000000000..b4556d8fc305 --- /dev/null +++ b/src/Illuminate/Database/DatabaseTransactionRecord.php @@ -0,0 +1,73 @@ +connection = $connection; + $this->level = $level; + } + + /** + * Register a callback to be executed after committing. + * + * @param callable $callback + * @return void + */ + public function addCallback($callback) + { + $this->callbacks[] = $callback; + } + + /** + * Execute all of the callbacks. + * + * @return void + */ + public function executeCallbacks() + { + foreach ($this->callbacks as $callback) { + call_user_func($callback); + } + } + + /** + * Get all of the callbacks. + * + * @return array + */ + public function getCallbacks() + { + return $this->callbacks; + } +} diff --git a/src/Illuminate/Database/DatabaseTransactionsManager.php b/src/Illuminate/Database/DatabaseTransactionsManager.php new file mode 100755 index 000000000000..e4f2f5fbb567 --- /dev/null +++ b/src/Illuminate/Database/DatabaseTransactionsManager.php @@ -0,0 +1,92 @@ +transactions = collect(); + } + + /** + * Start a new database transaction. + * + * @param string $connection + * @param int $level + * @return void + */ + public function begin($connection, $level) + { + $this->transactions->push( + new DatabaseTransactionRecord($connection, $level) + ); + } + + /** + * Rollback the active database transaction. + * + * @param string $connection + * @param int $level + * @return void + */ + public function rollback($connection, $level) + { + $this->transactions = $this->transactions->reject(function ($transaction) use ($connection, $level) { + return $transaction->connection == $connection && + $transaction->level >= $level; + })->values(); + } + + /** + * Commit the active database transaction. + * + * @param string $connection + * @return void + */ + public function commit($connection) + { + $this->transactions = $this->transactions->reject(function ($transaction) use ($connection) { + if ($transaction->connection == $connection) { + $transaction->executeCallbacks(); + + return true; + } + + return false; + })->values(); + } + + /** + * Register a transaction callback. + * + * @param callable $callback + * @return void. + */ + public function addCallback($callback) + { + $this->transactions->last()->addCallback($callback); + } + + /** + * Get all the transactions. + * + * @return \Illuminate\Support\Collection + */ + public function getTransactions() + { + return $this->transactions; + } +} diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php new file mode 100755 index 000000000000..231a8ac9db55 --- /dev/null +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -0,0 +1,174 @@ +begin('default', 1); + $manager->begin('default', 2); + $manager->begin('admin', 1); + + $this->assertCount(3, $manager->getTransactions()); + $this->assertEquals('default', $manager->getTransactions()[0]->connection); + $this->assertEquals(1, $manager->getTransactions()[0]->level); + $this->assertEquals('default', $manager->getTransactions()[1]->connection); + $this->assertEquals(2, $manager->getTransactions()[1]->level); + $this->assertEquals('admin', $manager->getTransactions()[2]->connection); + $this->assertEquals(1, $manager->getTransactions()[2]->level); + } + + public function testRollingBackTransactions() + { + $manager = (new DatabaseTransactionsManager()); + + $manager->begin('default', 1); + $manager->begin('default', 2); + $manager->begin('admin', 1); + + $manager->rollback('default', 2); + + $this->assertCount(2, $manager->getTransactions()); + + $this->assertEquals('default', $manager->getTransactions()[0]->connection); + $this->assertEquals(1, $manager->getTransactions()[0]->level); + + $this->assertEquals('admin', $manager->getTransactions()[1]->connection); + $this->assertEquals(1, $manager->getTransactions()[1]->level); + } + + public function testRollingBackTransactionsAllTheWay() + { + $manager = (new DatabaseTransactionsManager()); + + $manager->begin('default', 1); + $manager->begin('default', 2); + $manager->begin('admin', 1); + + $manager->rollback('default', 1); + + $this->assertCount(1, $manager->getTransactions()); + + $this->assertEquals('admin', $manager->getTransactions()[0]->connection); + $this->assertEquals(1, $manager->getTransactions()[0]->level); + } + + public function testCommittingTransactions() + { + $manager = (new DatabaseTransactionsManager()); + + $manager->begin('default', 1); + $manager->begin('default', 2); + $manager->begin('admin', 1); + + $manager->commit('default'); + + $this->assertCount(1, $manager->getTransactions()); + + $this->assertEquals('admin', $manager->getTransactions()[0]->connection); + $this->assertEquals(1, $manager->getTransactions()[0]->level); + } + + public function testCallbacksAreAddedToTheCurrentTransaction() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager()); + + $manager->begin('default', 1); + + $manager->addCallback(function () use (&$callbacks) { + + }); + + $manager->begin('default', 2); + + $manager->begin('admin', 1); + + $manager->addCallback(function () use (&$callbacks) { + + }); + + $this->assertCount(1, $manager->getTransactions()[0]->getCallbacks()); + $this->assertCount(0, $manager->getTransactions()[1]->getCallbacks()); + $this->assertCount(1, $manager->getTransactions()[2]->getCallbacks()); + } + + public function testCommittingTransactionsExecutesCallbacks() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager()); + + $manager->begin('default', 1); + + $manager->addCallback(function () use (&$callbacks) { + $callbacks[] = ['default', 1]; + }); + + $manager->begin('default', 2); + + $manager->addCallback(function () use (&$callbacks) { + $callbacks[] = ['default', 2]; + }); + + $manager->begin('admin', 1); + + $manager->commit('default'); + + $this->assertCount(2, $callbacks); + $this->assertEquals(['default', 1], $callbacks[0]); + $this->assertEquals(['default', 2], $callbacks[1]); + } + + public function testCommittingExecutesOnlyCallbacksOfTheConnection() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager()); + + $manager->begin('default', 1); + + $manager->addCallback(function () use (&$callbacks) { + $callbacks[] = ['default', 1]; + }); + + $manager->begin('default', 2); + $manager->begin('admin', 1); + + $manager->addCallback(function () use (&$callbacks) { + $callbacks[] = ['admin', 1]; + }); + + $manager->commit('default'); + + $this->assertCount(1, $callbacks); + $this->assertEquals(['default', 1], $callbacks[0]); + } +} From 04897e82a1cba6e869e8d8b5ef04ab56e8cf0095 Mon Sep 17 00:00:00 2001 From: Alexey Shirokov <40300551+demiurge-ash@users.noreply.github.com> Date: Wed, 25 Nov 2020 18:37:25 +0300 Subject: [PATCH 073/599] [8.x] Fix update date (#35356) * Fix date * [8.x] Fix update date --- 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 55e5ebb05309..6b5223d70d24 100644 --- a/CHANGELOG-8.x.md +++ b/CHANGELOG-8.x.md @@ -3,7 +3,7 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v8.16.0...8.x) -## [v8.16.0 (2020-11-17)](https://github.com/laravel/framework/compare/v8.15.0...v8.16.0) +## [v8.16.0 (2020-11-24)](https://github.com/laravel/framework/compare/v8.15.0...v8.16.0) ### Added - Added `Illuminate\Console\Concerns\InteractsWithIO::withProgressBar()` ([4e52a60](https://github.com/laravel/framework/commit/4e52a606e91619f6082ed8d46f8d64f9d4dbd0b2), [169fd2b](https://github.com/laravel/framework/commit/169fd2b5156650a067aa77a38681875d2a6c5e57)) From 0bb7fe4758d617b07b84f6fabfcfe2ca2cdb0964 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 25 Nov 2020 10:23:27 -0600 Subject: [PATCH 074/599] set default value on cloud driver' --- src/Illuminate/Filesystem/FilesystemManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index f9d47250d08f..5575439418fc 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -326,7 +326,7 @@ public function getDefaultDriver() */ public function getDefaultCloudDriver() { - return $this->app['config']['filesystems.cloud']; + return $this->app['config']['filesystems.cloud'] ?? 's3'; } /** From d09cd161f3789b125fe2de7df191eef5cb7dda0e Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 25 Nov 2020 18:26:55 +0200 Subject: [PATCH 075/599] register the transaction manager into the connection instance --- .../Database/Concerns/ManagesTransactions.php | 32 +++++++++++++++++++ src/Illuminate/Database/Connection.php | 30 +++++++++++++++++ src/Illuminate/Database/DatabaseManager.php | 4 +++ .../Database/DatabaseServiceProvider.php | 4 +++ .../Database/DatabaseTransactionsManager.php | 2 +- .../DatabaseTransactionsManagerTest.php | 4 +-- 6 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index 1dd4475290d6..7bf29ebef026 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -42,6 +42,10 @@ public function transaction(Closure $callback, $attempts = 1) try { if ($this->transactions == 1) { $this->getPdo()->commit(); + + if ($this->transactionsManager) { + $this->transactionsManager->commit($this->getName()); + } } $this->transactions = max(0, $this->transactions - 1); @@ -78,6 +82,12 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma $this->transactions > 1) { $this->transactions--; + if ($this->transactionsManager) { + $this->transactionsManager->rollback( + $this->getName(), $this->transactions + ); + } + throw $e; } @@ -107,6 +117,12 @@ public function beginTransaction() $this->transactions++; + if ($this->transactionsManager) { + $this->transactionsManager->begin( + $this->getName(), $this->transactions + ); + } + $this->fireConnectionEvent('beganTransaction'); } @@ -176,6 +192,10 @@ public function commit() { if ($this->transactions == 1) { $this->getPdo()->commit(); + + if ($this->transactionsManager) { + $this->transactionsManager->commit($this->getName()); + } } $this->transactions = max(0, $this->transactions - 1); @@ -241,6 +261,12 @@ public function rollBack($toLevel = null) $this->transactions = $toLevel; + if ($this->transactionsManager) { + $this->transactionsManager->rollback( + $this->getName(), $this->transactions + ); + } + $this->fireConnectionEvent('rollingBack'); } @@ -275,6 +301,12 @@ protected function handleRollBackException(Throwable $e) { if ($this->causedByLostConnection($e)) { $this->transactions = 0; + + if ($this->transactionsManager) { + $this->transactionsManager->rollback( + $this->getName(), $this->transactions + ); + } } throw $e; diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 98f12639713e..ea8c41e908e8 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -112,6 +112,13 @@ class Connection implements ConnectionInterface */ protected $transactions = 0; + /** + * The transaction manager instance. + * + * @var \Illuminate\Database\DatabaseTransactionsManager + */ + protected $transactionsManager; + /** * Indicates if changes have been made to the database. * @@ -1151,6 +1158,29 @@ public function unsetEventDispatcher() $this->events = null; } + /** + * Set the transaction manager instance on the connection. + * + * @param \Illuminate\Database\DatabaseTransactionsManager $manager + * @return $this + */ + public function setTransactionManager($manager) + { + $this->transactionsManager = $manager; + + return $this; + } + + /** + * Unset the event transaction manager for this connection. + * + * @return void + */ + public function unsetTransactionManager() + { + $this->transactionsManager = null; + } + /** * Determine if the connection is in a "dry run". * diff --git a/src/Illuminate/Database/DatabaseManager.php b/src/Illuminate/Database/DatabaseManager.php index d558d1665fc8..7f8fdf921fb3 100755 --- a/src/Illuminate/Database/DatabaseManager.php +++ b/src/Illuminate/Database/DatabaseManager.php @@ -174,6 +174,10 @@ protected function configure(Connection $connection, $type) $connection->setEventDispatcher($this->app['events']); } + if ($this->app->bound('db.transactions')) { + $connection->setTransactionManager($this->app['db.transactions']); + } + // Here we'll set a reconnector callback. This reconnector can be any callable // so we will set a Closure to reconnect from this manager with the name of // the connection, which will allow us to reconnect from the connections. diff --git a/src/Illuminate/Database/DatabaseServiceProvider.php b/src/Illuminate/Database/DatabaseServiceProvider.php index f64f8f2683d5..d8f87227ae07 100755 --- a/src/Illuminate/Database/DatabaseServiceProvider.php +++ b/src/Illuminate/Database/DatabaseServiceProvider.php @@ -71,6 +71,10 @@ protected function registerConnectionServices() $this->app->bind('db.connection', function ($app) { return $app['db']->connection(); }); + + $this->app->singleton('db.transactions', function ($app) { + return new DatabaseTransactionsManager(); + }); } /** diff --git a/src/Illuminate/Database/DatabaseTransactionsManager.php b/src/Illuminate/Database/DatabaseTransactionsManager.php index e4f2f5fbb567..37be16448bea 100755 --- a/src/Illuminate/Database/DatabaseTransactionsManager.php +++ b/src/Illuminate/Database/DatabaseTransactionsManager.php @@ -46,7 +46,7 @@ public function rollback($connection, $level) { $this->transactions = $this->transactions->reject(function ($transaction) use ($connection, $level) { return $transaction->connection == $connection && - $transaction->level >= $level; + $transaction->level > $level; })->values(); } diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php index 231a8ac9db55..4d92819e3996 100755 --- a/tests/Database/DatabaseTransactionsManagerTest.php +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -52,7 +52,7 @@ public function testRollingBackTransactions() $manager->begin('default', 2); $manager->begin('admin', 1); - $manager->rollback('default', 2); + $manager->rollback('default', 1); $this->assertCount(2, $manager->getTransactions()); @@ -71,7 +71,7 @@ public function testRollingBackTransactionsAllTheWay() $manager->begin('default', 2); $manager->begin('admin', 1); - $manager->rollback('default', 1); + $manager->rollback('default', 0); $this->assertCount(1, $manager->getTransactions()); From c6f14c6da9c36219455ae66bb853cfbc27d3b24d Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 26 Nov 2020 09:46:20 +0200 Subject: [PATCH 076/599] use arr wrap with backoff --- src/Illuminate/Queue/Queue.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index e9a98c663869..2cc64a60e3e4 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -5,6 +5,7 @@ use Closure; use DateTimeInterface; use Illuminate\Container\Container; +use Illuminate\Support\Arr; use Illuminate\Support\InteractsWithTime; use Illuminate\Support\Str; @@ -173,7 +174,7 @@ public function getJobBackoff($job) return; } - return collect($job->backoff ?? $job->backoff()) + return collect(Arr::wrap($job->backoff ?? $job->backoff())) ->map(function ($backoff) { return $backoff instanceof DateTimeInterface ? $this->secondsUntil($backoff) : $backoff; From fc1f3e3fa117f82bc5669c6cc23f8db87651d1c4 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 26 Nov 2020 14:47:02 +0200 Subject: [PATCH 077/599] add tests --- tests/Database/DatabaseTransactionsTest.php | 257 ++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 tests/Database/DatabaseTransactionsTest.php diff --git a/tests/Database/DatabaseTransactionsTest.php b/tests/Database/DatabaseTransactionsTest.php new file mode 100644 index 000000000000..0432d750656f --- /dev/null +++ b/tests/Database/DatabaseTransactionsTest.php @@ -0,0 +1,257 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ], 'second_connection'); + + $db->setAsGlobal(); + + $this->createSchema(); + } + + protected function createSchema() + { + foreach (['default', 'second_connection'] as $connection) { + $this->schema($connection)->create('users', function ($table) { + $table->increments('id'); + $table->string('name')->nullable(); + $table->string('value')->nullable(); + }); + } + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + foreach (['default', 'second_connection'] as $connection) { + $this->schema($connection)->drop('users'); + } + + m::close(); + } + + public function testTransactionIsRecordedAndCommitted() + { + $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager->shouldReceive('begin')->once()->with('default', 1); + $transactionManager->shouldReceive('commit')->once()->with('default'); + + $this->connection()->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + }); + } + + public function testTransactionIsRecordedAndCommittedUsingTheSeparateMethods() + { + $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager->shouldReceive('begin')->once()->with('default', 1); + $transactionManager->shouldReceive('commit')->once()->with('default'); + + $this->connection()->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + $this->connection()->beginTransaction(); + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + $this->connection()->commit(); + } + + public function testNestedTransactionIsRecordedAndCommitted() + { + $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'); + + $this->connection()->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + }); + }); + } + + public function testNestedTransactionIsRecordeForDifferentConnectionsdAndCommitted() + { + $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); + $transactionManager->shouldReceive('commit')->once()->with('default'); + $transactionManager->shouldReceive('commit')->once()->with('second_connection'); + + $this->connection()->setTransactionManager($transactionManager); + $this->connection('second_connection')->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + $this->connection('second_connection')->transaction(function() use ($transactionManager){ + $this->connection('second_connection')->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + $this->connection('second_connection')->transaction(function() use ($transactionManager){ + $this->connection('second_connection')->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + }); + }); + }); + } + + public function testTransactionIsRolledBack() + { + $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager->shouldReceive('begin')->once()->with('default', 1); + $transactionManager->shouldReceive('rollback')->once()->with('default', 0); + $transactionManager->shouldNotReceive('commit'); + + $this->connection()->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + try { + $this->connection()->transaction(function () use ($transactionManager) { + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + throw new \Exception; + }); + } catch (\Throwable $e) { + + } + } + + public function testTransactionIsRolledBackUsingSeparateMethods() + { + $transactionManager = m::mock(new DatabaseTransactionsManager()); + $transactionManager->shouldReceive('begin')->once()->with('default', 1); + $transactionManager->shouldReceive('rollback')->once()->with('default', 0); + $transactionManager->shouldNotReceive('commit'); + + $this->connection()->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + $this->connection()->beginTransaction(); + + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + $this->connection()->rollBack(); + } + + public function testNestedTransactionsAreRolledBack() + { + $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); + $transactionManager->shouldReceive('rollback')->once()->with('default', 0); + $transactionManager->shouldNotReceive('commit'); + + $this->connection()->setTransactionManager($transactionManager); + + $this->connection()->table('users')->insert([ + 'name' => 'zain', 'value' => 1 + ]); + + try { + $this->connection()->transaction(function () use ($transactionManager) { + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + $this->connection()->transaction(function () use ($transactionManager) { + $this->connection()->table('users')->where(['name' => 'zain'])->update([ + 'value' => 2 + ]); + + throw new \Exception; + }); + }); + } catch (\Throwable $e) { + + } + } + + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema($connection = 'default') + { + return $this->connection($connection)->getSchemaBuilder(); + } + + public function connection($name = 'default') + { + return DB::connection($name); + } +} From 923e277ad2e68cac3c1e2b1d4d259e480536026c Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 26 Nov 2020 15:11:40 +0200 Subject: [PATCH 078/599] add withinTransaction --- .../Database/Concerns/ManagesTransactions.php | 15 +++++++++++++++ .../Database/DatabaseTransactionsManager.php | 6 +++++- .../Database/DatabaseTransactionsManagerTest.php | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index 7bf29ebef026..68eb2fefe7a8 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Concerns; use Closure; +use RuntimeException; use Throwable; trait ManagesTransactions @@ -321,4 +322,18 @@ public function transactionLevel() { return $this->transactions; } + + /** + * Execute the callback within a transaction context. + * + * @return void + */ + public function withinTransaction($callback) + { + if ($this->transactionsManager) { + return $this->transactionsManager->addCallback($callback); + } + + throw new RuntimeException('Transactions Manager has not been set.'); + } } diff --git a/src/Illuminate/Database/DatabaseTransactionsManager.php b/src/Illuminate/Database/DatabaseTransactionsManager.php index 37be16448bea..95462a331c8f 100755 --- a/src/Illuminate/Database/DatabaseTransactionsManager.php +++ b/src/Illuminate/Database/DatabaseTransactionsManager.php @@ -77,7 +77,11 @@ public function commit($connection) */ public function addCallback($callback) { - $this->transactions->last()->addCallback($callback); + if ($current = $this->transactions->last()) { + return $current->addCallback($callback); + } + + call_user_func($callback); } /** diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php index 4d92819e3996..b065c24f6e21 100755 --- a/tests/Database/DatabaseTransactionsManagerTest.php +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -171,4 +171,18 @@ public function testCommittingExecutesOnlyCallbacksOfTheConnection() $this->assertCount(1, $callbacks); $this->assertEquals(['default', 1], $callbacks[0]); } + + public function testCallbackIsExecutedIfNoTransactions() + { + $callbacks = []; + + $manager = (new DatabaseTransactionsManager()); + + $manager->addCallback(function () use (&$callbacks) { + $callbacks[] = ['default', 1]; + }); + + $this->assertCount(1, $callbacks); + $this->assertEquals(['default', 1], $callbacks[0]); + } } From 127bbe7271099dd324988603c913151d0de6f16c Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 26 Nov 2020 15:24:00 +0200 Subject: [PATCH 079/599] fix style --- .../DatabaseTransactionsManagerTest.php | 22 ----------- tests/Database/DatabaseTransactionsTest.php | 39 +++++++++---------- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/tests/Database/DatabaseTransactionsManagerTest.php b/tests/Database/DatabaseTransactionsManagerTest.php index b065c24f6e21..172a48e5a4a1 100755 --- a/tests/Database/DatabaseTransactionsManagerTest.php +++ b/tests/Database/DatabaseTransactionsManagerTest.php @@ -2,28 +2,8 @@ namespace Illuminate\Tests\Database; -use DateTime; -use ErrorException; -use Exception; -use Illuminate\Contracts\Events\Dispatcher; -use Illuminate\Database\Connection; use Illuminate\Database\DatabaseTransactionsManager; -use Illuminate\Database\Events\QueryExecuted; -use Illuminate\Database\Events\TransactionBeginning; -use Illuminate\Database\Events\TransactionCommitted; -use Illuminate\Database\Events\TransactionRolledBack; -use Illuminate\Database\Query\Builder as BaseBuilder; -use Illuminate\Database\Query\Grammars\Grammar; -use Illuminate\Database\Query\Processors\Processor; -use Illuminate\Database\QueryException; -use Illuminate\Database\Schema\Builder; -use Mockery as m; -use PDO; -use PDOException; -use PDOStatement; use PHPUnit\Framework\TestCase; -use ReflectionClass; -use stdClass; class DatabaseTransactionsManagerTest extends TestCase { @@ -104,7 +84,6 @@ public function testCallbacksAreAddedToTheCurrentTransaction() $manager->begin('default', 1); $manager->addCallback(function () use (&$callbacks) { - }); $manager->begin('default', 2); @@ -112,7 +91,6 @@ public function testCallbacksAreAddedToTheCurrentTransaction() $manager->begin('admin', 1); $manager->addCallback(function () use (&$callbacks) { - }); $this->assertCount(1, $manager->getTransactions()[0]->getCallbacks()); diff --git a/tests/Database/DatabaseTransactionsTest.php b/tests/Database/DatabaseTransactionsTest.php index 0432d750656f..a2bd36114b9c 100644 --- a/tests/Database/DatabaseTransactionsTest.php +++ b/tests/Database/DatabaseTransactionsTest.php @@ -67,12 +67,12 @@ public function testTransactionIsRecordedAndCommitted() $this->connection()->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); $this->connection()->transaction(function() use ($transactionManager){ $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); }); } @@ -86,12 +86,12 @@ public function testTransactionIsRecordedAndCommittedUsingTheSeparateMethods() $this->connection()->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); $this->connection()->beginTransaction(); $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); $this->connection()->commit(); } @@ -106,17 +106,17 @@ public function testNestedTransactionIsRecordedAndCommitted() $this->connection()->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); $this->connection()->transaction(function() use ($transactionManager){ $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); $this->connection()->transaction(function() use ($transactionManager){ $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); }); }); @@ -135,22 +135,22 @@ public function testNestedTransactionIsRecordeForDifferentConnectionsdAndCommitt $this->connection('second_connection')->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); $this->connection()->transaction(function() use ($transactionManager){ $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); $this->connection('second_connection')->transaction(function() use ($transactionManager){ $this->connection('second_connection')->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); $this->connection('second_connection')->transaction(function() use ($transactionManager){ $this->connection('second_connection')->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); }); }); @@ -167,19 +167,18 @@ public function testTransactionIsRolledBack() $this->connection()->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); try { $this->connection()->transaction(function () use ($transactionManager) { $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); throw new \Exception; }); } catch (\Throwable $e) { - } } @@ -193,13 +192,13 @@ public function testTransactionIsRolledBackUsingSeparateMethods() $this->connection()->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); $this->connection()->beginTransaction(); $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); $this->connection()->rollBack(); @@ -217,29 +216,27 @@ public function testNestedTransactionsAreRolledBack() $this->connection()->setTransactionManager($transactionManager); $this->connection()->table('users')->insert([ - 'name' => 'zain', 'value' => 1 + 'name' => 'zain', 'value' => 1, ]); try { $this->connection()->transaction(function () use ($transactionManager) { $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); $this->connection()->transaction(function () use ($transactionManager) { $this->connection()->table('users')->where(['name' => 'zain'])->update([ - 'value' => 2 + 'value' => 2, ]); throw new \Exception; }); }); } catch (\Throwable $e) { - } } - /** * Get a schema builder instance. * From c4fe69ec8318bfb8ab847e962ad6b8c1353cbc20 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 26 Nov 2020 15:27:01 +0200 Subject: [PATCH 080/599] fix style --- tests/Database/DatabaseTransactionsTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Database/DatabaseTransactionsTest.php b/tests/Database/DatabaseTransactionsTest.php index a2bd36114b9c..2385d6d26313 100644 --- a/tests/Database/DatabaseTransactionsTest.php +++ b/tests/Database/DatabaseTransactionsTest.php @@ -70,7 +70,7 @@ public function testTransactionIsRecordedAndCommitted() 'name' => 'zain', 'value' => 1, ]); - $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); @@ -109,12 +109,12 @@ public function testNestedTransactionIsRecordedAndCommitted() 'name' => 'zain', 'value' => 1, ]); - $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); - $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); @@ -138,17 +138,17 @@ public function testNestedTransactionIsRecordeForDifferentConnectionsdAndCommitt 'name' => 'zain', 'value' => 1, ]); - $this->connection()->transaction(function() use ($transactionManager){ + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); - $this->connection('second_connection')->transaction(function() use ($transactionManager){ + $this->connection('second_connection')->transaction(function () { $this->connection('second_connection')->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); - $this->connection('second_connection')->transaction(function() use ($transactionManager){ + $this->connection('second_connection')->transaction(function () { $this->connection('second_connection')->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); @@ -171,7 +171,7 @@ public function testTransactionIsRolledBack() ]); try { - $this->connection()->transaction(function () use ($transactionManager) { + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); @@ -220,12 +220,12 @@ public function testNestedTransactionsAreRolledBack() ]); try { - $this->connection()->transaction(function () use ($transactionManager) { + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); - $this->connection()->transaction(function () use ($transactionManager) { + $this->connection()->transaction(function () { $this->connection()->table('users')->where(['name' => 'zain'])->update([ 'value' => 2, ]); From b5064d731a47dca3d7bd31f7a4eff5617aa5c2b9 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 26 Nov 2020 15:21:02 +0100 Subject: [PATCH 081/599] Backport Redis context option (#35370) --- src/Illuminate/Redis/Connectors/PhpRedisConnector.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php index b01f114205d8..5a1ef9117bf3 100644 --- a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php +++ b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php @@ -128,6 +128,10 @@ protected function establishConnection($client, array $config) $parameters[] = Arr::get($config, 'read_timeout', 0.0); } + if (version_compare(phpversion('redis'), '5.3.0', '>=')) { + $parameters[] = Arr::get($config, 'context'); + } + $client->{($persistent ? 'pconnect' : 'connect')}(...$parameters); } @@ -152,6 +156,10 @@ protected function createRedisClusterInstance(array $servers, array $options) $parameters[] = $options['password'] ?? null; } + if (version_compare(phpversion('redis'), '5.3.2', '>=')) { + $parameters[] = Arr::get($options, 'context'); + } + return tap(new RedisCluster(...$parameters), function ($client) use ($options) { if (! empty($options['prefix'])) { $client->setOption(RedisCluster::OPT_PREFIX, $options['prefix']); From ae885e664bc0c8921566a334dcd75b1512f12134 Mon Sep 17 00:00:00 2001 From: Tom Witkowski Date: Thu, 26 Nov 2020 15:23:07 +0100 Subject: [PATCH 082/599] fix typo in code comment (#35375) * fix typo * Update Container.php Co-authored-by: Taylor Otwell --- src/Illuminate/Container/Container.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 9403e6a0e546..5befce152ac9 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -681,7 +681,7 @@ protected function resolve($abstract, $parameters = [], $raiseEvents = true) { $abstract = $this->getAlias($abstract); - // First we wil fire any event handlers that handle the "before" resolving of + // First we'll fire any event handlers which handle the "before" resolving of // specific types. This gives some hooks the chance to add various extends // calls to change the resolution of objects that they're interested in. if ($raiseEvents) { From 7878d5eedeef422ddaba57377cf1f14e46d93cf8 Mon Sep 17 00:00:00 2001 From: Jason Beggs Date: Thu, 26 Nov 2020 09:30:03 -0500 Subject: [PATCH 083/599] [8.x] Update Tailwind pagination focus styles (#35365) * Update focus styles in tailwind.blade.php * Update focus styles in simple-tailwind.blade.php --- .../resources/views/simple-tailwind.blade.php | 4 ++-- .../Pagination/resources/views/tailwind.blade.php | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Pagination/resources/views/simple-tailwind.blade.php b/src/Illuminate/Pagination/resources/views/simple-tailwind.blade.php index 1c5e52f3e52a..6872cca360d5 100644 --- a/src/Illuminate/Pagination/resources/views/simple-tailwind.blade.php +++ b/src/Illuminate/Pagination/resources/views/simple-tailwind.blade.php @@ -6,14 +6,14 @@ {!! __('pagination.previous') !!} @else - @endif {{-- Next Page Link --}} @if ($paginator->hasMorePages()) - @else diff --git a/src/Illuminate/Pagination/resources/views/tailwind.blade.php b/src/Illuminate/Pagination/resources/views/tailwind.blade.php index 2f5eca93e152..2dd4d0ef3389 100644 --- a/src/Illuminate/Pagination/resources/views/tailwind.blade.php +++ b/src/Illuminate/Pagination/resources/views/tailwind.blade.php @@ -6,13 +6,13 @@ {!! __('pagination.previous') !!} @else - + {!! __('pagination.previous') !!} @endif @if ($paginator->hasMorePages()) - + {!! __('pagination.next') !!} @else @@ -47,7 +47,7 @@ @else - + {{ $page }} @endif @@ -81,7 +81,7 @@ {{-- Next Page Link --}} @if ($paginator->hasMorePages()) - 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 294/599] 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 295/599] 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 296/599] 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 297/599] 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 298/599] 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 299/599] [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 300/599] [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 301/599] 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 302/599] 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 303/599] 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 304/599] [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 305/599] 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 306/599] 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 307/599] 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 308/599] 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 309/599] 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 310/599] 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 311/599] 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 312/599] 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 313/599] [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 314/599] [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 315/599] [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 316/599] [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 317/599] [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 318/599] [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 319/599] [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 320/599] [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 321/599] [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 322/599] 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 323/599] 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 324/599] 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 325/599] 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 326/599] 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 327/599] 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 328/599] 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 329/599] 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 330/599] 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 331/599] 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 332/599] 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 333/599] 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 334/599] 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 335/599] 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 336/599] 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 337/599] 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 338/599] 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 339/599] 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 340/599] 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 341/599] [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 342/599] 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 343/599] 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 344/599] 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 345/599] 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 346/599] 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 347/599] 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 348/599] 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 349/599] 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 350/599] 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 351/599] 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 352/599] 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 353/599] 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 354/599] 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 355/599] 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 356/599] 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 357/599] 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 358/599] 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 359/599] 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 360/599] [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 361/599] 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 362/599] 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 363/599] 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 364/599] [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 365/599] [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 366/599] [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 367/599] [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 368/599] 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 369/599] 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 370/599] 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 371/599] 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 372/599] 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 373/599] 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 374/599] 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 375/599] 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 376/599] [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 377/599] 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 378/599] [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 379/599] [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 380/599] [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 381/599] [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 382/599] 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 383/599] 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 384/599] 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 385/599] [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 386/599] 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 387/599] 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 388/599] 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 389/599] 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 390/599] 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 391/599] [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 392/599] 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 393/599] 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 394/599] 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 395/599] 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 396/599] 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 397/599] [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 398/599] 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 399/599] [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 400/599] 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 401/599] [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 402/599] [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 403/599] 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 404/599] 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 405/599] 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 406/599] 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 407/599] 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 408/599] [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 409/599] 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 410/599] 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 411/599] [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 412/599] 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 413/599] 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 414/599] [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 415/599] [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 416/599] [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 417/599] [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 418/599] 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 419/599] 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 420/599] 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 421/599] [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 422/599] 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 423/599] 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 424/599] [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 425/599] 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 426/599] [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 427/599] 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 428/599] 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 429/599] 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 430/599] [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 431/599] 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 432/599] 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 433/599] 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 434/599] 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 435/599] [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 436/599] [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 437/599] [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 438/599] 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 439/599] [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 440/599] 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 441/599] 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 442/599] 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 443/599] 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 444/599] [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 445/599] [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 446/599] [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 447/599] 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 448/599] 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 449/599] 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 450/599] 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 451/599] 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 452/599] 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 453/599] 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 454/599] 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 455/599] 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 456/599] 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 457/599] 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 458/599] 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 459/599] 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 460/599] [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 461/599] 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 462/599] 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 463/599] [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 464/599] 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 465/599] 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 466/599] 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 467/599] 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 468/599] 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 469/599] 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 470/599] 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 471/599] 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 472/599] 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 473/599] 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 474/599] [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 475/599] 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 476/599] [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 477/599] [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 478/599] 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 479/599] 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 480/599] 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 481/599] 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 482/599] 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 483/599] 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 484/599] 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 485/599] 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 486/599] 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 487/599] [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 488/599] 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 489/599] 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 490/599] 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 491/599] 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 492/599] 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 493/599] 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 494/599] 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 495/599] [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 496/599] 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 497/599] 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 498/599] [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 499/599] 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 500/599] 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 501/599] 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 502/599] 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 503/599] 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 504/599] 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 505/599] 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 506/599] 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 507/599] 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 508/599] 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 509/599] 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 510/599] 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 511/599] [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 512/599] 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 513/599] 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 514/599] 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 515/599] 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 516/599] 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 517/599] [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 518/599] 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 519/599] [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 520/599] [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 521/599] 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 522/599] 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 523/599] [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 524/599] [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 525/599] 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 526/599] 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 527/599] 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 528/599] 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 529/599] 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 530/599] 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 531/599] 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 532/599] 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 533/599] 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 534/599] 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 535/599] 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 536/599] 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 537/599] 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 538/599] 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 539/599] 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 540/599] 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 541/599] [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 542/599] 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 543/599] 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 544/599] [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 545/599] 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 546/599] [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 547/599] 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 548/599] 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 549/599] 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 550/599] 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 551/599] [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 552/599] 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 553/599] 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 554/599] 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 555/599] 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 556/599] 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 557/599] 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 558/599] 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 559/599] 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 560/599] [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 561/599] [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 562/599] [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 563/599] [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 564/599] [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 565/599] 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 566/599] [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 567/599] 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 568/599] 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 569/599] 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 570/599] 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 571/599] 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 572/599] 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 573/599] 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 574/599] 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 575/599] 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 576/599] 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 577/599] 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 578/599] [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 579/599] 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 580/599] 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 581/599] [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 582/599] 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 583/599] 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 584/599] 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 585/599] 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 586/599] 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 587/599] 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 588/599] 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 589/599] 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 590/599] 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 591/599] 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 592/599] [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 593/599] 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 594/599] 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 595/599] 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 596/599] [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 9f986cef11b959679f530eb24d929b39a2690924 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 16 Mar 2021 19:40:07 +0200 Subject: [PATCH 597/599] [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 332844e5bde34f8db91aeca4d21cd4e0925d691e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Mar 2021 14:42:13 -0500 Subject: [PATCH 598/599] 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 599/599] 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.