From 0379a7ccb77e2029c43ce508fa76e251a0d68fce Mon Sep 17 00:00:00 2001 From: driesvints Date: Thu, 21 Mar 2024 14:15:49 +0000 Subject: [PATCH 001/123] Update version to v11.0.8 --- 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 7c538144d3b9..8acc4b219b16 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.0.7'; + const VERSION = '11.0.8'; /** * The base path for the Laravel installation. From bd096bcb2e5e45f1d175011028122c0cf3ccfded Mon Sep 17 00:00:00 2001 From: driesvints Date: Thu, 21 Mar 2024 14:20:32 +0000 Subject: [PATCH 002/123] Update CHANGELOG --- CHANGELOG.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 411bef1826b5..312418c7f341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.0.7...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.0.8...11.x) + +## [v11.0.8](https://github.com/laravel/framework/compare/v11.0.7...v11.0.8) - 2024-03-21 + +* [11.x] Change typehint for enum rule from string to class-string by [@liamduckett](https://github.com/liamduckett) in https://github.com/laravel/framework/pull/50603 +* [11.x] Fixed enum and enum.backed stub paths after publish by [@haroon-mahmood-4276](https://github.com/haroon-mahmood-4276) in https://github.com/laravel/framework/pull/50629 +* [11.x] Fix(ScheduleListCommand): fix doc block for listEvent method by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50638 +* [11.x] Re: Fix issue with missing 'js/' directory in broadcasting installation command by [@alnahian2003](https://github.com/alnahian2003) in https://github.com/laravel/framework/pull/50657 +* [11.x] Remove `$except` property from `ExcludesPaths` trait by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/50644 +* [11.x] Fix command alias registration and usage. by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/50617 +* [11.x] Fixed make:session-table Artisan command cannot be executed if a migration exists by [@naopusyu](https://github.com/naopusyu) in https://github.com/laravel/framework/pull/50615 +* [11.x] Fix(src\illuminate\Queue): update doc block, Simplification of the code in RedisManager by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50635 +* [11.x] Add `--without-reverb` and `--without-node` arguments to `install:broadcasting` command by [@duncanmcclean](https://github.com/duncanmcclean) in https://github.com/laravel/framework/pull/50662 +* [11.x] Fixed `trait` stub paths after publish by [@haroon-mahmood-4276](https://github.com/haroon-mahmood-4276) in https://github.com/laravel/framework/pull/50678 +* [11.x] Fixed `class` and `class.invokable` stub paths after publish by [@haroon-mahmood-4276](https://github.com/haroon-mahmood-4276) in https://github.com/laravel/framework/pull/50676 +* [10.x] Fix `Collection::concat()` return type by [@axlon](https://github.com/axlon) in https://github.com/laravel/framework/pull/50669 +* [11.x] Fix adding multiple bootstrap providers with opcache by [@jessarcher](https://github.com/jessarcher) in https://github.com/laravel/framework/pull/50665 +* [11.x] Allow `BackedEnum` and `UnitEnum` in `Rule::in` and `Rule::notIn` by [@PerryvanderMeer](https://github.com/PerryvanderMeer) in https://github.com/laravel/framework/pull/50680 +* [10.x] Fix command alias registration and usage by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/50695 ## [v11.0.7](https://github.com/laravel/framework/compare/v11.0.6...v11.0.7) - 2024-03-15 From 202e521b464135d2a4c2c0c89ad0f4dfa86dd293 Mon Sep 17 00:00:00 2001 From: Michael WIkberg <130439907+mwikberg-virta@users.noreply.github.com> Date: Thu, 21 Mar 2024 20:15:09 +0200 Subject: [PATCH 003/123] [11.x] MySQL transaction isolation level fix (#50689) * Fix transaction isolation level in MySqlConnector.php * Update DatabaseConnectorTest.php * Style fix * Code style fix --------- Co-authored-by: Graham Campbell --- src/Illuminate/Database/Connectors/MySqlConnector.php | 6 +++--- tests/Database/DatabaseConnectorTest.php | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Connectors/MySqlConnector.php b/src/Illuminate/Database/Connectors/MySqlConnector.php index 51b6a79ca135..0ecaf8bf4551 100755 --- a/src/Illuminate/Database/Connectors/MySqlConnector.php +++ b/src/Illuminate/Database/Connectors/MySqlConnector.php @@ -93,12 +93,12 @@ protected function getHostDsn(array $config) */ protected function configureConnection(PDO $connection, array $config) { - $statements = []; - if (isset($config['isolation_level'])) { - $statements[] = sprintf('SESSION TRANSACTION ISOLATION LEVEL %s', $config['isolation_level']); + $connection->exec(sprintf('SET SESSION TRANSACTION ISOLATION LEVEL %s;', $config['isolation_level'])); } + $statements = []; + if (isset($config['charset'])) { if (isset($config['collation'])) { $statements[] = sprintf("NAMES '%s' COLLATE '%s'", $config['charset'], $config['collation']); diff --git a/tests/Database/DatabaseConnectorTest.php b/tests/Database/DatabaseConnectorTest.php index 4774b6caff73..ca45cfa36465 100755 --- a/tests/Database/DatabaseConnectorTest.php +++ b/tests/Database/DatabaseConnectorTest.php @@ -62,7 +62,8 @@ public function testMySqlConnectCallsCreateConnectionWithIsolationLevel() $connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']); $connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection); $connection->shouldReceive('exec')->once()->with('use `bar`;')->andReturn(true); - $connection->shouldReceive('exec')->once()->with("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ, NAMES 'utf8' COLLATE 'utf8_unicode_ci';")->andReturn(true); + $connection->shouldReceive('exec')->once()->with('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;')->andReturn(true); + $connection->shouldReceive('exec')->once()->with("SET NAMES 'utf8' COLLATE 'utf8_unicode_ci';")->andReturn(true); $result = $connector->connect($config); $this->assertSame($result, $connection); From 075bda50c2789be393a8510a38d06ab823154568 Mon Sep 17 00:00:00 2001 From: Ariful Alam Date: Fri, 22 Mar 2024 00:57:34 +0600 Subject: [PATCH 004/123] [11.x] Add ListManagementOptions in SES mail transport (#50660) * Add ListManagementOptions in SES mail transport * formatting * formatting --------- Co-authored-by: Taylor Otwell --- .../Mail/Transport/SesTransport.php | 19 +++++++++++++++++++ .../Mail/Transport/SesV2Transport.php | 19 +++++++++++++++++++ tests/Mail/MailSesTransportTest.php | 2 ++ tests/Mail/MailSesV2TransportTest.php | 2 ++ 4 files changed, 42 insertions(+) diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index 7ef78eb582fa..c0f715329371 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -50,6 +50,10 @@ protected function doSend(SentMessage $message): void $options = $this->options; if ($message->getOriginalMessage() instanceof Message) { + if ($listManagementOptions = $this->listManagementOptions($message)) { + $options['ListManagementOptions'] = $listManagementOptions; + } + foreach ($message->getOriginalMessage()->getHeaders()->all() as $header) { if ($header instanceof MetadataHeader) { $options['Tags'][] = ['Name' => $header->getKey(), 'Value' => $header->getValue()]; @@ -89,6 +93,21 @@ protected function doSend(SentMessage $message): void $message->getOriginalMessage()->getHeaders()->addHeader('X-SES-Message-ID', $messageId); } + /** + * Extract the SES list managenent options, if applicable. + * + * @param \Illuminate\Mail\SentMessage $message + * @return array|null + */ + protected function listManagementOptions(SentMessage $message) + { + if ($header = $message->getOriginalMessage()->getHeaders()->get('X-SES-LIST-MANAGEMENT-OPTIONS')) { + if (preg_match("/^(contactListName=)*(?[^;]+)(;\s?topicName=(?.+))?$/ix", $header->getBodyAsString(), $listManagementOptions)) { + return array_filter($listManagementOptions, fn ($e) => in_array($e, ['ContactListName', 'TopicName']), ARRAY_FILTER_USE_KEY); + } + } + } + /** * Get the Amazon SES client for the SesTransport instance. * diff --git a/src/Illuminate/Mail/Transport/SesV2Transport.php b/src/Illuminate/Mail/Transport/SesV2Transport.php index e874e583abd5..85debd5b808e 100644 --- a/src/Illuminate/Mail/Transport/SesV2Transport.php +++ b/src/Illuminate/Mail/Transport/SesV2Transport.php @@ -50,6 +50,10 @@ protected function doSend(SentMessage $message): void $options = $this->options; if ($message->getOriginalMessage() instanceof Message) { + if ($listManagementOptions = $this->listManagementOptions($message)) { + $options['ListManagementOptions'] = $listManagementOptions; + } + foreach ($message->getOriginalMessage()->getHeaders()->all() as $header) { if ($header instanceof MetadataHeader) { $options['Tags'][] = ['Name' => $header->getKey(), 'Value' => $header->getValue()]; @@ -93,6 +97,21 @@ protected function doSend(SentMessage $message): void $message->getOriginalMessage()->getHeaders()->addHeader('X-SES-Message-ID', $messageId); } + /** + * Extract the SES list managenent options, if applicable. + * + * @param \Illuminate\Mail\SentMessage $message + * @return array|null + */ + protected function listManagementOptions(SentMessage $message) + { + if ($header = $message->getOriginalMessage()->getHeaders()->get('X-SES-LIST-MANAGEMENT-OPTIONS')) { + if (preg_match("/^(contactListName=)*(?[^;]+)(;\s?topicName=(?.+))?$/ix", $header->getBodyAsString(), $listManagementOptions)) { + return array_filter($listManagementOptions, fn ($e) => in_array($e, ['ContactListName', 'TopicName']), ARRAY_FILTER_USE_KEY); + } + } + } + /** * Get the Amazon SES V2 client for the SesV2Transport instance. * diff --git a/tests/Mail/MailSesTransportTest.php b/tests/Mail/MailSesTransportTest.php index 8d3fd4c6b83d..f8358cebcc25 100755 --- a/tests/Mail/MailSesTransportTest.php +++ b/tests/Mail/MailSesTransportTest.php @@ -62,6 +62,7 @@ public function testSend() $message->bcc('you@example.com'); $message->replyTo(new Address('taylor@example.com', 'Taylor Otwell')); $message->getHeaders()->add(new MetadataHeader('FooTag', 'TagValue')); + $message->getHeaders()->addTextHeader('X-Ses-List-Management-Options', 'contactListName=TestList;topicName=TestTopic'); $client = m::mock(SesClient::class); $sesResult = m::mock(); @@ -73,6 +74,7 @@ public function testSend() ->with(m::on(function ($arg) { return $arg['Source'] === 'myself@example.com' && $arg['Destinations'] === ['me@example.com', 'you@example.com'] && + $arg['ListManagementOptions'] === ['ContactListName' => 'TestList', 'TopicName' => 'TestTopic'] && $arg['Tags'] === [['Name' => 'FooTag', 'Value' => 'TagValue']] && strpos($arg['RawMessage']['Data'], 'Reply-To: Taylor Otwell ') !== false; })) diff --git a/tests/Mail/MailSesV2TransportTest.php b/tests/Mail/MailSesV2TransportTest.php index 7b7821558ac7..2170dc256d2e 100755 --- a/tests/Mail/MailSesV2TransportTest.php +++ b/tests/Mail/MailSesV2TransportTest.php @@ -62,6 +62,7 @@ public function testSend() $message->bcc('you@example.com'); $message->replyTo(new Address('taylor@example.com', 'Taylor Otwell')); $message->getHeaders()->add(new MetadataHeader('FooTag', 'TagValue')); + $message->getHeaders()->addTextHeader('X-SES-LIST-MANAGEMENT-OPTIONS', 'contactListName=TestList;topicName=TestTopic'); $client = m::mock(SesV2Client::class); $sesResult = m::mock(); @@ -73,6 +74,7 @@ public function testSend() ->with(m::on(function ($arg) { return $arg['Source'] === 'myself@example.com' && $arg['Destination']['ToAddresses'] === ['me@example.com', 'you@example.com'] && + $arg['ListManagementOptions'] === ['ContactListName' => 'TestList', 'TopicName' => 'TestTopic'] && $arg['Tags'] === [['Name' => 'FooTag', 'Value' => 'TagValue']] && strpos($arg['Content']['Raw']['Data'], 'Reply-To: Taylor Otwell ') !== false; })) From 08772cf0caaad628570041a58717fe481e315209 Mon Sep 17 00:00:00 2001 From: Giorgio Balduzzi Date: Thu, 21 Mar 2024 20:12:12 +0100 Subject: [PATCH 005/123] [11.x] Accept non-backed enum in database queries (#50674) * Cast non-backed enum in database bindings * Update enum queries integration tests --- src/Illuminate/Database/Query/Builder.php | 7 ++++++- tests/Database/DatabaseQueryBuilderTest.php | 10 ++++++++++ tests/Database/Enums.php | 7 +++++++ tests/Integration/Database/Enums.php | 7 +++++++ tests/Integration/Database/QueryingWithEnumsTest.php | 7 +++++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 29153e96c91d..de3ae0b839b9 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -27,6 +27,7 @@ use InvalidArgumentException; use LogicException; use RuntimeException; +use UnitEnum; class Builder implements BuilderContract { @@ -3953,7 +3954,11 @@ public function addBinding($value, $type = 'where') */ public function castBinding($value) { - return $value instanceof BackedEnum ? $value->value : $value; + if ($value instanceof UnitEnum) { + return $value instanceof BackedEnum ? $value->value : $value->name; + } + + return $value; } /** diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index b28215c5cad3..cbf772ba572a 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -30,6 +30,8 @@ use RuntimeException; use stdClass; +include_once 'Enums.php'; + class DatabaseQueryBuilderTest extends TestCase { protected $called; @@ -4474,6 +4476,14 @@ public function testAddBindingWithArrayMergesBindingsInCorrectOrder() $this->assertEquals(['foo', 'bar', 'baz'], $builder->getBindings()); } + public function testAddBindingWithEnum() + { + $builder = $this->getBuilder(); + $builder->addBinding(IntegerStatus::done); + $builder->addBinding([NonBackedStatus::done]); + $this->assertEquals([2, 'done'], $builder->getBindings()); + } + public function testMergeBuilders() { $builder = $this->getBuilder(); diff --git a/tests/Database/Enums.php b/tests/Database/Enums.php index 2dbcb98d776d..11c1820b1ef6 100644 --- a/tests/Database/Enums.php +++ b/tests/Database/Enums.php @@ -18,6 +18,13 @@ enum IntegerStatus: int case done = 2; } +enum NonBackedStatus +{ + case draft; + case pending; + case done; +} + enum ArrayableStatus: string implements Arrayable { case pending = 'pending'; diff --git a/tests/Integration/Database/Enums.php b/tests/Integration/Database/Enums.php index f3bf199a16dc..5f69cf5389b3 100644 --- a/tests/Integration/Database/Enums.php +++ b/tests/Integration/Database/Enums.php @@ -18,6 +18,13 @@ enum IntegerStatus: int case done = 2; } +enum NonBackedStatus +{ + case draft; + case pending; + case done; +} + enum ArrayableStatus: string implements Arrayable { case pending = 'pending'; diff --git a/tests/Integration/Database/QueryingWithEnumsTest.php b/tests/Integration/Database/QueryingWithEnumsTest.php index 923eba19eb65..489b90629c86 100644 --- a/tests/Integration/Database/QueryingWithEnumsTest.php +++ b/tests/Integration/Database/QueryingWithEnumsTest.php @@ -16,6 +16,7 @@ protected function afterRefreshingDatabase() $table->increments('id'); $table->string('string_status', 100)->nullable(); $table->integer('integer_status')->nullable(); + $table->string('non_backed_status', 100)->nullable(); }); } @@ -24,17 +25,21 @@ public function testCanQueryWithEnums() DB::table('enum_casts')->insert([ 'string_status' => 'pending', 'integer_status' => 1, + 'non_backed_status' => 'pending', ]); $record = DB::table('enum_casts')->where('string_status', StringStatus::pending)->first(); $record2 = DB::table('enum_casts')->where('integer_status', IntegerStatus::pending)->first(); $record3 = DB::table('enum_casts')->whereIn('integer_status', [IntegerStatus::pending])->first(); + $record4 = DB::table('enum_casts')->where('non_backed_status', NonBackedStatus::pending)->first(); $this->assertNotNull($record); $this->assertNotNull($record2); $this->assertNotNull($record3); + $this->assertNotNull($record4); $this->assertSame('pending', $record->string_status); $this->assertEquals(1, $record2->integer_status); + $this->assertSame('pending', $record4->non_backed_status); } public function testCanInsertWithEnums() @@ -42,6 +47,7 @@ public function testCanInsertWithEnums() DB::table('enum_casts')->insert([ 'string_status' => StringStatus::pending, 'integer_status' => IntegerStatus::pending, + 'non_backed_status' => NonBackedStatus::pending, ]); $record = DB::table('enum_casts')->where('string_status', StringStatus::pending)->first(); @@ -49,5 +55,6 @@ public function testCanInsertWithEnums() $this->assertNotNull($record); $this->assertSame('pending', $record->string_status); $this->assertEquals(1, $record->integer_status); + $this->assertSame('pending', $record->non_backed_status); } } From 62a101f306830cd64245104c4933b161f664275f Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Fri, 22 Mar 2024 20:34:16 +0200 Subject: [PATCH 006/123] [11.x] Add `Conditionable` trait to `Context` (#50707) * Add `Conditionable` trait to `Context` * Update Repository.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Log/Context/Repository.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Log/Context/Repository.php b/src/Illuminate/Log/Context/Repository.php index 184d56bcd972..a19f5a0e1ec2 100644 --- a/src/Illuminate/Log/Context/Repository.php +++ b/src/Illuminate/Log/Context/Repository.php @@ -8,13 +8,14 @@ use Illuminate\Log\Context\Events\ContextDehydrating as Dehydrating; use Illuminate\Log\Context\Events\ContextHydrated as Hydrated; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Traits\Conditionable; use Illuminate\Support\Traits\Macroable; use RuntimeException; use Throwable; class Repository { - use Macroable, SerializesModels; + use Conditionable, Macroable, SerializesModels; /** * The event dispatcher instance. From f6a8345762a2ccdaef896d7ea2eff9d4aeb330a1 Mon Sep 17 00:00:00 2001 From: Raymond Nambaale Date: Fri, 22 Mar 2024 21:34:30 +0300 Subject: [PATCH 007/123] [11.x] Adds thrown exception to doc blocks (#50715) --- src/Illuminate/Log/Context/Repository.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Illuminate/Log/Context/Repository.php b/src/Illuminate/Log/Context/Repository.php index a19f5a0e1ec2..47ca1b916735 100644 --- a/src/Illuminate/Log/Context/Repository.php +++ b/src/Illuminate/Log/Context/Repository.php @@ -241,6 +241,8 @@ public function addHiddenIf($key, $value) * @param string $key * @param mixed ...$values * @return $this + * + * @throws \RuntimeException */ public function push($key, ...$values) { @@ -262,6 +264,8 @@ public function push($key, ...$values) * @param string $key * @param mixed ...$values * @return $this + * + * @throws \RuntimeException */ public function pushHidden($key, ...$values) { @@ -393,6 +397,8 @@ public function dehydrate() * * @param ?array $context * @return $this + * + * @throws \RuntimeException */ public function hydrate($context) { From 12b999fe6d844af91e3d21f4eab62dc0265fdbc4 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 22 Mar 2024 22:04:50 +0330 Subject: [PATCH 008/123] [11.x] Test modifying nullable columns (#50708) * test modifying nullable columns * formatting --- .../Database/SchemaBuilderTest.php | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index dbf41b88db07..670bc95c1e6a 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -111,6 +111,70 @@ public function testChangeTextColumnToTextColumn() } } + public function testModifyNullableColumn() + { + if (! in_array($this->driver, ['mysql', 'mariadb'])) { + $this->markTestSkipped('Test requires a MySQL or a MariaDB connection.'); + } + + Schema::create('test', static function (Blueprint $table) { + $table->string('not_null_column_to_not_null'); + $table->string('not_null_column_to_nullable'); + $table->string('nullable_column_to_nullable')->nullable(); + $table->string('nullable_column_to_not_null')->nullable(); + }); + + $blueprint = new Blueprint('test', function ($table) { + $table->text('not_null_column_to_not_null')->change(); + $table->text('not_null_column_to_nullable')->nullable()->change(); + $table->text('nullable_column_to_nullable')->nullable()->change(); + $table->text('nullable_column_to_not_null')->change(); + }); + + $queries = $blueprint->toSql($this->getConnection(), $this->getConnection()->getSchemaGrammar()); + + $expected = [ + 'alter table `test` ' + .'modify `not_null_column_to_not_null` text not null, ' + .'modify `not_null_column_to_nullable` text null, ' + .'modify `nullable_column_to_nullable` text null, ' + .'modify `nullable_column_to_not_null` text not null', + ]; + + $this->assertEquals($expected, $queries); + } + + public function testChangeNullableColumn() + { + Schema::create('test', function (Blueprint $table) { + $table->string('not_null_column_to_not_null'); + $table->string('not_null_column_to_nullable'); + $table->string('nullable_column_to_nullable')->nullable(); + $table->string('nullable_column_to_not_null')->nullable(); + }); + + $columns = collect(Schema::getColumns('test')); + + $this->assertFalse($columns->firstWhere('name', 'not_null_column_to_not_null')['nullable']); + $this->assertFalse($columns->firstWhere('name', 'not_null_column_to_nullable')['nullable']); + $this->assertTrue($columns->firstWhere('name', 'nullable_column_to_nullable')['nullable']); + $this->assertTrue($columns->firstWhere('name', 'nullable_column_to_not_null')['nullable']); + + Schema::table('test', function (Blueprint $table) { + $table->text('not_null_column_to_not_null')->change(); + $table->text('not_null_column_to_nullable')->nullable()->change(); + $table->text('nullable_column_to_nullable')->nullable()->change(); + $table->text('nullable_column_to_not_null')->change(); + }); + + $columns = collect(Schema::getColumns('test')); + + $this->assertFalse($columns->firstWhere('name', 'not_null_column_to_not_null')['nullable']); + $this->assertTrue($columns->firstWhere('name', 'not_null_column_to_nullable')['nullable']); + $this->assertTrue($columns->firstWhere('name', 'nullable_column_to_nullable')['nullable']); + $this->assertFalse($columns->firstWhere('name', 'nullable_column_to_not_null')['nullable']); + } + public function testRenameColumnWithDefault() { Schema::create('test', static function (Blueprint $table) { From fc453b908fc41fea8b428260b2d4f3527d046bf8 Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Fri, 22 Mar 2024 18:37:47 +0000 Subject: [PATCH 009/123] Update facade docblocks --- src/Illuminate/Support/Facades/Context.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Facades/Context.php b/src/Illuminate/Support/Facades/Context.php index fe15a1b08f24..7ee4f40c003c 100644 --- a/src/Illuminate/Support/Facades/Context.php +++ b/src/Illuminate/Support/Facades/Context.php @@ -24,6 +24,8 @@ * @method static \Illuminate\Log\Context\Repository hydrated(callable $callback) * @method static \Illuminate\Log\Context\Repository handleUnserializeExceptionsUsing(callable|null $callback) * @method static \Illuminate\Log\Context\Repository flush() + * @method static \Illuminate\Log\Context\Repository|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Log\Context\Repository|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) * @method static bool hasMacro(string $name) From eb6fc3c3a990b4b9fac9430efe1ba3c4290c303a Mon Sep 17 00:00:00 2001 From: Stephen Rees-Carter Date: Mon, 25 Mar 2024 01:11:20 +1000 Subject: [PATCH 010/123] Introduce HASH_VERIFY env var (#50718) To help solve part of the issue reported in #50627, exposing an env var to toggle hash verification avoids the need to manually implement the hashing.php file. --- config/hashing.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/hashing.php b/config/hashing.php index f34179a8f19a..9eb408e09eea 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -30,7 +30,7 @@ 'bcrypt' => [ 'rounds' => env('BCRYPT_ROUNDS', 12), - 'verify' => true, + 'verify' => env('HASH_VERIFY', true), ], /* @@ -48,7 +48,7 @@ 'memory' => env('ARGON_MEMORY', 65536), 'threads' => env('ARGON_THREADS', 1), 'time' => env('ARGON_TIME', 4), - 'verify' => true, + 'verify' => env('HASH_VERIFY', true), ], /* From 8c61f5059896d69a542b5f9b4afe0d2e7a20bb1f Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Mon, 25 Mar 2024 18:55:47 +0200 Subject: [PATCH 011/123] [11.x] Apply default timezone when casting unix timestamps (#50751) * [11.x] Apply default timezone when casting unix timestamps * Add additional date_default_timezone_get calls --------- Co-authored-by: Sergey Danilchenko Co-authored-by: Dries Vints --- src/Illuminate/Bus/DatabaseBatchRepository.php | 6 +++--- src/Illuminate/Bus/DynamoBatchRepository.php | 6 +++--- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 2 +- src/Illuminate/Http/Middleware/SetCacheHeaders.php | 2 +- src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php | 4 ++-- src/Illuminate/Support/Sleep.php | 2 +- src/Illuminate/Testing/TestResponse.php | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index 4333c515ac79..a4ede3253185 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -374,9 +374,9 @@ protected function toBatch($batch) (int) $batch->failed_jobs, (array) 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 + CarbonImmutable::createFromTimestamp($batch->created_at, date_default_timezone_get()), + $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at, date_default_timezone_get()) : $batch->cancelled_at, + $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at, date_default_timezone_get()) : $batch->finished_at ); } diff --git a/src/Illuminate/Bus/DynamoBatchRepository.php b/src/Illuminate/Bus/DynamoBatchRepository.php index 7753fa21297c..b0dc34a10733 100644 --- a/src/Illuminate/Bus/DynamoBatchRepository.php +++ b/src/Illuminate/Bus/DynamoBatchRepository.php @@ -411,9 +411,9 @@ protected function toBatch($batch) (int) $batch->failed_jobs, $batch->failed_job_ids, $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 + CarbonImmutable::createFromTimestamp($batch->created_at, date_default_timezone_get()), + $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at, date_default_timezone_get()) : $batch->cancelled_at, + $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at, date_default_timezone_get()) : $batch->finished_at ); } diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 10187f50d701..94e6e95f5288 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1459,7 +1459,7 @@ protected function asDateTime($value) // and format a Carbon object from this timestamp. This allows flexibility // when defining your date fields as they might be UNIX timestamps here. if (is_numeric($value)) { - return Date::createFromTimestamp($value); + return Date::createFromTimestamp($value, date_default_timezone_get()); } // If the value is in simply year, month, day format, we will instantiate the diff --git a/src/Illuminate/Http/Middleware/SetCacheHeaders.php b/src/Illuminate/Http/Middleware/SetCacheHeaders.php index 6229e4cfd171..4b34061ae715 100644 --- a/src/Illuminate/Http/Middleware/SetCacheHeaders.php +++ b/src/Illuminate/Http/Middleware/SetCacheHeaders.php @@ -56,7 +56,7 @@ public function handle($request, Closure $next, $options = []) if (isset($options['last_modified'])) { if (is_numeric($options['last_modified'])) { - $options['last_modified'] = Carbon::createFromTimestamp($options['last_modified']); + $options['last_modified'] = Carbon::createFromTimestamp($options['last_modified'], date_default_timezone_get()); } else { $options['last_modified'] = Carbon::parse($options['last_modified']); } diff --git a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php index 226c752e94ef..a6df62e6a251 100644 --- a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php @@ -119,7 +119,7 @@ public function all() 'payload' => $result['payload']['S'], 'exception' => $result['exception']['S'], 'failed_at' => Carbon::createFromTimestamp( - (int) $result['failed_at']['N'] + (int) $result['failed_at']['N'], date_default_timezone_get() )->format(DateTimeInterface::ISO8601), ]; })->all(); @@ -152,7 +152,7 @@ public function find($id) 'payload' => $result['Item']['payload']['S'], 'exception' => $result['Item']['exception']['S'], 'failed_at' => Carbon::createFromTimestamp( - (int) $result['Item']['failed_at']['N'] + (int) $result['Item']['failed_at']['N'], date_default_timezone_get() )->format(DateTimeInterface::ISO8601), ]; } diff --git a/src/Illuminate/Support/Sleep.php b/src/Illuminate/Support/Sleep.php index e5ae861834c7..ebb8f4215b03 100644 --- a/src/Illuminate/Support/Sleep.php +++ b/src/Illuminate/Support/Sleep.php @@ -92,7 +92,7 @@ public static function for($duration) public static function until($timestamp) { if (is_numeric($timestamp)) { - $timestamp = Carbon::createFromTimestamp($timestamp); + $timestamp = Carbon::createFromTimestamp($timestamp, date_default_timezone_get()); } return new static(Carbon::now()->diff($timestamp)); diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 02a179171619..7cc4261b24e0 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -432,7 +432,7 @@ public function assertCookieExpired($cookieName) "Cookie [{$cookieName}] not present on response." ); - $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime()); + $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime(), date_default_timezone_get()); PHPUnit::assertTrue( $cookie->getExpiresTime() !== 0 && $expiresAt->lessThan(Carbon::now()), @@ -455,7 +455,7 @@ public function assertCookieNotExpired($cookieName) "Cookie [{$cookieName}] not present on response." ); - $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime()); + $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime(), date_default_timezone_get()); PHPUnit::assertTrue( $cookie->getExpiresTime() === 0 || $expiresAt->greaterThan(Carbon::now()), From a32ba83e5b0753142d85b535092424600b3bf850 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 26 Mar 2024 00:59:41 +0800 Subject: [PATCH 012/123] [10.x] Test Improvements (#50744) Add tests to verify using `auth()->logoutOtherDevices()` will rehash the password. Signed-off-by: Mior Muhammad Zaki --- .../Auth/RehashOnLogoutOtherDevicesTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php diff --git a/tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php b/tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php new file mode 100644 index 000000000000..8e704ff33345 --- /dev/null +++ b/tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php @@ -0,0 +1,46 @@ +post('logout', function (Request $request) { + auth()->logoutOtherDevices($request->input('password')); + + return response()->noContent(); + })->middleware(['web', 'auth']); + } + + public function testItRehashThePasswordUsingLogoutOtherDevices() + { + $this->withoutExceptionHandling(); + + $user = UserFactory::new()->create(); + + $password = $user->password; + + $this->actingAs($user); + + $this->post('logout', [ + 'password' => 'password', + ])->assertStatus(204); + + $user->refresh(); + + $this->assertNotSame($password, $user->password); + } +} From 598f26b423de455b6276c06b227bc200ffe60ab4 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 26 Mar 2024 01:00:00 +0800 Subject: [PATCH 013/123] [11.x] Fixes `ApplicationBuilder::withCommandRouting()` usage (#50742) * [11.x] Fixes `ApplicationBuilder::withCommandRouting()` usage. This also apply the changes from PR #50738 for `withCommandRouting()` method. Signed-off-by: Mior Muhammad Zaki * Apply fixes from StyleCI * wip Signed-off-by: Mior Muhammad Zaki * wip * wip --------- Signed-off-by: Mior Muhammad Zaki Co-authored-by: StyleCI Bot --- src/Illuminate/Foundation/Configuration/ApplicationBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php index 343786c10b18..0ee659a25055 100644 --- a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php +++ b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php @@ -274,7 +274,7 @@ public function withCommands(array $commands = []) protected function withCommandRouting(array $paths) { $this->app->afterResolving(ConsoleKernel::class, function ($kernel) use ($paths) { - $kernel->setCommandRoutePaths($paths); + $this->app->booted(fn () => $kernel->addCommandRoutePaths($paths)); }); } From 57610f7b34e89c65f7c9008fbb3d1a5ebc90a519 Mon Sep 17 00:00:00 2001 From: Kacper Pruszynski Date: Mon, 25 Mar 2024 22:06:52 +0100 Subject: [PATCH 014/123] [11.x] Register console commands, paths and routes after the app is booted (#50716) (#50738) Co-authored-by: Kacper Pruszynski --- .../Foundation/Configuration/ApplicationBuilder.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php index 0ee659a25055..37187367049b 100644 --- a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php +++ b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php @@ -257,9 +257,11 @@ public function withCommands(array $commands = []) [$commands, $paths] = collect($commands)->partition(fn ($command) => class_exists($command)); [$routes, $paths] = $paths->partition(fn ($path) => is_file($path)); - $kernel->addCommands($commands->all()); - $kernel->addCommandPaths($paths->all()); - $kernel->addCommandRoutePaths($routes->all()); + $this->app->booted(static function () use ($kernel, $commands, $paths, $routes) { + $kernel->addCommands($commands->all()); + $kernel->addCommandPaths($paths->all()); + $kernel->addCommandRoutePaths($routes->all()); + }); }); return $this; From bf02fde821d645d70d7f222b26af46af325ca7d7 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Mon, 25 Mar 2024 22:07:10 +0100 Subject: [PATCH 015/123] [11.x] Enhance malformed request handling (#50735) * Convert SuspiciousOperationException to BadRequestHttpException This is suggested per https://github.com/symfony/symfony/blob/7.1/src/Symfony/Component/HttpFoundation/Exception/RequestExceptionInterface.php * Update existing test on SuspiciousOperationException handling * Add integration test for malformed requests * Return 400 code on all exceptions extending RequestExceptionInterface --- src/Illuminate/Foundation/Exceptions/Handler.php | 7 ++++--- .../FoundationExceptionsHandlerTest.php | 6 +++--- .../Foundation/ExceptionHandlerTest.php | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index d3111a462b5c..791f2cc69812 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -38,10 +38,11 @@ use Symfony\Component\Console\Application as ConsoleApplication; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; +use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -143,7 +144,7 @@ class Handler implements ExceptionHandlerContract ModelNotFoundException::class, MultipleRecordsFoundException::class, RecordsNotFoundException::class, - SuspiciousOperationException::class, + RequestExceptionInterface::class, TokenMismatchException::class, ValidationException::class, ]; @@ -630,7 +631,7 @@ protected function prepareException(Throwable $e) ), $e instanceof AuthorizationException && ! $e->hasStatus() => new AccessDeniedHttpException($e->getMessage(), $e), $e instanceof TokenMismatchException => new HttpException(419, $e->getMessage(), $e), - $e instanceof SuspiciousOperationException => new NotFoundHttpException('Bad hostname provided.', $e), + $e instanceof RequestExceptionInterface => new BadRequestHttpException('Bad request.', $e), $e instanceof RecordsNotFoundException => new NotFoundHttpException('Not found.', $e), default => $e, }; diff --git a/tests/Foundation/FoundationExceptionsHandlerTest.php b/tests/Foundation/FoundationExceptionsHandlerTest.php index 51ecd52b16c0..70ac2a96f9c9 100644 --- a/tests/Foundation/FoundationExceptionsHandlerTest.php +++ b/tests/Foundation/FoundationExceptionsHandlerTest.php @@ -359,15 +359,15 @@ function ($argument) use (&$argumentActual) { $this->assertEquals($argumentExpected, $argumentActual); } - public function testSuspiciousOperationReturns404WithoutReporting() + public function testSuspiciousOperationReturns400WithoutReporting() { $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 SuspiciousOperationException('Invalid method override "__CONSTRUCT"')); - $this->assertEquals(404, $response->getStatusCode()); - $this->assertStringContainsString('"message": "Bad hostname provided."', $response->getContent()); + $this->assertEquals(400, $response->getStatusCode()); + $this->assertStringContainsString('"message": "Bad request."', $response->getContent()); $logger = m::mock(LoggerInterface::class); $this->container->instance(LoggerInterface::class, $logger); diff --git a/tests/Integration/Foundation/ExceptionHandlerTest.php b/tests/Integration/Foundation/ExceptionHandlerTest.php index d13a74f4122b..499751337c7a 100644 --- a/tests/Integration/Foundation/ExceptionHandlerTest.php +++ b/tests/Integration/Foundation/ExceptionHandlerTest.php @@ -124,6 +124,21 @@ public function testItHasFallbackErrorMessageForUnknownStatusCodes() ]); } + public function testItReturns400CodeOnMalformedRequests() + { + // HTTP request... + $this->post('test-route', ['_method' => '__construct']) + ->assertStatus(400) + ->assertSeeText('Bad Request'); // see https://github.com/symfony/symfony/blob/1d439995eb6d780531b97094ff5fa43e345fc42e/src/Symfony/Component/ErrorHandler/Resources/views/error.html.php#L12 + + // JSON request... + $this->postJson('test-route', ['_method' => '__construct']) + ->assertStatus(400) + ->assertExactJson([ + 'message' => 'Bad request.', + ]); + } + #[DataProvider('exitCodesProvider')] public function testItReturnsNonZeroExitCodesForUncaughtExceptions($providers, $successful) { From 7c0e6ad5619675b280ba3963a47ee3117df1ba16 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Mon, 25 Mar 2024 21:53:24 +0000 Subject: [PATCH 016/123] [11.x] Adds `withSchedule` to `bootstrap/app.php` file (#50755) * Adds `withSchedule` * formatting --------- Co-authored-by: Taylor Otwell --- .../Configuration/ApplicationBuilder.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php index 37187367049b..0e8f1913eb51 100644 --- a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php +++ b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php @@ -3,6 +3,8 @@ namespace Illuminate\Foundation\Configuration; use Closure; +use Illuminate\Console\Application as Artisan; +use Illuminate\Console\Scheduling\Schedule; use Illuminate\Contracts\Console\Kernel as ConsoleKernel; use Illuminate\Contracts\Http\Kernel as HttpKernel; use Illuminate\Foundation\Application; @@ -280,6 +282,21 @@ protected function withCommandRouting(array $paths) }); } + /** + * Register the scheduled tasks for the application. + * + * @param callable(Schedule $schedule): void $callback + * @return $this + */ + public function withSchedule(callable $callback) + { + $this->app->afterResolving(ConsoleKernel::class, function (ConsoleKernel $kernel) use ($callback) { + Artisan::starting(fn () => $callback($this->app->make(Schedule::class))); + }); + + return $this; + } + /** * Register and configure the application's exception handler. * From 772b861a7012b1cf6362759f828b53d38bed0532 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 26 Mar 2024 16:54:48 +0800 Subject: [PATCH 017/123] [10.x] Test Improvements (#50763) Add tests to verify using `auth()->logoutOtherDevices()` will rehash the password. Signed-off-by: Mior Muhammad Zaki --- .../Auth/RehashOnLogoutOtherDevicesTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php diff --git a/tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php b/tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php new file mode 100644 index 000000000000..8e704ff33345 --- /dev/null +++ b/tests/Integration/Auth/RehashOnLogoutOtherDevicesTest.php @@ -0,0 +1,46 @@ +post('logout', function (Request $request) { + auth()->logoutOtherDevices($request->input('password')); + + return response()->noContent(); + })->middleware(['web', 'auth']); + } + + public function testItRehashThePasswordUsingLogoutOtherDevices() + { + $this->withoutExceptionHandling(); + + $user = UserFactory::new()->create(); + + $password = $user->password; + + $this->actingAs($user); + + $this->post('logout', [ + 'password' => 'password', + ])->assertStatus(204); + + $user->refresh(); + + $this->assertNotSame($password, $user->password); + } +} From fe176089bc6920206470f73c424266b4bd6010da Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Tue, 26 Mar 2024 12:30:16 +0330 Subject: [PATCH 018/123] fix: update dock block for create method in InvalidArgumentException.php (#50762) --- src/Illuminate/Testing/Exceptions/InvalidArgumentException.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Testing/Exceptions/InvalidArgumentException.php b/src/Illuminate/Testing/Exceptions/InvalidArgumentException.php index c05ed94d8fb4..3722c41b9eb3 100644 --- a/src/Illuminate/Testing/Exceptions/InvalidArgumentException.php +++ b/src/Illuminate/Testing/Exceptions/InvalidArgumentException.php @@ -9,6 +9,8 @@ class InvalidArgumentException extends Exception /** * Creates a new exception for an invalid argument. * + * @param int $argument + * @param string $type * @return static */ public static function create(int $argument, string $type): static From 5daf21015e64e7a76d29d3ee72f98b0e03f3591d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E9=98=B3?= Date: Tue, 26 Mar 2024 21:17:29 +0800 Subject: [PATCH 019/123] [11.x] signature typo (#50766) * typo * Update HasMiddleware.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Routing/Controllers/HasMiddleware.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Controllers/HasMiddleware.php b/src/Illuminate/Routing/Controllers/HasMiddleware.php index 3d4b262bed0b..de2b21d5a0a9 100644 --- a/src/Illuminate/Routing/Controllers/HasMiddleware.php +++ b/src/Illuminate/Routing/Controllers/HasMiddleware.php @@ -7,7 +7,7 @@ interface HasMiddleware /** * Get the middleware that should be assigned to the controller. * - * @return \Illuminate\Routing\Controllers\Middleware|array + * @return \Illuminate\Routing\Controllers\Middleware[] */ public static function middleware(); } From 5c0ad50b075c3b0d38375db96ebbf9fe91923248 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 26 Mar 2024 21:17:46 +0800 Subject: [PATCH 020/123] [11.x] Simplify `ApplicationBuilder::withSchedule()` (#50765) * Simplify `ApplicationBuilder::withSchedule()` Signed-off-by: Mior Muhammad Zaki * Apply fixes from StyleCI * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki Co-authored-by: StyleCI Bot --- .../Configuration/ApplicationBuilder.php | 4 +- .../Scheduling/ScheduleTestCommandTest.php | 7 ---- .../Configuration/WithScheduleTest.php | 41 +++++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 tests/Integration/Foundation/Configuration/WithScheduleTest.php diff --git a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php index 0e8f1913eb51..4f4469fe832a 100644 --- a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php +++ b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php @@ -290,9 +290,7 @@ protected function withCommandRouting(array $paths) */ public function withSchedule(callable $callback) { - $this->app->afterResolving(ConsoleKernel::class, function (ConsoleKernel $kernel) use ($callback) { - Artisan::starting(fn () => $callback($this->app->make(Schedule::class))); - }); + Artisan::starting(fn () => $callback($this->app->make(Schedule::class))); return $this; } diff --git a/tests/Integration/Console/Scheduling/ScheduleTestCommandTest.php b/tests/Integration/Console/Scheduling/ScheduleTestCommandTest.php index cde9883d8242..830fb0be5f79 100644 --- a/tests/Integration/Console/Scheduling/ScheduleTestCommandTest.php +++ b/tests/Integration/Console/Scheduling/ScheduleTestCommandTest.php @@ -77,13 +77,6 @@ public function testRunUsingChoices() ) ->expectsOutputToContain('Running [callback]'); } - - protected function tearDown(): void - { - parent::tearDown(); - - Carbon::setTestNow(null); - } } class BarCommandStub extends Command diff --git a/tests/Integration/Foundation/Configuration/WithScheduleTest.php b/tests/Integration/Foundation/Configuration/WithScheduleTest.php new file mode 100644 index 000000000000..767727f233be --- /dev/null +++ b/tests/Integration/Foundation/Configuration/WithScheduleTest.php @@ -0,0 +1,41 @@ + 80); + } + + protected function tearDown(): void + { + ScheduleListCommand::resolveTerminalWidthUsing(null); + + parent::tearDown(); + } + + protected function resolveApplication() + { + return Application::configure(static::applicationBasePath()) + ->withSchedule(function ($schedule) { + $schedule->command('schedule:clear-cache')->everyMinute(); + })->create(); + } + + public function testDisplaySchedule() + { + $this->artisan(ScheduleListCommand::class) + ->assertSuccessful() + ->expectsOutputToContain(' * * * * * php artisan schedule:clear-cache'); + } +} From 4a9195f68b529b20fe01e24864f99991459c48d4 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 26 Mar 2024 15:17:39 +0000 Subject: [PATCH 021/123] Update version to v11.1.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 8acc4b219b16..c0c54d21e27a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.0.8'; + const VERSION = '11.1.0'; /** * The base path for the Laravel installation. From efa867e85b4abcaab8146f66bc676b7239507719 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 26 Mar 2024 15:26:22 +0000 Subject: [PATCH 022/123] Update CHANGELOG --- CHANGELOG.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 312418c7f341..4233af25dbe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.0.8...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.1.0...11.x) + +## [v11.1.0](https://github.com/laravel/framework/compare/v11.0.8...v11.1.0) - 2024-03-26 + +* [11.x] MySQL transaction isolation level fix by [@mwikberg-virta](https://github.com/mwikberg-virta) in https://github.com/laravel/framework/pull/50689 +* [11.x] Add ListManagementOptions in SES mail transport by [@arifszn](https://github.com/arifszn) in https://github.com/laravel/framework/pull/50660 +* [11.x] Accept non-backed enum in database queries by [@gbalduzzi](https://github.com/gbalduzzi) in https://github.com/laravel/framework/pull/50674 +* [11.x] Add `Conditionable` trait to `Context` by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/50707 +* [11.x] Adds `[@throws](https://github.com/throws)` section to the Context's doc blocks by [@rnambaale](https://github.com/rnambaale) in https://github.com/laravel/framework/pull/50715 +* [11.x] Test modifying nullable columns by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/50708 +* [11.x] Introduce HASH_VERIFY env var by [@valorin](https://github.com/valorin) in https://github.com/laravel/framework/pull/50718 +* [11.x] Apply default timezone when casting unix timestamps by [@daniser](https://github.com/daniser) in https://github.com/laravel/framework/pull/50751 +* [11.x] Fixes `ApplicationBuilder::withCommandRouting()` usage by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/50742 +* [11.x] Register console commands, paths and routes after the app is booted by [@plumthedev](https://github.com/plumthedev) in https://github.com/laravel/framework/pull/50738 +* [11.x] Enhance malformed request handling by [@jnoordsij](https://github.com/jnoordsij) in https://github.com/laravel/framework/pull/50735 +* [11.x] Adds `withSchedule` to `bootstrap/app.php` file by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/framework/pull/50755 +* [11.x] Fix dock block for create method in `InvalidArgumentException.php` by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50762 +* [11.x] signature typo by [@abrahamgreyson](https://github.com/abrahamgreyson) in https://github.com/laravel/framework/pull/50766 +* [11.x] Simplify `ApplicationBuilder::withSchedule()` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/50765 ## [v11.0.8](https://github.com/laravel/framework/compare/v11.0.7...v11.0.8) - 2024-03-21 From eb94218d4e613288cacc0201ee6121232010654d Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Wed, 27 Mar 2024 14:35:02 +0800 Subject: [PATCH 023/123] Test Improvements (#50778) Signed-off-by: Mior Muhammad Zaki --- .../Foundation/FoundationHelpersTest.php | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/tests/Integration/Foundation/FoundationHelpersTest.php b/tests/Integration/Foundation/FoundationHelpersTest.php index 89554abb2a02..a55e6c73cf42 100644 --- a/tests/Integration/Foundation/FoundationHelpersTest.php +++ b/tests/Integration/Foundation/FoundationHelpersTest.php @@ -3,10 +3,10 @@ namespace Illuminate\Tests\Integration\Foundation; use Exception; -use Illuminate\Config\Repository as ConfigRepository; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\TestCase; class FoundationHelpersTest extends TestCase @@ -66,10 +66,9 @@ public function testMixReportsExceptionWhenAssetIsMissingFromManifest() unlink($manifest); } + #[WithConfig('app.debug', false)] public function testMixSilentlyFailsWhenAssetIsMissingFromManifestWhenNotInDebugMode() { - $this->app['config']->set('app.debug', false); - $manifest = $this->makeManifest(); $path = mix('missing.js'); @@ -79,13 +78,12 @@ public function testMixSilentlyFailsWhenAssetIsMissingFromManifestWhenNotInDebug unlink($manifest); } + #[WithConfig('app.debug', true)] public function testMixThrowsExceptionWhenAssetIsMissingFromManifestWhenInDebugMode() { $this->expectException(Exception::class); $this->expectExceptionMessage('Unable to locate Mix file: /missing.js.'); - $this->app['config']->set('app.debug', true); - $manifest = $this->makeManifest(); try { @@ -97,11 +95,11 @@ public function testMixThrowsExceptionWhenAssetIsMissingFromManifestWhenInDebugM } } + #[WithConfig('app.debug', true)] public function testMixOnlyThrowsAndReportsOneExceptionWhenAssetIsMissingFromManifestWhenInDebugMode() { $handler = new FakeHandler; $this->app->instance(ExceptionHandler::class, $handler); - $this->app['config']->set('app.debug', true); $manifest = $this->makeManifest(); @@ -118,20 +116,15 @@ public function testMixOnlyThrowsAndReportsOneExceptionWhenAssetIsMissingFromMan public function testFakeReturnsSameInstance() { - app()->instance('config', new ConfigRepository([])); - $this->assertSame(fake(), fake()); $this->assertSame(fake(), fake('en_US')); $this->assertSame(fake('en_AU'), fake('en_AU')); $this->assertNotSame(fake('en_US'), fake('en_AU')); - - app()->flush(); } public function testFakeUsesLocale() { mt_srand(12345, MT_RAND_PHP); - app()->instance('config', new ConfigRepository([])); // Should fallback to en_US $this->assertSame('Arkansas', fake()->state()); @@ -144,7 +137,7 @@ public function testFakeUsesLocale() 'Guadeloupe', 'Martinique', 'Guyane', 'La Réunion', 'Mayotte', ]); - app()->instance('config', new ConfigRepository(['app' => ['faker_locale' => 'en_AU']])); + config(['app.faker_locale' => 'en_AU']); mt_srand(4, MT_RAND_PHP); // Should fallback to en_US From e740b582e2d3234986b02b367ac3b561fce6e475 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Wed, 27 Mar 2024 20:09:25 +0330 Subject: [PATCH 024/123] [11.x] Fix: update `@param` in doc blocks (#50791) * fix: update @param in doc blocks * fix: update code style --- src/Illuminate/Database/Events/DatabaseRefreshed.php | 2 +- .../Database/Migrations/DatabaseMigrationRepository.php | 2 +- src/Illuminate/Foundation/Console/ChannelListCommand.php | 2 +- src/Illuminate/Support/DefaultProviders.php | 2 +- src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Events/DatabaseRefreshed.php b/src/Illuminate/Database/Events/DatabaseRefreshed.php index f476c39e43b4..4b63aefd6e63 100644 --- a/src/Illuminate/Database/Events/DatabaseRefreshed.php +++ b/src/Illuminate/Database/Events/DatabaseRefreshed.php @@ -10,7 +10,7 @@ class DatabaseRefreshed implements MigrationEventContract * Create a new event instance. * * @param string|null $database - * @param bool seeding + * @param bool $seeding * @return void */ public function __construct( diff --git a/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php b/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php index bd8ee4963129..cf020d64db06 100755 --- a/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php +++ b/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php @@ -71,7 +71,7 @@ public function getMigrations($steps) /** * Get the list of the migrations by batch number. * - * @param int $batchNumber + * @param int $batch * @return array */ public function getMigrationsByBatch($batch) diff --git a/src/Illuminate/Foundation/Console/ChannelListCommand.php b/src/Illuminate/Foundation/Console/ChannelListCommand.php index 8e4d8bacce60..7063f1addfe1 100644 --- a/src/Illuminate/Foundation/Console/ChannelListCommand.php +++ b/src/Illuminate/Foundation/Console/ChannelListCommand.php @@ -36,7 +36,7 @@ class ChannelListCommand extends Command /** * Execute the console command. * - * @param \Illuminate\Contracts\Broadcasting\Broadcaster + * @param \Illuminate\Contracts\Broadcasting\Broadcaster $broadcaster * @return void */ public function handle(Broadcaster $broadcaster) diff --git a/src/Illuminate/Support/DefaultProviders.php b/src/Illuminate/Support/DefaultProviders.php index 395b7cb9ec43..57598a614ec0 100644 --- a/src/Illuminate/Support/DefaultProviders.php +++ b/src/Illuminate/Support/DefaultProviders.php @@ -60,7 +60,7 @@ public function merge(array $providers) /** * Replace the given providers with other providers. * - * @param array $items + * @param array $replacements * @return static */ public function replace(array $replacements) diff --git a/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php b/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php index 4d1cec732ed3..4026ad2338b3 100644 --- a/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php +++ b/src/Illuminate/Support/Testing/Fakes/ChainedBatchTruthTest.php @@ -27,7 +27,7 @@ public function __construct(Closure $callback) /** * Invoke the truth test with the given pending batch. * - * @param \Illuminate\Bus\PendingBatch + * @param \Illuminate\Bus\PendingBatch $pendingBatch * @return bool */ public function __invoke($pendingBatch) From 488e251e48005d55d61b1894c359e23f7718ce24 Mon Sep 17 00:00:00 2001 From: Jacob Baker-Kretzmar Date: Wed, 27 Mar 2024 15:32:07 -0400 Subject: [PATCH 025/123] [11.x] Fix query builder `whereBetween` with CarbonPeriod and Carbon 3 (#50792) * Use `getStartDate()` and `getEndDate()` * Fix test --- src/Illuminate/Database/Query/Builder.php | 4 ++-- tests/Database/DatabaseQueryBuilderTest.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index de3ae0b839b9..0a407d8f2184 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1316,7 +1316,7 @@ public function whereBetween($column, iterable $values, $boolean = 'and', $not = $type = 'between'; if ($values instanceof CarbonPeriod) { - $values = [$values->start, $values->end]; + $values = [$values->getStartDate(), $values->getEndDate()]; } $this->wheres[] = compact('type', 'column', 'values', 'boolean', 'not'); @@ -2381,7 +2381,7 @@ public function havingBetween($column, iterable $values, $boolean = 'and', $not $type = 'between'; if ($values instanceof CarbonPeriod) { - $values = [$values->start, $values->end]; + $values = [$values->getStartDate(), $values->getEndDate()]; } $this->havings[] = compact('type', 'column', 'values', 'boolean', 'not'); diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index cbf772ba572a..1583efb63b7d 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -771,17 +771,17 @@ public function testWhereBetweens() $this->assertEquals([], $builder->getBindings()); $builder = $this->getBuilder(); - $period = now()->toPeriod(now()->addDay()); + $period = now()->startOfDay()->toPeriod(now()->addDay()->startOfDay()); $builder->select('*')->from('users')->whereBetween('created_at', $period); $this->assertSame('select * from "users" where "created_at" between ? and ?', $builder->toSql()); - $this->assertEquals([$period->start, $period->end], $builder->getBindings()); + $this->assertEquals([now()->startOfDay(), now()->addDay()->startOfDay()], $builder->getBindings()); // custom long carbon period date $builder = $this->getBuilder(); - $period = now()->toPeriod(now()->addMonth()); + $period = now()->startOfDay()->toPeriod(now()->addMonth()->startOfDay()); $builder->select('*')->from('users')->whereBetween('created_at', $period); $this->assertSame('select * from "users" where "created_at" between ? and ?', $builder->toSql()); - $this->assertEquals([$period->start, $period->end], $builder->getBindings()); + $this->assertEquals([now()->startOfDay(), now()->addMonth()->startOfDay()], $builder->getBindings()); $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereBetween('id', collect([1, 2])); From 4b4d5ad7cb3f16de423a67ca06a7982bc3536821 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Wed, 27 Mar 2024 19:55:40 +0000 Subject: [PATCH 026/123] [11.x] Allows asserting no output in Artisan commands (#50702) * Allows to test for no output console output * Apply fixes from StyleCI * Update InteractsWithConsole.php --------- Co-authored-by: StyleCI Bot Co-authored-by: Taylor Otwell --- .../Testing/Concerns/InteractsWithConsole.php | 7 ++ src/Illuminate/Testing/PendingCommand.php | 32 ++++- .../Testing/ArtisanCommandTest.php | 117 ++++++++++++++++++ 3 files changed, 152 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index c5d4e1aae60c..9c5060b3db54 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -15,6 +15,13 @@ trait InteractsWithConsole */ public $mockConsoleOutput = true; + /** + * Indicates if the command is expected to output anything. + * + * @var bool|null + */ + public $expectsOutput; + /** * All of the expected output lines. * diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index d2f75737e510..bf6a3edd5ad2 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -132,11 +132,17 @@ public function expectsChoice($question, $answer, $answers, $strict = false) /** * Specify output that should be printed when the command runs. * - * @param string $output + * @param string|null $output * @return $this */ - public function expectsOutput($output) + public function expectsOutput($output = null) { + if ($output === null) { + $this->test->expectsOutput = true; + + return $this; + } + $this->test->expectedOutput[] = $output; return $this; @@ -145,11 +151,17 @@ public function expectsOutput($output) /** * Specify output that should never be printed when the command runs. * - * @param string $output + * @param string|null $output * @return $this */ - public function doesntExpectOutput($output) + public function doesntExpectOutput($output = null) { + if ($output === null) { + $this->test->expectsOutput = false; + + return $this; + } + $this->test->unexpectedOutput[$output] = false; return $this; @@ -410,6 +422,18 @@ private function createABufferedOutputMock() ->shouldAllowMockingProtectedMethods() ->shouldIgnoreMissing(); + if ($this->test->expectsOutput === false) { + $mock->shouldReceive('doWrite')->never(); + + return $mock; + } + + if ($this->test->expectsOutput === true + && count($this->test->expectedOutput) === 0 + && count($this->test->expectedOutputSubstrings) === 0) { + $mock->shouldReceive('doWrite')->atLeast()->once(); + } + foreach ($this->test->expectedOutput as $i => $output) { $mock->shouldReceive('doWrite') ->once() diff --git a/tests/Integration/Testing/ArtisanCommandTest.php b/tests/Integration/Testing/ArtisanCommandTest.php index 1592d63dfea8..08cd327e0582 100644 --- a/tests/Integration/Testing/ArtisanCommandTest.php +++ b/tests/Integration/Testing/ArtisanCommandTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Testing; +use Illuminate\Console\Command; use Illuminate\Support\Facades\Artisan; use Mockery as m; use Mockery\Exception\InvalidCountException; @@ -33,6 +34,22 @@ protected function setUp(): void $this->line($this->ask('Huh?')); }); + Artisan::command('interactions', function () { + /** @var Command $this */ + $this->ask('What is your name?'); + $this->choice('Which language do you prefer?', [ + 'PHP', + 'PHP', + 'PHP', + ]); + + $this->table(['Name', 'Email'], [ + ['Taylor Otwell', 'taylor@laravel.com'], + ]); + + $this->confirm('Do you want to continue?', true); + }); + Artisan::command('exit {code}', fn () => (int) $this->argument('code')); Artisan::command('contains', function () { @@ -146,6 +163,106 @@ public function test_console_command_that_passes_if_the_output_contains() ->assertExitCode(0); } + public function test_console_command_that_passes_if_outputs_something() + { + $this->artisan('contains') + ->expectsOutput() + ->assertExitCode(0); + } + + public function test_console_command_that_passes_if_outputs_is_something_and_is_the_expected_output() + { + $this->artisan('contains') + ->expectsOutput() + ->expectsOutput('My name is Taylor Otwell') + ->assertExitCode(0); + } + + public function test_console_command_that_fail_if_doesnt_output_something() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('exit', ['code' => 0]) + ->expectsOutput() + ->assertExitCode(0); + + m::close(); + } + + public function test_console_command_that_fail_if_doesnt_output_something_and_is_not_the_expected_output() + { + $this->expectException(AssertionFailedError::class); + + $this->ignoringMockOnceExceptions(function () { + $this->artisan('exit', ['code' => 0]) + ->expectsOutput() + ->expectsOutput('My name is Taylor Otwell') + ->assertExitCode(0); + }); + } + + public function test_console_command_that_passes_if_does_not_output_anything() + { + $this->artisan('exit', ['code' => 0]) + ->doesntExpectOutput() + ->assertExitCode(0); + } + + public function test_console_command_that_passes_if_does_not_output_anything_and_is_not_the_expected_output() + { + $this->artisan('exit', ['code' => 0]) + ->doesntExpectOutput() + ->doesntExpectOutput('My name is Taylor Otwell') + ->assertExitCode(0); + } + + public function test_console_command_that_passes_if_expects_output_and_there_is_interactions() + { + $this->artisan('interactions', ['--no-interaction' => true]) + ->expectsOutput() + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsChoice('Which language do you prefer?', 'PHP', ['PHP', 'PHP', 'PHP']) + ->expectsConfirmation('Do you want to continue?', true) + ->assertExitCode(0); + } + + public function test_console_command_that_fails_if_doesnt_expect_output_but__there_is_interactions() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('interactions', ['--no-interaction' => true]) + ->doesntExpectOutput() + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsChoice('Which language do you prefer?', 'PHP', ['PHP', 'PHP', 'PHP']) + ->expectsConfirmation('Do you want to continue?', true) + ->assertExitCode(0); + + m::close(); + } + + public function test_console_command_that_fails_if_doesnt_expect_output_but_outputs_something() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('contains') + ->doesntExpectOutput() + ->assertExitCode(0); + + m::close(); + } + + public function test_console_command_that_fails_if_doesnt_expect_output_and_does_expect_output() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('contains') + ->doesntExpectOutput() + ->doesntExpectOutput('My name is Taylor Otwell') + ->assertExitCode(0); + + m::close(); + } + public function test_console_command_that_fails_if_the_output_does_not_contain() { $this->expectException(AssertionFailedError::class); From 53901cdbbcfba0f231f2c45f336d1fab5a72392a Mon Sep 17 00:00:00 2001 From: Antonio Date: Thu, 28 Mar 2024 12:17:42 +0100 Subject: [PATCH 027/123] fix typo (#50808) --- src/Illuminate/Encryption/Encrypter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Encryption/Encrypter.php b/src/Illuminate/Encryption/Encrypter.php index 003bbfbffc87..e3e03bb9f950 100755 --- a/src/Illuminate/Encryption/Encrypter.php +++ b/src/Illuminate/Encryption/Encrypter.php @@ -335,7 +335,7 @@ public function getPreviousKeys() /** * Set the previous / legacy encryption keys that should be utilized if decryption fails. * - * @param array $key + * @param array $keys * @return $this */ public function previousKeys(array $keys) From 7bc70f29ba7a8cee2cac1bba758d968ba4927fdf Mon Sep 17 00:00:00 2001 From: Dima Kondrashov Date: Thu, 28 Mar 2024 15:00:29 +0100 Subject: [PATCH 028/123] Detect lost redis connection (#50812) --- 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 32492eb0729c..f946f35dc59c 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -71,6 +71,7 @@ protected function causedByLostConnection(Throwable $e) 'SQLSTATE[HY000] [2002] The requested address is not valid in its context', 'SQLSTATE[HY000] [2002] A socket operation was attempted to an unreachable network', 'SQLSTATE[HY000]: General error: 3989', + 'went away', ]); } } From f25fcd2061cd3c01be0cd74e5e72a4a15aaa0583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1nos=20Hajdu?= <40004107+SajtiDH@users.noreply.github.com> Date: Thu, 28 Mar 2024 15:12:19 +0100 Subject: [PATCH 029/123] [11.x] Make DB::usingConnection() respect read/write type (#50806) * Resolving default connection name before parsing it * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Database/DatabaseManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/DatabaseManager.php b/src/Illuminate/Database/DatabaseManager.php index 9239fca06f90..cf408bc68785 100755 --- a/src/Illuminate/Database/DatabaseManager.php +++ b/src/Illuminate/Database/DatabaseManager.php @@ -81,9 +81,9 @@ public function __construct($app, ConnectionFactory $factory) */ public function connection($name = null) { - [$database, $type] = $this->parseConnectionName($name); + $name = $name ?: $this->getDefaultConnection(); - $name = $name ?: $database; + [$database, $type] = $this->parseConnectionName($name); // If we haven't created this connection, we'll create it based on the config // provided in the application. Once we've created the connections we will From 71561e76a5bf33d0696ae5216826ecd5065673d4 Mon Sep 17 00:00:00 2001 From: Jack Webb-Heller Date: Thu, 28 Mar 2024 15:05:30 +0000 Subject: [PATCH 030/123] Fix deprecation warning in Carbon 3.2 (#50813) --- src/Illuminate/Cache/Repository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 469e075feb4a..ab219c308efc 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -548,7 +548,7 @@ protected function getSeconds($ttl) $duration = $this->parseDateInterval($ttl); if ($duration instanceof DateTimeInterface) { - $duration = Carbon::now()->diffInRealSeconds($duration, false); + $duration = Carbon::now()->diffInSeconds($duration, false); } return (int) ($duration > 0 ? $duration : 0); From 1437cea6d2b04cbc83743fbb208e1a01efccd9ec Mon Sep 17 00:00:00 2001 From: driesvints Date: Thu, 28 Mar 2024 15:07:18 +0000 Subject: [PATCH 031/123] Update version to v11.1.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index c0c54d21e27a..41a3b2065989 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.1.0'; + const VERSION = '11.1.1'; /** * The base path for the Laravel installation. From 954c226343f438c453019019c00eb3ae54923b2c Mon Sep 17 00:00:00 2001 From: driesvints Date: Thu, 28 Mar 2024 15:30:56 +0000 Subject: [PATCH 032/123] Update CHANGELOG --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4233af25dbe3..a12ce8194534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.1.0...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.1.1...11.x) + +## [v11.1.1](https://github.com/laravel/framework/compare/v11.1.0...v11.1.1) - 2024-03-28 + +* [11.x] Fix: update `[@param](https://github.com/param)` in doc blocks by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50791 +* [11.x] Fix query builder `whereBetween` with CarbonPeriod and Carbon 3 by [@bakerkretzmar](https://github.com/bakerkretzmar) in https://github.com/laravel/framework/pull/50792 +* [11.x] Allows asserting no output in Artisan commands by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/framework/pull/50702 +* fix typo by [@elguitarraverde](https://github.com/elguitarraverde) in https://github.com/laravel/framework/pull/50808 +* [11.x] Make DB::usingConnection() respect read/write type by [@SajtiDH](https://github.com/SajtiDH) in https://github.com/laravel/framework/pull/50806 +* [11.x] Fix deprecation warning caused by Carbon 3.2 by [@JackWH](https://github.com/JackWH) in https://github.com/laravel/framework/pull/50813 ## [v11.1.0](https://github.com/laravel/framework/compare/v11.0.8...v11.1.0) - 2024-03-26 From 694e51aed2c9a2dc46a2594f27feb8573ca04f24 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Fri, 29 Mar 2024 12:26:39 +0330 Subject: [PATCH 033/123] [11.x] Fix: update `@param` in some doc block (#50827) * fix: update @param in some doc block * fix code style * Update src/Illuminate/Console/Signals.php --------- Co-authored-by: Dries Vints --- src/Illuminate/Console/Signals.php | 2 +- src/Illuminate/Foundation/Exceptions/Handler.php | 2 +- src/Illuminate/Foundation/Vite.php | 2 +- src/Illuminate/Mail/Mailables/Headers.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Console/Signals.php b/src/Illuminate/Console/Signals.php index 106b54d14319..f998f0ed52ba 100644 --- a/src/Illuminate/Console/Signals.php +++ b/src/Illuminate/Console/Signals.php @@ -142,7 +142,7 @@ protected function setHandlers($handlers) /** * Set the availability resolver. * - * @param callable(): bool + * @param (callable(): bool) $resolver * @return void */ public static function resolveAvailabilityUsing($resolver) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 791f2cc69812..7d049553737e 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -277,7 +277,7 @@ public function dontReport(array|string $exceptions) /** * Indicate that the given exception type should not be reported. * - * @param array|string $class + * @param array|string $exceptions * @return $this */ public function ignore(array|string $exceptions) diff --git a/src/Illuminate/Foundation/Vite.php b/src/Illuminate/Foundation/Vite.php index a81ca1616b96..0116a5bf7025 100644 --- a/src/Illuminate/Foundation/Vite.php +++ b/src/Illuminate/Foundation/Vite.php @@ -170,7 +170,7 @@ public function useManifestFilename($filename) /** * Resolve asset paths using the provided resolver. * - * @param callable|null $urlResolver + * @param callable|null $resolver * @return $this */ public function createAssetPathsUsing($resolver) diff --git a/src/Illuminate/Mail/Mailables/Headers.php b/src/Illuminate/Mail/Mailables/Headers.php index 87cee52b4768..71080873a819 100644 --- a/src/Illuminate/Mail/Mailables/Headers.php +++ b/src/Illuminate/Mail/Mailables/Headers.php @@ -76,7 +76,7 @@ public function references(array $references) /** * Set the headers for this message. * - * @param array $references + * @param array $text * @return $this */ public function text(array $text) From 1da00500581e5ac44fe6a2b8f3ec124e9c5b9f41 Mon Sep 17 00:00:00 2001 From: driesvints Date: Fri, 29 Mar 2024 08:57:05 +0000 Subject: [PATCH 034/123] Update facade docblocks --- src/Illuminate/Support/Facades/Vite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php index 2f37c6753420..d475d2c1fe59 100644 --- a/src/Illuminate/Support/Facades/Vite.php +++ b/src/Illuminate/Support/Facades/Vite.php @@ -9,7 +9,7 @@ * @method static \Illuminate\Foundation\Vite useIntegrityKey(string|false $key) * @method static \Illuminate\Foundation\Vite withEntryPoints(array $entryPoints) * @method static \Illuminate\Foundation\Vite useManifestFilename(string $filename) - * @method static \Illuminate\Foundation\Vite createAssetPathsUsing(void $resolver) + * @method static \Illuminate\Foundation\Vite createAssetPathsUsing(callable|null $resolver) * @method static string hotFile() * @method static \Illuminate\Foundation\Vite useHotFile(string $path) * @method static \Illuminate\Foundation\Vite useBuildDirectory(string $path) From 21d32cc25f10428d42c96f891c43968a01c52272 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Fri, 29 Mar 2024 12:28:54 +0330 Subject: [PATCH 035/123] [11.x] Fix: update @return in some doc blocks (#50826) * fix: update @return in som doc blocks * Update src/Illuminate/Filesystem/LockableFile.php Co-authored-by: Mior Muhammad Zaki --------- Co-authored-by: Mior Muhammad Zaki --- src/Illuminate/Filesystem/LockableFile.php | 2 +- tests/Redis/RedisManagerExtensionTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Filesystem/LockableFile.php b/src/Illuminate/Filesystem/LockableFile.php index d354b884036a..80a3b8a13c51 100644 --- a/src/Illuminate/Filesystem/LockableFile.php +++ b/src/Illuminate/Filesystem/LockableFile.php @@ -144,7 +144,7 @@ public function getSharedLock($block = false) * Get an exclusive lock on the file. * * @param bool $block - * @return bool + * @return $this * * @throws \Illuminate\Contracts\Filesystem\LockTimeoutException */ diff --git a/tests/Redis/RedisManagerExtensionTest.php b/tests/Redis/RedisManagerExtensionTest.php index 5cac41877cc2..6baac48d8eb2 100644 --- a/tests/Redis/RedisManagerExtensionTest.php +++ b/tests/Redis/RedisManagerExtensionTest.php @@ -98,7 +98,7 @@ class FakeRedisConnector implements Connector * * @param array $config * @param array $options - * @return \Illuminate\Contracts\Redis\Connection + * @return string */ public function connect(array $config, array $options) { @@ -111,7 +111,7 @@ public function connect(array $config, array $options) * @param array $config * @param array $clusterOptions * @param array $options - * @return \Illuminate\Contracts\Redis\Connection + * @return string */ public function connectToCluster(array $config, array $clusterOptions, array $options) { From fd4edf409637dcf9a71f64a57d017dc6f37a19aa Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 29 Mar 2024 17:42:34 +0330 Subject: [PATCH 036/123] [11.x] Fix retrieving generated columns on legacy PostgreSQL (#50834) * fix retrieving generated column on pgsql < 12 * flip the condition --- src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 5aa785a88a75..db487e1509eb 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -123,7 +123,7 @@ public function compileColumns($schema, $table) .'(select tc.collcollate from pg_catalog.pg_collation tc where tc.oid = a.attcollation) as collation, ' .'not a.attnotnull as nullable, ' .'(select pg_get_expr(adbin, adrelid) from pg_attrdef where c.oid = pg_attrdef.adrelid and pg_attrdef.adnum = a.attnum) as default, ' - .'a.attgenerated as generated, ' + .(version_compare($this->connection?->getServerVersion(), '12.0', '<') ? "'' as generated, " : 'a.attgenerated as generated, ') .'col_description(c.oid, a.attnum) as comment ' .'from pg_attribute a, pg_class c, pg_type t, pg_namespace n ' .'where c.relname = %s and n.nspname = %s and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid and n.oid = c.relnamespace ' From ade3b6ba458457d560c977732f0d4280a941649f Mon Sep 17 00:00:00 2001 From: Dasun Tharanga Date: Fri, 29 Mar 2024 19:42:55 +0530 Subject: [PATCH 037/123] [11.x] Trim invisible characters (#50832) * fix: Trim invisible characters * test: Add test cases * fix: Regex pattern --- .../Http/Middleware/TrimStrings.php | 2 +- tests/Http/Middleware/TrimStringsTest.php | 90 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php index f5ad195b0325..0edc84376205 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php +++ b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php @@ -65,7 +65,7 @@ protected function transform($key, $value) return $value; } - return preg_replace('~^[\s\x{FEFF}\x{200B}]+|[\s\x{FEFF}\x{200B}]+$~u', '', $value) ?? trim($value); + return preg_replace('~^[\s\x{FEFF}\x{200B}\x{200E}]+|[\s\x{FEFF}\x{200B}\x{200E}]+$~u', '', $value) ?? trim($value); } /** diff --git a/tests/Http/Middleware/TrimStringsTest.php b/tests/Http/Middleware/TrimStringsTest.php index 98302534b6a5..4fa0f3f623c7 100644 --- a/tests/Http/Middleware/TrimStringsTest.php +++ b/tests/Http/Middleware/TrimStringsTest.php @@ -132,4 +132,94 @@ public function test_combination_of_leading_and_trailing_zero_width_non_breakabl $this->assertEquals('This title contains a combination of zero-width non-breakable space and zero-width spaces characters at the beginning and the end', $req->title); }); } + + /** + * Test leading invisible character are trimmed [U+200E]. + */ + public function test_leading_invisible_characters_are_trimmed() + { + $request = new Request; + + $request->merge([ + 'title' => '‎This title contains a invisible character at the beginning', + ]); + + $middleware = new TrimStrings; + + $middleware->handle($request, function ($req) { + $this->assertEquals('This title contains a invisible character at the beginning', $req->title); + }); + } + + /** + * Test trailing invisible character are trimmed [U+200E]. + */ + public function test_trailing_invisible_characters_are_trimmed() + { + $request = new Request; + + $request->merge([ + 'title' => 'This title contains a invisible character at the end‎', + ]); + + $middleware = new TrimStrings; + + $middleware->handle($request, function ($req) { + $this->assertEquals('This title contains a invisible character at the end', $req->title); + }); + } + + /** + * Test leading multiple invisible character are trimmed [U+200E]. + */ + public function test_leading_multiple_invisible_characters_are_trimmed() + { + $request = new Request; + + $request->merge([ + 'title' => '‎‎This title contains a invisible character at the beginning', + ]); + + $middleware = new TrimStrings; + + $middleware->handle($request, function ($req) { + $this->assertEquals('This title contains a invisible character at the beginning', $req->title); + }); + } + + /** + * Test trailing multiple invisible character are trimmed [U+200E]. + */ + public function test_trailing_multiple_invisible_characters_are_trimmed() + { + $request = new Request; + + $request->merge([ + 'title' => 'This title contains a invisible character at the end‎‎', + ]); + + $middleware = new TrimStrings; + + $middleware->handle($request, function ($req) { + $this->assertEquals('This title contains a invisible character at the end', $req->title); + }); + } + + /** + * Test combination of leading and trailing multiple invisible characters are trimmed [U+200E]. + */ + public function test_combination_of_leading_and_trailing_multiple_invisible_characters_are_trimmed() + { + $request = new Request; + + $request->merge([ + 'title' => '‎‎This title contains a combination of a invisible character at beginning and the end‎‎', + ]); + + $middleware = new TrimStrings; + + $middleware->handle($request, function ($req) { + $this->assertEquals('This title contains a combination of a invisible character at beginning and the end', $req->title); + }); + } } From 61f3908f0386134cdd87bc6d8053c57403c418ba Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:14:12 +0200 Subject: [PATCH 038/123] [11.x] Add default value for `get` and `getHidden` on `Context` (#50824) * Add default value for `get` and `getHidden` on `Context` * Update Repository.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Log/Context/Repository.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Log/Context/Repository.php b/src/Illuminate/Log/Context/Repository.php index 47ca1b916735..13b2b2b30d84 100644 --- a/src/Illuminate/Log/Context/Repository.php +++ b/src/Illuminate/Log/Context/Repository.php @@ -99,22 +99,24 @@ public function allHidden() * Retrieve the given key's value. * * @param string $key + * @param mixed $default * @return mixed */ - public function get($key) + public function get($key, $default = null) { - return $this->data[$key] ?? null; + return $this->data[$key] ?? value($default); } /** * Retrieve the given key's hidden value. * * @param string $key + * @param mixed $default * @return mixed */ - public function getHidden($key) + public function getHidden($key, $default = null) { - return $this->hidden[$key] ?? null; + return $this->hidden[$key] ?? value($default); } /** From bcc30449455e333f861892c19fc0ee7699d66a33 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 29 Mar 2024 14:15:32 +0000 Subject: [PATCH 039/123] Improves serve command (#50821) --- .../Foundation/Console/ServeCommand.php | 117 +++++++++++------- 1 file changed, 74 insertions(+), 43 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ServeCommand.php b/src/Illuminate/Foundation/Console/ServeCommand.php index a73bf52ef5c1..0c9cd9f5e6b1 100644 --- a/src/Illuminate/Foundation/Console/ServeCommand.php +++ b/src/Illuminate/Foundation/Console/ServeCommand.php @@ -36,6 +36,13 @@ class ServeCommand extends Command */ protected $portOffset = 0; + /** + * The list of lines that are pending to be output. + * + * @var string + */ + protected $outputBuffer = ''; + /** * The list of requests being handled and their start time. * @@ -245,68 +252,92 @@ protected function canTryAnotherPort() */ protected function handleProcessOutput() { - return fn ($type, $buffer) => str($buffer)->explode("\n")->each(function ($line) { - if (str($line)->contains('Development Server (http')) { - if ($this->serverRunningHasBeenDisplayed) { - return; - } + return function ($type, $buffer) { + $this->outputBuffer .= $buffer; - $this->components->info("Server running on [http://{$this->host()}:{$this->port()}]."); - $this->comment(' Press Ctrl+C to stop the server'); + $this->flushOutputBuffer(); + }; + } - $this->newLine(); + /** + * Flush the output buffer. + * + * @return void + */ + protected function flushOutputBuffer() + { + $lines = str($this->outputBuffer)->explode("\n"); + + $this->outputBuffer = (string) $lines->pop(); - $this->serverRunningHasBeenDisplayed = true; - } elseif (str($line)->contains(' Accepted')) { - $requestPort = $this->getRequestPortFromLine($line); + $lines + ->map(fn ($line) => trim($line)) + ->filter() + ->each(function ($line) { + if (str($line)->contains('Development Server (http')) { + if ($this->serverRunningHasBeenDisplayed === false) { + $this->serverRunningHasBeenDisplayed = true; - $this->requestsPool[$requestPort] = [ - $this->getDateFromLine($line), - false, - ]; - } elseif (str($line)->contains([' [200]: GET '])) { - $requestPort = $this->getRequestPortFromLine($line); + $this->components->info("Server running on [http://{$this->host()}:{$this->port()}]."); + $this->comment(' Press Ctrl+C to stop the server'); - $this->requestsPool[$requestPort][1] = trim(explode('[200]: GET', $line)[1]); - } elseif (str($line)->contains(' Closing')) { - $requestPort = $this->getRequestPortFromLine($line); + $this->newLine(); + } - if (empty($this->requestsPool[$requestPort])) { return; } - [$startDate, $file] = $this->requestsPool[$requestPort]; + if (str($line)->contains(' Accepted')) { + $requestPort = $this->getRequestPortFromLine($line); - $formattedStartedAt = $startDate->format('Y-m-d H:i:s'); + $this->requestsPool[$requestPort] = [ + $this->getDateFromLine($line), + false, + ]; + } elseif (str($line)->contains([' [200]: GET '])) { + $requestPort = $this->getRequestPortFromLine($line); - unset($this->requestsPool[$requestPort]); + $this->requestsPool[$requestPort][1] = trim(explode('[200]: GET', $line)[1]); + } elseif (str($line)->contains(' Closing')) { + $requestPort = $this->getRequestPortFromLine($line); - [$date, $time] = explode(' ', $formattedStartedAt); + if (empty($this->requestsPool[$requestPort])) { + $this->requestsPool[$requestPort] = [ + $this->getDateFromLine($line), + false, + ]; + } - $this->output->write(" $date $time"); + [$startDate, $file] = $this->requestsPool[$requestPort]; - $runTime = $this->getDateFromLine($line)->diffInSeconds($startDate); + $formattedStartedAt = $startDate->format('Y-m-d H:i:s'); - if ($file) { - $this->output->write($file = " $file"); - } + unset($this->requestsPool[$requestPort]); - $dots = max(terminal()->width() - mb_strlen($formattedStartedAt) - mb_strlen($file) - mb_strlen($runTime) - 9, 0); + [$date, $time] = explode(' ', $formattedStartedAt); - $this->output->write(' '.str_repeat('.', $dots)); - $this->output->writeln(" ~ {$runTime}s"); - } elseif (str($line)->contains(['Closed without sending a request'])) { - // ... - } elseif (! empty($line)) { - $position = strpos($line, '] '); + $this->output->write(" $date $time"); - if ($position !== false) { - $line = substr($line, $position + 1); - } + $runTime = $this->getDateFromLine($line)->diffInSeconds($startDate); - $this->components->warn($line); - } - }); + if ($file) { + $this->output->write($file = " $file"); + } + + $dots = max(terminal()->width() - mb_strlen($formattedStartedAt) - mb_strlen($file) - mb_strlen($runTime) - 9, 0); + + $this->output->write(' '.str_repeat('.', $dots)); + $this->output->writeln(" ~ {$runTime}s"); + } elseif (str($line)->contains(['Closed without sending a request', 'Failed to poll event'])) { + // ... + } elseif (! empty($line)) { + if (str($line)->startsWith('[')) { + $line = str($line)->after('] '); + } + + $this->output->writeln(" $line"); + } + }); } /** From c8dfb41c322792e1ac8b24a49b11847c7e4a6721 Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Fri, 29 Mar 2024 14:17:05 +0000 Subject: [PATCH 040/123] Update facade docblocks --- src/Illuminate/Support/Facades/Context.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Facades/Context.php b/src/Illuminate/Support/Facades/Context.php index 7ee4f40c003c..ef77e87ba815 100644 --- a/src/Illuminate/Support/Facades/Context.php +++ b/src/Illuminate/Support/Facades/Context.php @@ -7,8 +7,8 @@ * @method static bool hasHidden(string $key) * @method static array all() * @method static array allHidden() - * @method static mixed get(string $key) - * @method static mixed getHidden(string $key) + * @method static mixed get(string $key, mixed $default = null) + * @method static mixed getHidden(string $key, mixed $default = null) * @method static array only(array $keys) * @method static array onlyHidden(array $keys) * @method static \Illuminate\Log\Context\Repository add(string|array $key, mixed $value = null) From a6de7c6c3a9559d7a3004fe5204c85f7115100a4 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:32:53 +0100 Subject: [PATCH 041/123] [11.x] Rehash user passwords when logging in once (#50843) * Rehash user passwords when validating credentials * Update SessionGuard.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Auth/SessionGuard.php | 2 ++ tests/Auth/AuthGuardTest.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 7966eaa7da12..a88e213dbb5c 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -253,6 +253,8 @@ public function once(array $credentials = []) $this->fireAttemptEvent($credentials); if ($this->validate($credentials)) { + $this->rehashPasswordIfRequired($this->lastAttempted, $credentials); + $this->setUser($this->lastAttempted); return true; diff --git a/tests/Auth/AuthGuardTest.php b/tests/Auth/AuthGuardTest.php index e75efd642c37..d7df6decea9d 100755 --- a/tests/Auth/AuthGuardTest.php +++ b/tests/Auth/AuthGuardTest.php @@ -623,6 +623,7 @@ public function testLoginOnceSetsUser() }); $guard->getProvider()->shouldReceive('retrieveByCredentials')->once()->with(['foo'])->andReturn($user); $guard->getProvider()->shouldReceive('validateCredentials')->once()->with($user, ['foo'])->andReturn(true); + $guard->getProvider()->shouldReceive('rehashPasswordIfRequired')->with($user, ['foo'])->once(); $guard->shouldReceive('setUser')->once()->with($user); $this->assertTrue($guard->once(['foo'])); } @@ -637,6 +638,7 @@ public function testLoginOnceFailure() }); $guard->getProvider()->shouldReceive('retrieveByCredentials')->once()->with(['foo'])->andReturn($user); $guard->getProvider()->shouldReceive('validateCredentials')->once()->with($user, ['foo'])->andReturn(false); + $guard->getProvider()->shouldNotReceive('rehashPasswordIfRequired'); $this->assertFalse($guard->once(['foo'])); } From 679cb581a9be930e4481346f60b73bb77930688d Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 29 Mar 2024 15:37:01 +0100 Subject: [PATCH 042/123] [11.x] Do not wipe database if it does not exists (#50838) * Do not wipe database if it does not exists * wip --- .../Console/Migrations/FreshCommand.php | 37 +++++++++++++++---- .../Database/MigrationServiceProvider.php | 4 +- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Console/Migrations/FreshCommand.php b/src/Illuminate/Database/Console/Migrations/FreshCommand.php index 41d75ade559f..133de41ef7e1 100644 --- a/src/Illuminate/Database/Console/Migrations/FreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/FreshCommand.php @@ -6,6 +6,7 @@ use Illuminate\Console\ConfirmableTrait; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Events\DatabaseRefreshed; +use Illuminate\Database\Migrations\Migrator; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; @@ -28,6 +29,26 @@ class FreshCommand extends Command */ protected $description = 'Drop all tables and re-run all migrations'; + /** + * The migrator instance. + * + * @var \Illuminate\Database\Migrations\Migrator + */ + protected $migrator; + + /** + * Create a new fresh command instance. + * + * @param \Illuminate\Database\Migrations\Migrator $migrator + * @return void + */ + public function __construct(Migrator $migrator) + { + parent::__construct(); + + $this->migrator = $migrator; + } + /** * Execute the console command. * @@ -41,14 +62,16 @@ public function handle() $database = $this->input->getOption('database'); - $this->newLine(); + if ($this->migrator->repositoryExists()) { + $this->newLine(); - $this->components->task('Dropping all tables', fn () => $this->callSilent('db:wipe', array_filter([ - '--database' => $database, - '--drop-views' => $this->option('drop-views'), - '--drop-types' => $this->option('drop-types'), - '--force' => true, - ])) == 0); + $this->components->task('Dropping all tables', fn () => $this->callSilent('db:wipe', array_filter([ + '--database' => $database, + '--drop-views' => $this->option('drop-views'), + '--drop-types' => $this->option('drop-types'), + '--force' => true, + ])) == 0); + } $this->newLine(); diff --git a/src/Illuminate/Database/MigrationServiceProvider.php b/src/Illuminate/Database/MigrationServiceProvider.php index 4dad13838cb3..cab266bb2f9d 100755 --- a/src/Illuminate/Database/MigrationServiceProvider.php +++ b/src/Illuminate/Database/MigrationServiceProvider.php @@ -130,7 +130,9 @@ protected function registerMigrateCommand() */ protected function registerMigrateFreshCommand() { - $this->app->singleton(FreshCommand::class); + $this->app->singleton(FreshCommand::class, function ($app) { + return new FreshCommand($app['migrator']); + }); } /** From aa22a812b03f98dab009a1debe54784ba9c93a12 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 29 Mar 2024 15:39:01 +0100 Subject: [PATCH 043/123] [11.x] Better database creation failure handling (#50836) * Better database creation failure handling * Update MigrateCommand.php * Update MigrateCommand.php --------- Co-authored-by: Taylor Otwell --- .../Database/Console/Migrations/MigrateCommand.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php index 2b07dc94a540..2db166a88937 100755 --- a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php @@ -10,6 +10,7 @@ use Illuminate\Database\SQLiteDatabaseDoesNotExistException; use Illuminate\Database\SqlServerConnection; use PDOException; +use RuntimeException; use Symfony\Component\Console\Attribute\AsCommand; use Throwable; @@ -187,6 +188,8 @@ protected function repositoryExists() * * @param string $path * @return bool + * + * @throws \RuntimeException */ protected function createMissingSqliteDatabase($path) { @@ -201,7 +204,9 @@ protected function createMissingSqliteDatabase($path) $this->components->warn('The SQLite database configured for this application does not exist: '.$path); if (! confirm('Would you like to create it?', default: true)) { - return false; + $this->components->info('Operation cancelled. No database was created.'); + + throw new RuntimeException('Database was not created. Aborting migration.'); } return touch($path); @@ -211,6 +216,8 @@ protected function createMissingSqliteDatabase($path) * Create a missing MySQL database. * * @return bool + * + * @throws \RuntimeException */ protected function createMissingMysqlDatabase($connection) { @@ -226,7 +233,9 @@ protected function createMissingMysqlDatabase($connection) $this->components->warn("The database '{$connection->getDatabaseName()}' does not exist on the '{$connection->getName()}' connection."); if (! confirm('Would you like to create it?', default: true)) { - return false; + $this->components->info('Operation cancelled. No database was created.'); + + throw new RuntimeException('Database was not created. Aborting migration.'); } } From 978ee8887801d4000a73591c6ca19805bf4c229a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2024 09:51:06 -0500 Subject: [PATCH 044/123] allow event discovery to be disabled --- .../Configuration/ApplicationBuilder.php | 10 +++++++--- .../Providers/EventServiceProvider.php | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php index 4f4469fe832a..5419666cee3f 100644 --- a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php +++ b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php @@ -83,15 +83,19 @@ public function withProviders(array $providers = [], bool $withBootstrapProvider /** * Register the core event service provider for the application. * - * @param array $discover + * @param array|bool $discover * @return $this */ - public function withEvents(array $discover = []) + public function withEvents(array|bool $discover = []) { - if (count($discover) > 0) { + if (is_array($discover) && count($discover) > 0) { AppEventServiceProvider::setEventDiscoveryPaths($discover); } + if ($discover === false) { + AppEventServiceProvider::disableEventDiscovery(); + } + if (! isset($this->pendingProviders[AppEventServiceProvider::class])) { $this->app->booting(function () { $this->app->register(AppEventServiceProvider::class); diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 69f4e63f28f4..ef568c10ee8b 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -32,6 +32,13 @@ class EventServiceProvider extends ServiceProvider */ protected $observers = []; + /** + * Indiates if events should be discovered. + * + * @var bool + */ + protected static $shouldDiscoverEvents = true; + /** * The configured event discovery paths. * @@ -127,7 +134,7 @@ protected function discoveredEvents() */ public function shouldDiscoverEvents() { - return get_class($this) === __CLASS__; + return get_class($this) === __CLASS__ && static::$shouldDiscoverEvents === true; } /** @@ -182,6 +189,16 @@ protected function eventDiscoveryBasePath() return base_path(); } + /** + * Disable event discovery for the application. + * + * @return void + */ + public static function disableEventDiscovery() + { + static::$shouldDiscoverEvents = false; + } + /** * Configure the proper event listeners for email verification. * From a8a40d9bb151f42b1d6cfe8bd05a3f4a39fec728 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 1 Apr 2024 08:24:24 +0800 Subject: [PATCH 045/123] [10.x] Test Improvements (#50864) Use `#[RequiresOperatingSystem('Linux|DAR')]` instead of checking `windows_os()` Signed-off-by: Mior Muhammad Zaki --- tests/Process/ProcessTest.php | 61 ++++++++--------------------------- 1 file changed, 13 insertions(+), 48 deletions(-) diff --git a/tests/Process/ProcessTest.php b/tests/Process/ProcessTest.php index 4557004e1d1a..4c914b2e9698 100644 --- a/tests/Process/ProcessTest.php +++ b/tests/Process/ProcessTest.php @@ -7,6 +7,7 @@ use Illuminate\Process\Exceptions\ProcessTimedOutException; use Illuminate\Process\Factory; use OutOfBoundsException; +use PHPUnit\Framework\Attributes\RequiresOperatingSystem; use PHPUnit\Framework\TestCase; use RuntimeException; @@ -424,12 +425,9 @@ public function testFakeProcessesDontThrowIfFalse() $this->assertTrue(true); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanHaveErrorOutput() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory; $result = $factory->path(__DIR__)->run('echo "Hello World" >&2; exit 1;'); @@ -455,12 +453,9 @@ public function testFakeProcessesCanThrowWithoutOutput() $result->throw(); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanThrowWithoutOutput() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $this->expectException(ProcessFailedException::class); $this->expectExceptionMessage(<<<'EOT' The command "exit 1;" failed. @@ -496,12 +491,9 @@ public function testFakeProcessesCanThrowWithErrorOutput() $result->throw(); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanThrowWithErrorOutput() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $this->expectException(ProcessFailedException::class); $this->expectExceptionMessage(<<<'EOT' The command "echo "Hello World" >&2; exit 1;" failed. @@ -541,12 +533,9 @@ public function testFakeProcessesCanThrowWithOutput() $result->throw(); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanThrowWithOutput() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $this->expectException(ProcessFailedException::class); $this->expectExceptionMessage(<<<'EOT' The command "echo "Hello World" >&1; exit 1;" failed. @@ -565,12 +554,9 @@ public function testRealProcessesCanThrowWithOutput() $result->throw(); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanTimeout() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $this->expectException(ProcessTimedOutException::class); $this->expectExceptionMessage( 'The process "sleep 2; exit 1;" exceeded the timeout of 1 seconds.' @@ -582,12 +568,9 @@ public function testRealProcessesCanTimeout() $result->throw(); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanThrowIfTrue() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $this->expectException(ProcessFailedException::class); $factory = new Factory; @@ -596,12 +579,9 @@ public function testRealProcessesCanThrowIfTrue() $result->throwIf(true); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesDoesntThrowIfFalse() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory; $result = $factory->path(__DIR__)->run('echo "Hello World" >&2; exit 1;'); @@ -610,24 +590,18 @@ public function testRealProcessesDoesntThrowIfFalse() $this->assertTrue(true); } + #[RequiresOperatingSystem('Linux|DAR')] public function testRealProcessesCanUseStandardInput() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory(); $result = $factory->input('foobar')->run('cat'); $this->assertSame('foobar', $result->output()); } + #[RequiresOperatingSystem('Linux|DAR')] public function testProcessPipe() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory; $factory->fake([ 'cat *' => "Hello, world\nfoo\nbar", @@ -641,12 +615,9 @@ public function testProcessPipe() $this->assertSame("foo\n", $pipe->output()); } + #[RequiresOperatingSystem('Linux|DAR')] public function testProcessPipeFailed() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory; $factory->fake([ 'cat *' => $factory->result(exitCode: 1), @@ -660,12 +631,9 @@ public function testProcessPipeFailed() $this->assertTrue($pipe->failed()); } + #[RequiresOperatingSystem('Linux|DAR')] public function testProcessSimplePipe() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory; $factory->fake([ 'cat *' => "Hello, world\nfoo\nbar", @@ -679,12 +647,9 @@ public function testProcessSimplePipe() $this->assertSame("foo\n", $pipe->output()); } + #[RequiresOperatingSystem('Linux|DAR')] public function testProcessSimplePipeFailed() { - if (windows_os()) { - $this->markTestSkipped('Requires Linux.'); - } - $factory = new Factory; $factory->fake([ 'cat *' => $factory->result(exitCode: 1), From 9e7ba356c31969b35c1442e7d012bab31e012831 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Mon, 1 Apr 2024 03:59:49 +0330 Subject: [PATCH 046/123] [11.x] Use Default Schema Name on SQL Server (#50855) * get default schema name on sqlsrv * force re-run tests * add test * wip * wip * wip * wip * revert adding test * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * formatting --------- Co-authored-by: Taylor Otwell --- .../Schema/Grammars/SqlServerGrammar.php | 10 +++++ .../Database/Schema/SqlServerBuilder.php | 14 ++++++- .../Database/SchemaBuilderSchemaNameTest.php | 37 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index a661094b2e84..d15a32f3cbe7 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -37,6 +37,16 @@ class SqlServerGrammar extends Grammar */ protected $fluentCommands = ['Default']; + /** + * Compile a query to determine the name of the default schema. + * + * @return string + */ + public function compileDefaultSchema() + { + return 'select schema_name()'; + } + /** * Compile a create database command. * diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index 876e8b39be46..2833b5098aba 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -42,6 +42,7 @@ public function hasTable($table) { [$schema, $table] = $this->parseSchemaAndTable($table); + $schema ??= $this->getDefaultSchema(); $table = $this->connection->getTablePrefix().$table; foreach ($this->getTables() as $value) { @@ -64,6 +65,7 @@ public function hasView($view) { [$schema, $view] = $this->parseSchemaAndTable($view); + $schema ??= $this->getDefaultSchema(); $view = $this->connection->getTablePrefix().$view; foreach ($this->getViews() as $value) { @@ -151,6 +153,16 @@ public function getForeignKeys($table) ); } + /** + * Get the default schema for the connection. + * + * @return string + */ + protected function getDefaultSchema() + { + return $this->connection->scalar($this->grammar->compileDefaultSchema()); + } + /** * Parse the database object reference and extract the schema and table. * @@ -159,7 +171,7 @@ public function getForeignKeys($table) */ protected function parseSchemaAndTable($reference) { - $parts = array_pad(explode('.', $reference, 2), -2, 'dbo'); + $parts = array_pad(explode('.', $reference, 2), -2, null); if (str_contains($parts[1], '.')) { $database = $parts[0]; diff --git a/tests/Integration/Database/SchemaBuilderSchemaNameTest.php b/tests/Integration/Database/SchemaBuilderSchemaNameTest.php index 2d6d9512ed87..f548422317db 100644 --- a/tests/Integration/Database/SchemaBuilderSchemaNameTest.php +++ b/tests/Integration/Database/SchemaBuilderSchemaNameTest.php @@ -425,6 +425,43 @@ public function testAutoIncrementStartingValue($connection) }); } + #[DataProvider('connectionProvider')] + public function testHasTable($connection) + { + if ($this->driver !== 'sqlsrv') { + $this->markTestSkipped('Test requires a SQL Server connection.'); + } + + $db = DB::connection($connection); + $schema = $db->getSchemaBuilder(); + + try { + $db->statement("create login my_user with password = 'Passw0rd'"); + $db->statement('create user my_user for login my_user'); + } catch(\Illuminate\Database\QueryException $e) { + // + } + + $db->statement('grant create table to my_user'); + $db->statement('grant alter on SCHEMA::my_schema to my_user'); + $db->statement("alter user my_user with default_schema = my_schema execute as user='my_user'"); + + config([ + 'database.connections.'.$connection.'.username' => 'my_user', + 'database.connections.'.$connection.'.password' => 'Passw0rd', + ]); + + $this->assertEquals('my_schema', $db->scalar('select schema_name()')); + + $schema->create('table', function (Blueprint $table) { + $table->id(); + }); + + $this->assertTrue($schema->hasTable('table')); + $this->assertTrue($schema->hasTable('my_schema.table')); + $this->assertFalse($schema->hasTable('dbo.table')); + } + public static function connectionProvider(): array { return [ From 175b0bb2f8db5ce34229bb175d2e85d4527f7039 Mon Sep 17 00:00:00 2001 From: Ollie Read Date: Mon, 1 Apr 2024 01:32:56 +0100 Subject: [PATCH 047/123] Correct typing for startedAs and virtualAs database column definitions (#50851) * Correct typing for startedAs and virtualAs database column definitions * Update the typing the use the Expression contract rather than the concrete --- src/Illuminate/Database/Schema/ColumnDefinition.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/ColumnDefinition.php b/src/Illuminate/Database/Schema/ColumnDefinition.php index 0093ee1f25c6..255ddabd5873 100644 --- a/src/Illuminate/Database/Schema/ColumnDefinition.php +++ b/src/Illuminate/Database/Schema/ColumnDefinition.php @@ -15,7 +15,7 @@ * @method $this default(mixed $value) Specify a "default" value for the column * @method $this first() Place the column "first" in the table (MySQL) * @method $this from(int $startingValue) Set the starting value of an auto-incrementing field (MySQL / PostgreSQL) - * @method $this generatedAs(string|\Illuminate\Database\Query\Expression $expression = null) Create a SQL compliant identity column (PostgreSQL) + * @method $this generatedAs(string|\Illuminate\Contracts\Database\Query\Expression $expression = null) Create a SQL compliant identity column (PostgreSQL) * @method $this index(bool|string $indexName = null) Add an index * @method $this invisible() Specify that the column should be invisible to "SELECT *" (MySQL) * @method $this nullable(bool $value = true) Allow NULL values to be inserted into the column @@ -24,13 +24,13 @@ * @method $this fulltext(bool|string $indexName = null) Add a fulltext index * @method $this spatialIndex(bool|string $indexName = null) Add a spatial index * @method $this startingValue(int $startingValue) Set the starting value of an auto-incrementing field (MySQL/PostgreSQL) - * @method $this storedAs(string $expression) Create a stored generated column (MySQL/PostgreSQL/SQLite) + * @method $this storedAs(string|\Illuminate\Contracts\Database\Query\Expression $expression) Create a stored generated column (MySQL/PostgreSQL/SQLite) * @method $this type(string $type) Specify a type for the column * @method $this unique(bool|string $indexName = null) Add a unique index * @method $this unsigned() Set the INTEGER column as UNSIGNED (MySQL) * @method $this useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value * @method $this useCurrentOnUpdate() Set the TIMESTAMP column to use CURRENT_TIMESTAMP when updating (MySQL) - * @method $this virtualAs(string $expression) Create a virtual generated column (MySQL/PostgreSQL/SQLite) + * @method $this virtualAs(string|\Illuminate\Contracts\Database\Query\Expression $expression) Create a virtual generated column (MySQL/PostgreSQL/SQLite) */ class ColumnDefinition extends Fluent { From 910d64d14abc217479e9596c0748ba22551fb766 Mon Sep 17 00:00:00 2001 From: Kacper Pruszynski Date: Mon, 1 Apr 2024 02:34:48 +0200 Subject: [PATCH 048/123] Allow passing query Expression as column in Many-to-Many relationships (#50787) (#50849) --- .../Eloquent/Relations/BelongsToMany.php | 38 +++-- ...aseEloquentBelongsToManyExpressionTest.php | 152 ++++++++++++++++++ ...tBelongsToManyWithCastedAttributesTest.php | 4 + ...BelongsToManyWithDefaultAttributesTest.php | 2 + ...oquentBelongsToManyWithoutTouchingTest.php | 2 + tests/Database/DatabaseEloquentModelTest.php | 2 + .../DatabaseEloquentMorphToManyTest.php | 51 ++++-- 7 files changed, 222 insertions(+), 29 deletions(-) create mode 100644 tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 9fe0d301918b..a030b059a60b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -65,7 +65,7 @@ class BelongsToMany extends Relation /** * The pivot table columns to retrieve. * - * @var array + * @var array */ protected $pivotColumns = []; @@ -356,7 +356,7 @@ public function as($accessor) /** * Set a where clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param mixed $operator * @param mixed $value * @param string $boolean @@ -372,7 +372,7 @@ public function wherePivot($column, $operator = null, $value = null, $boolean = /** * Set a "where between" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param array $values * @param string $boolean * @param bool $not @@ -386,7 +386,7 @@ public function wherePivotBetween($column, array $values, $boolean = 'and', $not /** * Set a "or where between" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param array $values * @return $this */ @@ -398,7 +398,7 @@ public function orWherePivotBetween($column, array $values) /** * Set a "where pivot not between" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param array $values * @param string $boolean * @return $this @@ -411,7 +411,7 @@ public function wherePivotNotBetween($column, array $values, $boolean = 'and') /** * Set a "or where not between" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param array $values * @return $this */ @@ -423,7 +423,7 @@ public function orWherePivotNotBetween($column, array $values) /** * Set a "where in" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param mixed $values * @param string $boolean * @param bool $not @@ -439,7 +439,7 @@ public function wherePivotIn($column, $values, $boolean = 'and', $not = false) /** * Set an "or where" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param mixed $operator * @param mixed $value * @return $this @@ -454,7 +454,7 @@ public function orWherePivot($column, $operator = null, $value = null) * * In addition, new pivot records will receive this value. * - * @param string|array $column + * @param string|\Illuminate\Contracts\Database\Query\Expression|array $column * @param mixed $value * @return $this * @@ -494,7 +494,7 @@ public function orWherePivotIn($column, $values) /** * Set a "where not in" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param mixed $values * @param string $boolean * @return $this @@ -519,7 +519,7 @@ public function orWherePivotNotIn($column, $values) /** * Set a "where null" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param string $boolean * @param bool $not * @return $this @@ -534,7 +534,7 @@ public function wherePivotNull($column, $boolean = 'and', $not = false) /** * Set a "where not null" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param string $boolean * @return $this */ @@ -546,7 +546,7 @@ public function wherePivotNotNull($column, $boolean = 'and') /** * Set a "or where null" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param bool $not * @return $this */ @@ -558,7 +558,7 @@ public function orWherePivotNull($column, $not = false) /** * Set a "or where not null" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @return $this */ public function orWherePivotNotNull($column) @@ -569,7 +569,7 @@ public function orWherePivotNotNull($column) /** * Add an "order by" clause for a pivot table column. * - * @param string $column + * @param string|\Illuminate\Contracts\Database\Query\Expression $column * @param string $direction * @return $this */ @@ -1558,11 +1558,15 @@ public function getPivotColumns() /** * Qualify the given column name by the pivot table. * - * @param string $column - * @return string + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return string|\Illuminate\Contracts\Database\Query\Expression */ public function qualifyPivotColumn($column) { + if ($this->getGrammar()->isExpression($column)) { + return $column; + } + return str_contains($column, '.') ? $column : $this->table.'.'.$column; diff --git a/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php b/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php new file mode 100644 index 000000000000..647757bb3ff3 --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php @@ -0,0 +1,152 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + public function testAmbiguousColumnsExpression(): void + { + $this->seedData(); + + $tags = DatabaseEloquentBelongsToManyExpressionTestTestPost::findOrFail(1) + ->tags() + ->wherePivotNotIn(new Expression("tag_id || '_' || type"), ['1_t1']) + ->get(); + + $this->assertCount(1, $tags); + $this->assertEquals(2, $tags->first()->getKey()); + } + + public function testQualifiedColumnExpression(): void + { + $this->seedData(); + + $tags = DatabaseEloquentBelongsToManyExpressionTestTestPost::findOrFail(2) + ->tags() + ->wherePivotNotIn(new Expression("taggables.tag_id || '_' || taggables.type"), ['2_t2']) + ->get(); + + $this->assertCount(1, $tags); + $this->assertEquals(3, $tags->first()->getKey()); + } + + /** + * Setup the database schema. + * + * @return void + */ + public function createSchema() + { + $this->schema()->create('posts', fn (Blueprint $t) => $t->id()); + $this->schema()->create('tags', fn (Blueprint $t) => $t->id()); + $this->schema()->create('taggables', function (Blueprint $t) { + $t->unsignedBigInteger('tag_id'); + $t->unsignedBigInteger('taggable_id'); + $t->string('type', 10); + $t->string('taggable_type'); + } + ); + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + $this->schema()->drop('posts'); + $this->schema()->drop('tags'); + $this->schema()->drop('taggables'); + } + + /** + * Helpers... + */ + protected function seedData(): void + { + $p1 = DatabaseEloquentBelongsToManyExpressionTestTestPost::query()->create(); + $p2 = DatabaseEloquentBelongsToManyExpressionTestTestPost::query()->create(); + $t1 = DatabaseEloquentBelongsToManyExpressionTestTestTag::query()->create(); + $t2 = DatabaseEloquentBelongsToManyExpressionTestTestTag::query()->create(); + $t3 = DatabaseEloquentBelongsToManyExpressionTestTestTag::query()->create(); + + $p1->tags()->sync([ + $t1->getKey() => ['type' => 't1'], + $t2->getKey() => ['type' => 't2'], + ]); + $p2->tags()->sync([ + $t2->getKey() => ['type' => 't2'], + $t3->getKey() => ['type' => 't3'], + ]); + } + + /** + * Get a database connection instance. + * + * @return \Illuminate\Database\ConnectionInterface + */ + protected function connection() + { + return Eloquent::getConnectionResolver()->connection(); + } + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema() + { + return $this->connection()->getSchemaBuilder(); + } +} + +class DatabaseEloquentBelongsToManyExpressionTestTestPost extends Eloquent +{ + protected $table = 'posts'; + protected $fillable = ['id']; + public $timestamps = false; + + public function tags(): MorphToMany + { + return $this->morphToMany( + DatabaseEloquentBelongsToManyExpressionTestTestTag::class, + 'taggable', + 'taggables', + 'taggable_id', + 'tag_id', + 'id', + 'id', + ); + } +} + +class DatabaseEloquentBelongsToManyExpressionTestTestTag extends Eloquent +{ + protected $table = 'tags'; + protected $fillable = ['id']; + public $timestamps = false; +} diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php index 7e1047ac9a38..34f89e8c49ef 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -61,6 +62,9 @@ protected function getRelation() $builder->shouldReceive('getModel')->andReturn($related); $related->shouldReceive('qualifyColumn'); $builder->shouldReceive('join', 'where'); + $builder->shouldReceive('getGrammar')->andReturn( + m::mock(Grammar::class, ['isExpression' => false]) + ); return new BelongsToMany( $builder, diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php index 512f87454691..90174ce3e771 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php @@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; use stdClass; @@ -55,6 +56,7 @@ public function getRelationArguments() $builder->shouldReceive('join')->once()->with('club_user', 'users.id', '=', 'club_user.user_id'); $builder->shouldReceive('where')->once()->with('club_user.club_id', '=', 1); $builder->shouldReceive('where')->once()->with('club_user.is_admin', '=', 1, 'and'); + $builder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); return [$builder, $parent, 'club_user', 'club_id', 'user_id', 'id', 'id', null, false]; } diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php index 32d617e36fb2..6eafa9668671 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -31,6 +32,7 @@ public function testItWillNotTouchRelatedModelsWhenUpdatingChild(): void $parent->shouldReceive('getAttribute')->with('id')->andReturn(1); $builder->shouldReceive('getModel')->andReturn($related); $builder->shouldReceive('where'); + $builder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); $relation = new BelongsToMany($builder, $parent, 'article_users', 'user_id', 'article_id', 'id', 'id'); $builder->shouldReceive('update')->never(); diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index cbfe8f74b1f9..2b8f11eaee8e 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -2860,6 +2860,7 @@ protected function addMockConnection($model) $resolver->shouldReceive('connection')->andReturn($connection = m::mock(Connection::class)); $connection->shouldReceive('getQueryGrammar')->andReturn($grammar = m::mock(Grammar::class)); $grammar->shouldReceive('getBitwiseOperators')->andReturn([]); + $grammar->shouldReceive('isExpression')->andReturnFalse(); $connection->shouldReceive('getPostProcessor')->andReturn($processor = m::mock(Processor::class)); $connection->shouldReceive('query')->andReturnUsing(function () use ($connection, $grammar, $processor) { return new BaseBuilder($connection, $grammar, $processor); @@ -3214,6 +3215,7 @@ public function getConnection() $mock = m::mock(Connection::class); $mock->shouldReceive('getQueryGrammar')->andReturn($grammar = m::mock(Grammar::class)); $grammar->shouldReceive('getBitwiseOperators')->andReturn([]); + $grammar->shouldReceive('isExpression')->andReturnFalse(); $mock->shouldReceive('getPostProcessor')->andReturn($processor = m::mock(Processor::class)); $mock->shouldReceive('getName')->andReturn('name'); $mock->shouldReceive('query')->andReturnUsing(function () use ($mock, $grammar, $processor) { diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 32ccbe4b6705..36f4466ee943 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -5,18 +5,15 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; +use Illuminate\Database\Query\Expression; +use Illuminate\Database\Query\Grammars\Grammar; +use Mockery\Adapter\Phpunit\MockeryTestCase as TestCase; use Mockery as m; -use PHPUnit\Framework\TestCase; use stdClass; class DatabaseEloquentMorphToManyTest extends TestCase { - protected function tearDown(): void - { - m::close(); - } - - public function testEagerConstraintsAreProperlyAdded() + public function testEagerConstraintsAreProperlyAdded(): void { $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->andReturn('id'); @@ -30,7 +27,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation->addEagerConstraints([$model1, $model2]); } - public function testAttachInsertsPivotTableRecord() + public function testAttachInsertsPivotTableRecord(): void { $relation = $this->getMockBuilder(MorphToMany::class)->onlyMethods(['touchIfTouching'])->setConstructorArgs($this->getRelationArguments())->getMock(); $query = m::mock(stdClass::class); @@ -43,7 +40,7 @@ public function testAttachInsertsPivotTableRecord() $relation->attach(2, ['foo' => 'bar']); } - public function testDetachRemovesPivotTableRecord() + public function testDetachRemovesPivotTableRecord(): void { $relation = $this->getMockBuilder(MorphToMany::class)->onlyMethods(['touchIfTouching'])->setConstructorArgs($this->getRelationArguments())->getMock(); $query = m::mock(stdClass::class); @@ -59,7 +56,7 @@ public function testDetachRemovesPivotTableRecord() $this->assertTrue($relation->detach([1, 2, 3])); } - public function testDetachMethodClearsAllPivotRecordsWhenNoIDsAreGiven() + public function testDetachMethodClearsAllPivotRecordsWhenNoIDsAreGiven(): void { $relation = $this->getMockBuilder(MorphToMany::class)->onlyMethods(['touchIfTouching'])->setConstructorArgs($this->getRelationArguments())->getMock(); $query = m::mock(stdClass::class); @@ -75,14 +72,39 @@ public function testDetachMethodClearsAllPivotRecordsWhenNoIDsAreGiven() $this->assertTrue($relation->detach()); } - public function getRelation() + public function testQueryExpressionCanBePassedToDifferentPivotQueryBuilderClauses(): void + { + $value = 'pivot_value'; + $column = new Expression("CONCAT(foo, '_', bar)"); + $relation = $this->getRelation(); + /** @var Builder|m\MockInterface $builder */ + $builder = $relation->getQuery(); + + $builder->shouldReceive('where')->with($column, '=', $value, 'and')->times(2)->andReturnSelf(); + $relation->wherePivot($column, '=', $value); + $relation->withPivotValue($column, $value); + + $builder->shouldReceive('whereBetween')->with($column, [$value, $value], 'and', false)->once()->andReturnSelf(); + $relation->wherePivotBetween($column, [$value, $value]); + + $builder->shouldReceive('whereIn')->with($column, [$value], 'and', false)->once()->andReturnSelf(); + $relation->wherePivotIn($column, [$value]); + + $builder->shouldReceive('whereNull')->with($column, 'and', false)->once()->andReturnSelf(); + $relation->wherePivotNull($column); + + $builder->shouldReceive('orderBy')->with($column, 'asc')->once()->andReturnSelf(); + $relation->orderByPivot($column); + } + + public function getRelation(): MorphToMany { [$builder, $parent] = $this->getRelationArguments(); return new MorphToMany($builder, $parent, 'taggable', 'taggables', 'taggable_id', 'tag_id', 'id', 'id'); } - public function getRelationArguments() + public function getRelationArguments(): array { $parent = m::mock(Model::class); $parent->shouldReceive('getMorphClass')->andReturn(get_class($parent)); @@ -105,6 +127,11 @@ public function getRelationArguments() $builder->shouldReceive('where')->once()->with('taggables.taggable_id', '=', 1); $builder->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($parent)); + $grammar = m::mock(Grammar::class); + $grammar->shouldReceive('isExpression')->with(m::type(Expression::class))->andReturnTrue(); + $grammar->shouldReceive('isExpression')->with(m::type('string'))->andReturnFalse(); + $builder->shouldReceive('getGrammar')->andReturn($grammar); + return [$builder, $parent, 'taggable', 'taggables', 'taggable_id', 'tag_id', 'id', 'id', 'relation_name', false]; } } From e122d0b779056046fb3970f8ab0ea3935f4e61f5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 31 Mar 2024 20:45:39 -0500 Subject: [PATCH 049/123] wip --- src/Illuminate/Bus/Queueable.php | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Illuminate/Bus/Queueable.php b/src/Illuminate/Bus/Queueable.php index 3d3bbb9b290e..eb51ce56d7a1 100644 --- a/src/Illuminate/Bus/Queueable.php +++ b/src/Illuminate/Bus/Queueable.php @@ -23,27 +23,6 @@ trait Queueable */ public $queue; - /** - * The name of the connection the chain should be sent to. - * - * @var string|null - */ - public $chainConnection; - - /** - * The name of the queue the chain should be sent to. - * - * @var string|null - */ - public $chainQueue; - - /** - * The callbacks to be executed on chain failure. - * - * @var array|null - */ - public $chainCatchCallbacks; - /** * The number of seconds before the job should be made available. * @@ -72,6 +51,27 @@ trait Queueable */ public $chained = []; + /** + * The name of the connection the chain should be sent to. + * + * @var string|null + */ + public $chainConnection; + + /** + * The name of the queue the chain should be sent to. + * + * @var string|null + */ + public $chainQueue; + + /** + * The callbacks to be executed on chain failure. + * + * @var array|null + */ + public $chainCatchCallbacks; + /** * Set the desired connection for the job. * From 261774910a9f48d56baa9593e08e1a159efde395 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:40:39 +0200 Subject: [PATCH 050/123] [11.x] Fix `Middleware::trustHosts(subdomains: true)` (#50877) * Fix usage of config before its resolved * Allow trusting hosts via a callback * Remove unused import * Update TrustHosts.php --------- Co-authored-by: Taylor Otwell --- .../Foundation/Configuration/Middleware.php | 6 +-- src/Illuminate/Http/Middleware/TrustHosts.php | 39 +++++++++++++------ .../Configuration/MiddlewareTest.php | 15 ++++--- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Foundation/Configuration/Middleware.php b/src/Illuminate/Foundation/Configuration/Middleware.php index e8916d552d44..cf58263d830a 100644 --- a/src/Illuminate/Foundation/Configuration/Middleware.php +++ b/src/Illuminate/Foundation/Configuration/Middleware.php @@ -608,15 +608,15 @@ public function trimStrings(array $except = []) /** * Indicate that the trusted host middleware should be enabled. * - * @param array|null $at + * @param array|(callable(): array)|null $at * @param bool $subdomains * @return $this */ - public function trustHosts(array $at = null, bool $subdomains = true) + public function trustHosts(array|callable $at = null, bool $subdomains = true) { $this->trustHosts = true; - if (is_array($at)) { + if (! is_null($at)) { TrustHosts::at($at, $subdomains); } diff --git a/src/Illuminate/Http/Middleware/TrustHosts.php b/src/Illuminate/Http/Middleware/TrustHosts.php index 13dd1f00b62c..8eae16d1cec0 100644 --- a/src/Illuminate/Http/Middleware/TrustHosts.php +++ b/src/Illuminate/Http/Middleware/TrustHosts.php @@ -17,10 +17,17 @@ class TrustHosts /** * The trusted hosts that have been configured to always be trusted. * - * @var array|null + * @var array|(callable(): array)|null */ protected static $alwaysTrust; + /** + * Indicates whether subdomains of the application URL should be trusted. + * + * @var bool|null + */ + protected static $subdomains; + /** * Create a new middleware instance. * @@ -39,9 +46,21 @@ public function __construct(Application $app) */ public function hosts() { - return is_array(static::$alwaysTrust) - ? static::$alwaysTrust - : [$this->allSubdomainsOfApplicationUrl()]; + if (is_null(static::$alwaysTrust)) { + return [$this->allSubdomainsOfApplicationUrl()]; + } + + $hosts = match (true) { + is_array(static::$alwaysTrust) => static::$alwaysTrust, + is_callable(static::$alwaysTrust) => call_user_func(static::$alwaysTrust), + default => [], + }; + + if (static::$subdomains) { + $hosts[] = $this->allSubdomainsOfApplicationUrl(); + } + + return $hosts; } /** @@ -63,19 +82,14 @@ public function handle(Request $request, $next) /** * Specify the hosts that should always be trusted. * - * @param array $hosts + * @param array|(callable(): array) $hosts * @param bool $subdomains * @return void */ - public static function at(array $hosts, bool $subdomains = true) + public static function at(array|callable $hosts, bool $subdomains = true) { - if ($subdomains) { - if ($host = parse_url(config('app.url'), PHP_URL_HOST)) { - $hosts[] = '^(.+\.)?'.preg_quote($host).'$'; - } - } - static::$alwaysTrust = $hosts; + static::$subdomains = $subdomains; } /** @@ -109,5 +123,6 @@ protected function allSubdomainsOfApplicationUrl() public static function flushState() { static::$alwaysTrust = null; + static::$subdomains = null; } } diff --git a/tests/Foundation/Configuration/MiddlewareTest.php b/tests/Foundation/Configuration/MiddlewareTest.php index 9012b4d5fa0c..8fde56c7a9c1 100644 --- a/tests/Foundation/Configuration/MiddlewareTest.php +++ b/tests/Foundation/Configuration/MiddlewareTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Foundation\Configuration; -use Illuminate\Config\Repository; use Illuminate\Container\Container; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Foundation\Application; @@ -219,23 +218,29 @@ protected function allSubdomainsOfApplicationUrl() $configuration->trustHosts(); $this->assertEquals(['^(.+\.)?laravel\.test$'], $middleware->hosts()); - app()['config'] = Mockery::mock(Repository::class); - app()['config']->shouldReceive('get')->with('app.url', null)->times(3)->andReturn('http://laravel.test'); - $configuration->trustHosts(at: ['my.test']); $this->assertEquals(['my.test', '^(.+\.)?laravel\.test$'], $middleware->hosts()); - $configuration->trustHosts(at: ['my.test']); + $configuration->trustHosts(at: static fn () => ['my.test']); $this->assertEquals(['my.test', '^(.+\.)?laravel\.test$'], $middleware->hosts()); $configuration->trustHosts(at: ['my.test'], subdomains: false); $this->assertEquals(['my.test'], $middleware->hosts()); + $configuration->trustHosts(at: static fn () => ['my.test'], subdomains: false); + $this->assertEquals(['my.test'], $middleware->hosts()); + $configuration->trustHosts(at: []); $this->assertEquals(['^(.+\.)?laravel\.test$'], $middleware->hosts()); + $configuration->trustHosts(at: static fn () => []); + $this->assertEquals(['^(.+\.)?laravel\.test$'], $middleware->hosts()); + $configuration->trustHosts(at: [], subdomains: false); $this->assertEquals([], $middleware->hosts()); + + $configuration->trustHosts(at: static fn () => [], subdomains: false); + $this->assertEquals([], $middleware->hosts()); } public function testEncryptCookies() From 73ed300e640afd0a6011a87997ecacfa081db6f0 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:11:43 +0330 Subject: [PATCH 051/123] modify doc blocks for getGateArguments (#50874) --- src/Illuminate/Auth/Middleware/Authorize.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Middleware/Authorize.php b/src/Illuminate/Auth/Middleware/Authorize.php index 1b0bf042e842..0b6ece4a5935 100644 --- a/src/Illuminate/Auth/Middleware/Authorize.php +++ b/src/Illuminate/Auth/Middleware/Authorize.php @@ -62,7 +62,7 @@ public function handle($request, Closure $next, $ability, ...$models) * * @param \Illuminate\Http\Request $request * @param array|null $models - * @return \Illuminate\Database\Eloquent\Model|array|string + * @return array */ protected function getGateArguments($request, $models) { From 6f44f16153193f464e7e0974847a7f04cb8c5762 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:12:08 +0330 Subject: [PATCH 052/123] Add @throws to doc block for resolve method (#50873) --- src/Illuminate/Support/MultipleInstanceManager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/MultipleInstanceManager.php b/src/Illuminate/Support/MultipleInstanceManager.php index 8544bdf71b34..4251bbd64437 100644 --- a/src/Illuminate/Support/MultipleInstanceManager.php +++ b/src/Illuminate/Support/MultipleInstanceManager.php @@ -94,6 +94,7 @@ protected function get($name) * @return mixed * * @throws \InvalidArgumentException + * @throws \RuntimeException */ protected function resolve($name) { From 4f6088b10c5b3d04893cc165d04a9353361646be Mon Sep 17 00:00:00 2001 From: Patrick O'Meara Date: Tue, 2 Apr 2024 00:42:54 +1100 Subject: [PATCH 053/123] [11.x] Str trim methods (#50822) * Add trim method to Str to remove unicode space characters * Add ltrim and rtrim methods * Comments * styleCI patch * Assert that new lines are removed * Handle binary data * Use in middleware * Implement @dasundev's changes from #50832 --- .../Http/Middleware/TrimStrings.php | 3 +- src/Illuminate/Support/Str.php | 50 +++++++++++- src/Illuminate/Support/Stringable.php | 6 +- tests/Support/SupportStrTest.php | 77 +++++++++++++++++++ 4 files changed, 131 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php index 0edc84376205..b82bdbfa8127 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php +++ b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php @@ -4,6 +4,7 @@ use Closure; use Illuminate\Support\Arr; +use Illuminate\Support\Str; class TrimStrings extends TransformsRequest { @@ -65,7 +66,7 @@ protected function transform($key, $value) return $value; } - return preg_replace('~^[\s\x{FEFF}\x{200B}\x{200E}]+|[\s\x{FEFF}\x{200B}\x{200E}]+$~u', '', $value) ?? trim($value); + return Str::trim($value); } /** diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 39e303cae3b1..679e86bbb3f6 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -1418,6 +1418,54 @@ public static function snake($value, $delimiter = '_') return static::$snakeCache[$key][$delimiter] = $value; } + /** + * Remove all whitespace from both ends of a string. + * + * @param string $value + * @param string|null $charlist + * @return string + */ + public static function trim($value, $charlist = null) + { + if ($charlist === null) { + return preg_replace('~^[\s\x{FEFF}\x{200B}\x{200E}]+|[\s\x{FEFF}\x{200B}\x{200E}]+$~u', '', $value) ?? trim($value); + } + + return trim($value, $charlist); + } + + /** + * Remove all whitespace from the beginning of a string. + * + * @param string $value + * @param string|null $charlist + * @return string + */ + public static function ltrim($value, $charlist = null) + { + if ($charlist === null) { + return preg_replace('~^[\s\x{FEFF}\x{200B}\x{200E}]+~u', '', $value) ?? ltrim($value); + } + + return ltrim($value, $charlist); + } + + /** + * Remove all whitespace from the end of a string. + * + * @param string $value + * @param string|null $charlist + * @return string + */ + public static function rtrim($value, $charlist = null) + { + if ($charlist === null) { + return preg_replace('~[\s\x{FEFF}\x{200B}\x{200E}]+$~u', '', $value) ?? rtrim($value); + } + + return rtrim($value, $charlist); + } + /** * Remove all "extra" blank space from the given string. * @@ -1426,7 +1474,7 @@ public static function snake($value, $delimiter = '_') */ public static function squish($value) { - return preg_replace('~(\s|\x{3164}|\x{1160})+~u', ' ', preg_replace('~^[\s\x{FEFF}]+|[\s\x{FEFF}]+$~u', '', $value)); + return preg_replace('~(\s|\x{3164}|\x{1160})+~u', ' ', static::trim($value)); } /** diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index 8fe1f9e39a1d..defbb6c135a2 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -968,7 +968,7 @@ public function take(int $limit) */ public function trim($characters = null) { - return new static(trim(...array_merge([$this->value], func_get_args()))); + return new static(Str::trim(...array_merge([$this->value], func_get_args()))); } /** @@ -979,7 +979,7 @@ public function trim($characters = null) */ public function ltrim($characters = null) { - return new static(ltrim(...array_merge([$this->value], func_get_args()))); + return new static(Str::ltrim(...array_merge([$this->value], func_get_args()))); } /** @@ -990,7 +990,7 @@ public function ltrim($characters = null) */ public function rtrim($characters = null) { - return new static(rtrim(...array_merge([$this->value], func_get_args()))); + return new static(Str::rtrim(...array_merge([$this->value], func_get_args()))); } /** diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 844c52b781bc..9670e9672ef3 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -766,6 +766,83 @@ public function testSnake() $this->assertSame('żółtałódka', Str::snake('ŻółtaŁódka')); } + public function testTrim() + { + $this->assertSame('foo bar', Str::trim(' foo bar ')); + $this->assertSame('foo bar', Str::trim('foo bar ')); + $this->assertSame('foo bar', Str::trim(' foo bar')); + $this->assertSame('foo bar', Str::trim('foo bar')); + $this->assertSame(' foo bar ', Str::trim(' foo bar ', '')); + $this->assertSame('foo bar', Str::trim(' foo bar ', ' ')); + $this->assertSame('foo bar', Str::trim('-foo bar_', '-_')); + + $this->assertSame('foo bar', Str::trim(' foo bar ')); + + $this->assertSame('123', Str::trim('  123   ')); + $this->assertSame('だ', Str::trim('だ')); + $this->assertSame('ム', Str::trim('ム')); + $this->assertSame('だ', Str::trim('  だ   ')); + $this->assertSame('ム', Str::trim('  ム   ')); + + $this->assertSame( + 'foo bar', + Str::trim(' + foo bar + ') + ); + $this->assertSame( + 'foo + bar', + Str::trim(' + foo + bar + ') + ); + + $this->assertSame("\xE9", Str::trim(" \xE9 ")); + } + + public function testLtrim() + { + $this->assertSame('foo bar ', Str::ltrim(' foo bar ')); + + $this->assertSame('123   ', Str::ltrim('  123   ')); + $this->assertSame('だ', Str::ltrim('だ')); + $this->assertSame('ム', Str::ltrim('ム')); + $this->assertSame('だ   ', Str::ltrim('  だ   ')); + $this->assertSame('ム   ', Str::ltrim('  ム   ')); + + $this->assertSame( + 'foo bar + ', + Str::ltrim(' + foo bar + ') + ); + $this->assertSame("\xE9 ", Str::ltrim(" \xE9 ")); + } + + public function testRtrim() + { + $this->assertSame(' foo bar', Str::rtrim(' foo bar ')); + + $this->assertSame('  123', Str::rtrim('  123   ')); + $this->assertSame('だ', Str::rtrim('だ')); + $this->assertSame('ム', Str::rtrim('ム')); + $this->assertSame('  だ', Str::rtrim('  だ   ')); + $this->assertSame('  ム', Str::rtrim('  ム   ')); + + $this->assertSame( + ' + foo bar', + Str::rtrim(' + foo bar + ') + ); + + $this->assertSame(" \xE9", Str::rtrim(" \xE9 ")); + } + public function testSquish() { $this->assertSame('laravel php framework', Str::squish(' laravel php framework ')); From c215697f2da08a275b0e9c0814041a6badb6701c Mon Sep 17 00:00:00 2001 From: Philo Hermans Date: Mon, 1 Apr 2024 17:22:25 +0200 Subject: [PATCH 054/123] [11.x] Add fluent helper (#50848) * Add fluent helper * Update docblock * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/helpers.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 6dcb131b233a..172291ad228a 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -4,6 +4,7 @@ use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\Env; +use Illuminate\Support\Fluent; use Illuminate\Support\HigherOrderTapProxy; use Illuminate\Support\Once; use Illuminate\Support\Onceable; @@ -154,6 +155,19 @@ function filled($value) } } +if (! function_exists('fluent')) { + /** + * Create an Fluent object from the given value. + * + * @param object|array $value + * @return \Illuminate\Support\Fluent + */ + function fluent($value) + { + return new Fluent($value); + } +} + if (! function_exists('literal')) { /** * Return a new literal or anonymous object using named arguments. From 9983d7b5ec3a06253ecc2ace7097ca2b05a9a522 Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:10:00 +0200 Subject: [PATCH 055/123] [11.x] Add a new helper for context (#50878) * Add a new helper for context * Formatting * Clean * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Foundation/helpers.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index c698bbdfaa8e..b19b0d85397e 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -16,6 +16,7 @@ use Illuminate\Foundation\Bus\PendingDispatch; use Illuminate\Foundation\Mix; use Illuminate\Http\Exceptions\HttpResponseException; +use Illuminate\Log\Context\Repository as ContextRepository; use Illuminate\Queue\CallQueuedClosure; use Illuminate\Routing\Router; use Illuminate\Support\Facades\Date; @@ -288,6 +289,24 @@ function config_path($path = '') } } +if (! function_exists('context')) { + /** + * Get / set the specified context value. + * + * @param array|string|null $key + * @param mixed $default + * @return mixed|\Illuminate\Log\Context\Repository + */ + function context($key, $default = null) + { + return match (true) { + is_null($key) => app(ContextRepository::class), + is_array($key) => app(ContextRepository::class)->add($key), + default => app(ContextRepository::class)->get($key, $default), + }; + } +} + if (! function_exists('cookie')) { /** * Create a new cookie instance. From f389d79892afdc0754526a74a0825b093e069c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Debrauwer?= Date: Mon, 1 Apr 2024 22:47:36 +0200 Subject: [PATCH 056/123] [11.x] `assertChain` and `assertNoChain` on job instance (#50858) * assertChain and assertNoChain * Fix linting issues * formatting * formatting * fix test --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Bus/Queueable.php | 36 +++++++++++ tests/Support/SupportTestingQueueFakeTest.php | 63 +++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/Illuminate/Bus/Queueable.php b/src/Illuminate/Bus/Queueable.php index eb51ce56d7a1..ae84ca79fc67 100644 --- a/src/Illuminate/Bus/Queueable.php +++ b/src/Illuminate/Bus/Queueable.php @@ -5,6 +5,7 @@ use Closure; use Illuminate\Queue\CallQueuedClosure; use Illuminate\Support\Arr; +use PHPUnit\Framework\Assert as PHPUnit; use RuntimeException; trait Queueable @@ -273,4 +274,39 @@ public function invokeChainCatchCallbacks($e) $callback($e); }); } + + /** + * Assert that the job has the given chain of jobs attached to it. + * + * @param array $expectedChain + * @return void + */ + public function assertHasChain($expectedChain) + { + PHPUnit::assertTrue( + collect($expectedChain)->isNotEmpty(), + 'The expected chain can not be empty.' + ); + + if (collect($expectedChain)->contains(fn ($job) => is_object($job))) { + $expectedChain = collect($expectedChain)->map(fn ($job) => serialize($job))->all(); + } else { + $chain = collect($this->chained)->map(fn ($job) => get_class(unserialize($job)))->all(); + } + + PHPUnit::assertTrue( + $expectedChain === ($chain ?? $this->chained), + 'The job does not have the expected chain.' + ); + } + + /** + * Assert that the job has no remaining chained jobs. + * + * @return void + */ + public function assertDoesntHaveChain() + { + PHPUnit::assertEmpty($this->chained, 'The job has chained jobs.'); + } } diff --git a/tests/Support/SupportTestingQueueFakeTest.php b/tests/Support/SupportTestingQueueFakeTest.php index dd632426d543..3122cbe6fe69 100644 --- a/tests/Support/SupportTestingQueueFakeTest.php +++ b/tests/Support/SupportTestingQueueFakeTest.php @@ -417,6 +417,69 @@ public function testItCanFakePushedJobsWithClassAndPayload() $fake->assertPushed('JobStub', 1); $fake->assertPushed('JobStub', fn ($job, $queue, $payload) => $payload === ['job' => 'payload']); } + + public function testAssertChainUsingClassesOrObjectsArray() + { + $job = new JobWithChainStub([ + new JobStub, + ]); + + $job->assertHasChain([ + JobStub::class, + ]); + + $job->assertHasChain([ + new JobStub(), + ]); + } + + public function testAssertNoChain() + { + $job = new JobWithChainStub([]); + + $job->assertDoesntHaveChain(); + } + + public function testAssertChainErrorHandling() + { + $job = new JobWithChainStub([ + new JobStub, + ]); + + try { + $job->assertHasChain([]); + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertStringContainsString('The expected chain can not be empty.', $e->getMessage()); + } + + try { + $job->assertHasChain([ + new JobStub, + new JobStub, + ]); + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertStringContainsString('The job does not have the expected chain.', $e->getMessage()); + } + + try { + $job->assertHasChain([ + JobStub::class, + JobStub::class, + ]); + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertStringContainsString('The job does not have the expected chain.', $e->getMessage()); + } + + try { + $job->assertDoesntHaveChain(); + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertStringContainsString('The job has chained jobs.', $e->getMessage()); + } + } } class JobStub From cc4dde4eb931d7aa246497dfddd8750c43d3211c Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Tue, 2 Apr 2024 02:07:01 +0330 Subject: [PATCH 057/123] Fix: Remove redundant overrides in classes extending GeneratorCommand (#50880) --- .../Foundation/Console/ClassMakeCommand.php | 11 ----------- .../Foundation/Console/InterfaceMakeCommand.php | 11 ----------- .../Foundation/Console/TraitMakeCommand.php | 11 ----------- 3 files changed, 33 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ClassMakeCommand.php b/src/Illuminate/Foundation/Console/ClassMakeCommand.php index 5c091c6098fb..17144d35ba04 100644 --- a/src/Illuminate/Foundation/Console/ClassMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ClassMakeCommand.php @@ -55,17 +55,6 @@ protected function resolveStubPath($stub) : __DIR__.$stub; } - /** - * Get the default namespace for the class. - * - * @param string $rootNamespace - * @return string - */ - protected function getDefaultNamespace($rootNamespace) - { - return $rootNamespace; - } - /** * Get the console command arguments. * diff --git a/src/Illuminate/Foundation/Console/InterfaceMakeCommand.php b/src/Illuminate/Foundation/Console/InterfaceMakeCommand.php index f2dcf7d804c4..2e864de169cd 100644 --- a/src/Illuminate/Foundation/Console/InterfaceMakeCommand.php +++ b/src/Illuminate/Foundation/Console/InterfaceMakeCommand.php @@ -40,17 +40,6 @@ protected function getStub() return __DIR__.'/stubs/interface.stub'; } - /** - * Get the default namespace for the class. - * - * @param string $rootNamespace - * @return string - */ - protected function getDefaultNamespace($rootNamespace) - { - return $rootNamespace; - } - /** * Get the console command arguments. * diff --git a/src/Illuminate/Foundation/Console/TraitMakeCommand.php b/src/Illuminate/Foundation/Console/TraitMakeCommand.php index a4542018c15c..5d98d1c9ce0e 100644 --- a/src/Illuminate/Foundation/Console/TraitMakeCommand.php +++ b/src/Illuminate/Foundation/Console/TraitMakeCommand.php @@ -53,17 +53,6 @@ protected function resolveStubPath($stub) : __DIR__.$stub; } - /** - * Get the default namespace for the class. - * - * @param string $rootNamespace - * @return string - */ - protected function getDefaultNamespace($rootNamespace) - { - return $rootNamespace; - } - /** * Get the console command arguments. * From 28de931377aed9fc2935b62f4bbd4bedab3eca30 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Tue, 2 Apr 2024 02:17:30 +0330 Subject: [PATCH 058/123] Fix: Remove implementation of ConnectorInterface in MariaDbConnector (#50881) --- src/Illuminate/Database/Connectors/MariaDbConnector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Connectors/MariaDbConnector.php b/src/Illuminate/Database/Connectors/MariaDbConnector.php index 560e31c96916..b7203f87ae2f 100755 --- a/src/Illuminate/Database/Connectors/MariaDbConnector.php +++ b/src/Illuminate/Database/Connectors/MariaDbConnector.php @@ -4,7 +4,7 @@ use PDO; -class MariaDbConnector extends MySqlConnector implements ConnectorInterface +class MariaDbConnector extends MySqlConnector { /** * Get the sql_mode value. From f172dfac830e00fd32604127b0cb2ecc8a2a0855 Mon Sep 17 00:00:00 2001 From: Kelvin Macharia Ngunyi Date: Tue, 2 Apr 2024 16:11:56 +0300 Subject: [PATCH 059/123] fix: error when using `orderByRaw` in query before using `cursorPaginate()` (#50887) Error: `array_flip(): Can only flip string and integer values, entry skipped` --- src/Illuminate/Pagination/AbstractCursorPaginator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Pagination/AbstractCursorPaginator.php b/src/Illuminate/Pagination/AbstractCursorPaginator.php index 5a150f132279..27f470382d8e 100644 --- a/src/Illuminate/Pagination/AbstractCursorPaginator.php +++ b/src/Illuminate/Pagination/AbstractCursorPaginator.php @@ -206,6 +206,7 @@ public function getCursorForItem($item, $isNext = true) public function getParametersForItem($item) { return collect($this->parameters) + ->filter() ->flip() ->map(function ($_, $parameterName) use ($item) { if ($item instanceof JsonResource) { From a1750156b671f37cba702380107e2d22161c31e3 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 2 Apr 2024 14:01:33 +0000 Subject: [PATCH 060/123] Update version to v11.2.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 41a3b2065989..a96232ba4b3e 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.1.1'; + const VERSION = '11.2.0'; /** * The base path for the Laravel installation. From 209800f04a1b6012a70c25f9e2164cbe28c9d0ed Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 2 Apr 2024 14:03:35 +0000 Subject: [PATCH 061/123] Update CHANGELOG --- CHANGELOG.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a12ce8194534..7fe23c2c387a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,31 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.1.1...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.2.0...11.x) + +## [v11.2.0](https://github.com/laravel/framework/compare/v11.1.1...v11.2.0) - 2024-04-02 + +* [11.x] Fix: update `[@param](https://github.com/param)` in some doc block by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50827 +* [11.x] Fix: update [@return](https://github.com/return) in some doc blocks by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50826 +* [11.x] Fix retrieving generated columns on legacy PostgreSQL by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/50834 +* [11.x] Trim invisible characters by [@dasundev](https://github.com/dasundev) in https://github.com/laravel/framework/pull/50832 +* [11.x] Add default value for `get` and `getHidden` on `Context` by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/50824 +* [11.x] Improves `serve` Artisan command by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/framework/pull/50821 +* [11.x] Rehash user passwords when logging in once by [@axlon](https://github.com/axlon) in https://github.com/laravel/framework/pull/50843 +* [11.x] Do not wipe database if it does not exists by [@driesvints](https://github.com/driesvints) in https://github.com/laravel/framework/pull/50838 +* [11.x] Better database creation failure handling by [@driesvints](https://github.com/driesvints) in https://github.com/laravel/framework/pull/50836 +* [11.x] Use Default Schema Name on SQL Server by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/50855 +* Correct typing for startedAs and virtualAs database column definitions by [@ollieread](https://github.com/ollieread) in https://github.com/laravel/framework/pull/50851 +* Allow passing query Expression as column in Many-to-Many relationship by [@plumthedev](https://github.com/plumthedev) in https://github.com/laravel/framework/pull/50849 +* [11.x] Fix `Middleware::trustHosts(subdomains: true)` by [@axlon](https://github.com/axlon) in https://github.com/laravel/framework/pull/50877 +* [11.x] Modify doc blocks for getGateArguments by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50874 +* [11.x] Add `[@throws](https://github.com/throws)` to doc block for resolve method by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50873 +* [11.x] Str trim methods by [@patrickomeara](https://github.com/patrickomeara) in https://github.com/laravel/framework/pull/50822 +* [11.x] Add fluent helper by [@PhiloNL](https://github.com/PhiloNL) in https://github.com/laravel/framework/pull/50848 +* [11.x] Add a new helper for context by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/50878 +* [11.x] `assertChain` and `assertNoChain` on job instance by [@gdebrauwer](https://github.com/gdebrauwer) in https://github.com/laravel/framework/pull/50858 +* [11.x] Remove redundant `getDefaultNamespace` method in some classes (class, interface and trait commands) by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50880 +* [11.x] Remove redundant implementation of ConnectorInterface in MariaDbConnector by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50881 +* [11.X] Fix: error when using `orderByRaw` in query before using `cursorPaginate` by [@ngunyimacharia](https://github.com/ngunyimacharia) in https://github.com/laravel/framework/pull/50887 ## [v11.1.1](https://github.com/laravel/framework/compare/v11.1.0...v11.1.1) - 2024-03-28 From 94bfff1d057c9c53d24ad0c3b66294e4c0a81bb7 Mon Sep 17 00:00:00 2001 From: Mina William Date: Wed, 3 Apr 2024 16:41:15 +0200 Subject: [PATCH 062/123] [11.x] Introduce if_successful directive for conditional caching control (#50903) * Introduce if_successful directive for conditional caching control * Update SetCacheHeaders.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Http/Middleware/SetCacheHeaders.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Http/Middleware/SetCacheHeaders.php b/src/Illuminate/Http/Middleware/SetCacheHeaders.php index 4b34061ae715..a6e7e807869e 100644 --- a/src/Illuminate/Http/Middleware/SetCacheHeaders.php +++ b/src/Illuminate/Http/Middleware/SetCacheHeaders.php @@ -50,6 +50,10 @@ public function handle($request, Closure $next, $options = []) $options = $this->parseOptions($options); } + if (! $response->isSuccessful()) { + return $response; + } + if (isset($options['etag']) && $options['etag'] === true) { $options['etag'] = $response->getEtag() ?? md5($response->getContent()); } From 1bf10e62d161114ad147578ad44cc080f3361a1b Mon Sep 17 00:00:00 2001 From: Mahmoud Mohamed Ramadan <48416569+mahmoudmohamedramadan@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:46:15 +0200 Subject: [PATCH 063/123] [11.x] Add Session `hasAny` method (#50897) * Add `hasAny` method * Add the test method * Update Store.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Session/Store.php | 15 ++++++++++++++- tests/Session/SessionStoreTest.php | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Session/Store.php b/src/Illuminate/Session/Store.php index fb9e2c4fd5d2..5e07f5f34bf8 100755 --- a/src/Illuminate/Session/Store.php +++ b/src/Illuminate/Session/Store.php @@ -283,7 +283,7 @@ public function missing($key) } /** - * Checks if a key is present and not null. + * Determine if a key is present and not null. * * @param string|array $key * @return bool @@ -295,6 +295,19 @@ public function has($key) }); } + /** + * Determine if any of the given keys are present and not null. + * + * @param string|array $key + * @return bool + */ + public function hasAny($key) + { + return collect(is_array($key) ? $key : func_get_args())->filter(function ($key) { + return ! is_null($this->get($key)); + })->count() >= 1; + } + /** * Get an item from the session. * diff --git a/tests/Session/SessionStoreTest.php b/tests/Session/SessionStoreTest.php index bfb064048e50..9f2e89a98ece 100644 --- a/tests/Session/SessionStoreTest.php +++ b/tests/Session/SessionStoreTest.php @@ -521,6 +521,22 @@ public function testKeyHas() $this->assertFalse($session->has('foo', 'bar')); } + public function testKeyHasAny() + { + $session = $this->getSession(); + $session->put('first_name', 'Mahmoud'); + $session->put('last_name', 'Ramadan'); + + $this->assertTrue($session->hasAny('first_name')); + $this->assertTrue($session->hasAny('first_name', 'last_name')); + $this->assertTrue($session->hasAny(['first_name', 'last_name'])); + $this->assertTrue($session->hasAny(['first_name', 'middle_name'])); + + $this->assertFalse($session->hasAny('middle_name')); + $this->assertFalse($session->hasAny('foo', 'bar')); + $this->assertFalse($session->hasAny(['foo', 'bar'])); + } + public function testKeyExists() { $session = $this->getSession(); From 627e9c5f40a3464545abf25f481c357df5b47558 Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Wed, 3 Apr 2024 14:46:45 +0000 Subject: [PATCH 064/123] Update facade docblocks --- src/Illuminate/Support/Facades/Session.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Session.php b/src/Illuminate/Support/Facades/Session.php index 125b3dbb496f..fe0f447f43a6 100755 --- a/src/Illuminate/Support/Facades/Session.php +++ b/src/Illuminate/Support/Facades/Session.php @@ -25,6 +25,7 @@ * @method static bool exists(string|array $key) * @method static bool missing(string|array $key) * @method static bool has(string|array $key) + * @method static bool hasAny(string|array $key) * @method static mixed get(string $key, mixed $default = null) * @method static mixed pull(string $key, mixed $default = null) * @method static bool hasOldInput(string|null $key = null) From 552bdee19eb52de423c4d86d5ed6206d74dd9de9 Mon Sep 17 00:00:00 2001 From: Jasper Zonneveld Date: Wed, 3 Apr 2024 16:51:08 +0200 Subject: [PATCH 065/123] [11.x] Add option to report throttled exception in ThrottlesExceptions middleware (#50896) * feat: add option to report the throttled exception * Update ThrottlesExceptions.php --------- Co-authored-by: Taylor Otwell --- .../Queue/Middleware/ThrottlesExceptions.php | 24 ++++++++++++++ .../ThrottlesExceptionsWithRedis.php | 4 +++ .../Queue/ThrottlesExceptionsTest.php | 31 ++++++++++++++++++ .../ThrottlesExceptionsWithRedisTest.php | 32 +++++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php index 60ba1801c7d8..83d789616649 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php @@ -43,6 +43,13 @@ class ThrottlesExceptions */ protected $retryAfterMinutes = 0; + /** + * The callback that determines if the exception should be reported. + * + * @var callable + */ + protected $reportCallback; + /** * The callback that determines if rate limiting should apply. * @@ -101,6 +108,10 @@ public function handle($job, $next) throw $throwable; } + if ($this->reportCallback && call_user_func($this->reportCallback, $throwable)) { + report($throwable); + } + $this->limiter->hit($jobKey, $this->decaySeconds); return $job->release($this->retryAfterMinutes * 60); @@ -188,6 +199,19 @@ public function byJob() return $this; } + /** + * Report exceptions and optionally specify a callback that determines if the exception should be reported. + * + * @param callable|null $callback + * @return $this + */ + public function report(?callable $callback = null) + { + $this->reportCallback = $callback ?? fn () => true; + + return $this; + } + /** * Get the number of seconds that should elapse before the job is retried. * diff --git a/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php b/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php index 0dbc9443b4b0..e5b79a7d67ed 100644 --- a/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php +++ b/src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php @@ -54,6 +54,10 @@ public function handle($job, $next) throw $throwable; } + if ($this->reportCallback && call_user_func($this->reportCallback, $throwable)) { + report($throwable); + } + $this->limiter->acquire(); return $job->release($this->retryAfterMinutes * 60); diff --git a/tests/Integration/Queue/ThrottlesExceptionsTest.php b/tests/Integration/Queue/ThrottlesExceptionsTest.php index 2b583f416435..e559c41b7f8f 100644 --- a/tests/Integration/Queue/ThrottlesExceptionsTest.php +++ b/tests/Integration/Queue/ThrottlesExceptionsTest.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Bus\Dispatcher; use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Queue\Job; use Illuminate\Queue\CallQueuedHandler; use Illuminate\Queue\InteractsWithQueue; @@ -262,6 +263,36 @@ public function release() $this->assertTrue($job->released); $this->assertTrue($job->handled); } + + public function testReportingExceptions() + { + $this->spy(ExceptionHandler::class) + ->shouldReceive('report') + ->twice() + ->with(m::type(RuntimeException::class)); + + $job = new class + { + public function release() + { + return $this; + } + }; + $next = function () { + throw new RuntimeException('Whoops!'); + }; + + $middleware = new ThrottlesExceptions(); + + $middleware->report(); + $middleware->handle($job, $next); + + $middleware->report(fn () => true); + $middleware->handle($job, $next); + + $middleware->report(fn () => false); + $middleware->handle($job, $next); + } } class CircuitBreakerTestJob diff --git a/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php b/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php index f035f85c00a2..4a11502ae293 100644 --- a/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php +++ b/tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Bus\Dispatcher; use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Queue\Job; use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; use Illuminate\Queue\CallQueuedHandler; @@ -14,6 +15,7 @@ use Illuminate\Support\Str; use Mockery as m; use Orchestra\Testbench\TestCase; +use RuntimeException; class ThrottlesExceptionsWithRedisTest extends TestCase { @@ -116,6 +118,36 @@ protected function assertJobRanSuccessfully($class, $key) $this->assertTrue($class::$handled); } + + public function testReportingExceptions() + { + $this->spy(ExceptionHandler::class) + ->shouldReceive('report') + ->twice() + ->with(m::type(RuntimeException::class)); + + $job = new class + { + public function release() + { + return $this; + } + }; + $next = function () { + throw new RuntimeException('Whoops!'); + }; + + $middleware = new ThrottlesExceptionsWithRedis(); + + $middleware->report(); + $middleware->handle($job, $next); + + $middleware->report(fn () => true); + $middleware->handle($job, $next); + + $middleware->report(fn () => false); + $middleware->handle($job, $next); + } } class CircuitBreakerWithRedisTestJob From da0120adc331adc536bb86f8ef40cce14ee4b274 Mon Sep 17 00:00:00 2001 From: Milwad <98118400+milwad-dev@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:28:09 +0330 Subject: [PATCH 066/123] [11.x] Add tests for `Pivot` methods (#50891) * add `testOrWherePivotOnBoolean` * add `testWherePivotNotBetween` test * Update EloquentBelongsToManyTest.php * Update EloquentBelongsToManyTest.php * Update EloquentBelongsToManyTest.php --- .../Database/EloquentBelongsToManyTest.php | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 7f77db612656..68087659bb6c 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -65,6 +65,7 @@ protected function afterRefreshingDatabase() $table->integer('tag_id')->default(0); $table->string('tag_name')->default('')->nullable(); $table->string('flag')->default('')->nullable(); + $table->string('isActive')->default('')->nullable(); $table->timestamps(); }); @@ -985,6 +986,36 @@ public function testWherePivotOnBoolean() $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); } + public function testOrWherePivotOnBoolean() + { + $tag = Tag::create(['name' => Str::random()])->fresh(); + $post = Post::create(['title' => Str::random()]); + + DB::table('posts_tags')->insert([ + ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => true, 'isActive' => false], + ]); + + $relationTag = $post->tags()->wherePivot('isActive', false)->orWherePivot('flag', true)->first(); + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + } + + public function testWherePivotNotBetween() + { + $tag = Tag::create(['name' => Str::random()])->fresh(); + $post = Post::create(['title' => Str::random()]); + + DB::table('posts_tags')->insert([ + ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => true, 'isActive' => false], + ]); + + $relationTag = $post->tags() + ->wherePivotNotBetween('isActive', ['true', 'false']) + ->orWherePivotNotBetween('flag', ['true', 'false']) + ->first(); + + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + } + public function testWherePivotInMethod() { $tag = Tag::create(['name' => Str::random()])->fresh(); @@ -1081,13 +1112,13 @@ public function testWherePivotNotNullMethod() $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ - ['post_id' => $post->id, 'tag_id' => $tag1->id, 'flag' => 'foo'], + ['post_id' => $post->id, 'tag_id' => $tag1->id, 'flag' => 'foo', 'isActive' => true], ]); DB::table('posts_tags')->insert([ - ['post_id' => $post->id, 'tag_id' => $tag2->id, 'flag' => null], + ['post_id' => $post->id, 'tag_id' => $tag2->id, 'flag' => null, 'isActive' => false], ]); - $relationTag = $post->tagsWithExtraPivot()->wherePivotNotNull('flag')->first(); + $relationTag = $post->tagsWithExtraPivot()->wherePivotNotNull('flag')->orWherePivotNotNull('isActive')->first(); $this->assertEquals($relationTag->getAttributes(), $tag1->getAttributes()); } From 96593e206d877ae33c784b8af69be1e63455cca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=ABl=20Hagestein?= <6616996+Neol3108@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:09:55 +0200 Subject: [PATCH 067/123] Add DeleteWhenMissingModels attribute (#50890) --- .../Attributes/DeleteWhenMissingModels.php | 11 ++++++ src/Illuminate/Queue/CallQueuedHandler.php | 7 ++-- .../Queue/CallQueuedHandlerTest.php | 36 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/Illuminate/Queue/Attributes/DeleteWhenMissingModels.php diff --git a/src/Illuminate/Queue/Attributes/DeleteWhenMissingModels.php b/src/Illuminate/Queue/Attributes/DeleteWhenMissingModels.php new file mode 100644 index 000000000000..d4c10261a512 --- /dev/null +++ b/src/Illuminate/Queue/Attributes/DeleteWhenMissingModels.php @@ -0,0 +1,11 @@ +resolveName(); try { - $shouldDelete = (new ReflectionClass($class)) - ->getDefaultProperties()['deleteWhenMissingModels'] ?? false; + $reflectionClass = new ReflectionClass($class); + + $shouldDelete = $reflectionClass->getDefaultProperties()['deleteWhenMissingModels'] + ?? count($reflectionClass->getAttributes(DeleteWhenMissingModels::class)) !== 0; } catch (Exception) { $shouldDelete = false; } diff --git a/tests/Integration/Queue/CallQueuedHandlerTest.php b/tests/Integration/Queue/CallQueuedHandlerTest.php index bd4a179322ac..8afa8fe9e025 100644 --- a/tests/Integration/Queue/CallQueuedHandlerTest.php +++ b/tests/Integration/Queue/CallQueuedHandlerTest.php @@ -6,6 +6,7 @@ use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\Job; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Queue\Attributes\DeleteWhenMissingModels; use Illuminate\Queue\CallQueuedHandler; use Illuminate\Queue\Events\JobFailed; use Illuminate\Queue\InteractsWithQueue; @@ -117,6 +118,27 @@ public function testJobIsDeletedIfHasDeleteProperty() Event::assertNotDispatched(JobFailed::class); } + + public function testJobIsDeletedIfHasDeleteAttribute() + { + Event::fake(); + + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $job = m::mock(Job::class); + $job->shouldReceive('getConnectionName')->andReturn('connection'); + $job->shouldReceive('resolveName')->andReturn(CallQueuedHandlerAttributeExceptionThrower::class); + $job->shouldReceive('markAsFailed')->never(); + $job->shouldReceive('isDeleted')->andReturn(false); + $job->shouldReceive('delete')->once(); + $job->shouldReceive('failed')->never(); + + $instance->call($job, [ + 'command' => serialize(new CallQueuedHandlerAttributeExceptionThrower()), + ]); + + Event::assertNotDispatched(JobFailed::class); + } } class CallQueuedHandlerTestJob @@ -179,6 +201,20 @@ public function __wakeup() } } +#[DeleteWhenMissingModels] +class CallQueuedHandlerAttributeExceptionThrower +{ + public function handle() + { + // + } + + public function __wakeup() + { + throw new ModelNotFoundException('Foo'); + } +} + class TestJobMiddleware { public function handle($command, $next) From 95aa2fecec13ffdfe1d05c62001377a05296144f Mon Sep 17 00:00:00 2001 From: grohiro Date: Thu, 4 Apr 2024 00:18:37 +0900 Subject: [PATCH 068/123] [11.x] Allow customizing TrimStrings::$except (#50901) * extract method * formatting --------- Co-authored-by: Taylor Otwell --- .../Foundation/Http/Middleware/TrimStrings.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php index b82bdbfa8127..80be7a476e90 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php +++ b/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php @@ -62,13 +62,25 @@ protected function transform($key, $value) { $except = array_merge($this->except, static::$neverTrim); - if (in_array($key, $except, true) || ! is_string($value)) { + if ($this->shouldSkip($key, $except) || ! is_string($value)) { return $value; } return Str::trim($value); } + /** + * Determine if the given key should be skipped. + * + * @param string $key + * @param array $except + * @return bool + */ + protected function shouldSkip($key, $except) + { + return in_array($key, $except, true); + } + /** * Indicate that the given attributes should never be trimmed. * From 1b453a84552e8e6bc6368e7038ee4104a54ae01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9?= Date: Wed, 3 Apr 2024 17:54:09 +0200 Subject: [PATCH 069/123] [11.x] Add pull methods to Context (#50904) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [11.x] Add pull and pullHidden methods to Context * [11.x] fix typo in testcase name --------- Co-authored-by: René Geuze --- src/Illuminate/Log/Context/Repository.php | 28 ++++++++++++++++++++++ src/Illuminate/Support/Facades/Context.php | 2 ++ tests/Log/ContextTest.php | 15 +++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Log/Context/Repository.php b/src/Illuminate/Log/Context/Repository.php index 13b2b2b30d84..35779da3e70d 100644 --- a/src/Illuminate/Log/Context/Repository.php +++ b/src/Illuminate/Log/Context/Repository.php @@ -119,6 +119,34 @@ public function getHidden($key, $default = null) return $this->hidden[$key] ?? value($default); } + /** + * Retrieve the given key's value and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public function pull($key, $default = null) + { + return tap($this->get($key, $default), function () use ($key) { + $this->forget($key); + }); + } + + /** + * Retrieve the given key's hidden value and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public function pullHidden($key, $default = null) + { + return tap($this->getHidden($key, $default), function () use ($key) { + $this->forgetHidden($key); + }); + } + /** * Retrieve only the values of the given keys. * diff --git a/src/Illuminate/Support/Facades/Context.php b/src/Illuminate/Support/Facades/Context.php index ef77e87ba815..b8e44f28b126 100644 --- a/src/Illuminate/Support/Facades/Context.php +++ b/src/Illuminate/Support/Facades/Context.php @@ -9,6 +9,8 @@ * @method static array allHidden() * @method static mixed get(string $key, mixed $default = null) * @method static mixed getHidden(string $key, mixed $default = null) + * @method static mixed pull(string $key, mixed $default = null) + * @method static mixed pullHidden(string $key, mixed $default = null) * @method static array only(array $keys) * @method static array onlyHidden(array $keys) * @method static \Illuminate\Log\Context\Repository add(string|array $key, mixed $value = null) diff --git a/tests/Log/ContextTest.php b/tests/Log/ContextTest.php index 5290e546df83..b9c647e596fb 100644 --- a/tests/Log/ContextTest.php +++ b/tests/Log/ContextTest.php @@ -114,7 +114,7 @@ public function test_hydrating_null_triggers_hydrating_event() $this->assertTrue($called); } - public function test_it_can_serilize_values() + public function test_it_can_serialize_values() { Context::add([ 'string' => 'string', @@ -354,6 +354,19 @@ public function test_it_can_add_hidden() Context::pushHidden('foo', 2); } + public function test_it_can_pull() + { + Context::add('foo', 'data'); + + $this->assertSame('data', Context::pull('foo')); + $this->assertNull(Context::get('foo')); + + Context::addHidden('foo', 'data'); + + $this->assertSame('data', Context::pullHidden('foo')); + $this->assertNull(Context::getHidden('foo')); + } + public function test_it_adds_context_to_logged_exceptions() { $path = storage_path('logs/laravel.log'); From b9e4c7a27f30f05a87563f82b4917c544f8eb1bd Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 3 Apr 2024 21:08:50 +0330 Subject: [PATCH 070/123] [11.x] Remove redundant code from MariaDbGrammar (#50907) * remove redundant code * force re-run tests * Update MySqlGrammar.php --------- Co-authored-by: Taylor Otwell --- .../Schema/Grammars/MariaDbGrammar.php | 31 +------- .../Database/Schema/Grammars/MySqlGrammar.php | 77 +++++++++++-------- .../Database/DatabaseSchemaBlueprintTest.php | 3 +- 3 files changed, 48 insertions(+), 63 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php index 39ae68619127..2996406a27fb 100755 --- a/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MariaDbGrammar.php @@ -3,9 +3,7 @@ namespace Illuminate\Database\Schema\Grammars; use Illuminate\Database\Connection; -use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Schema\ColumnDefinition; use Illuminate\Support\Fluent; class MariaDbGrammar extends MySqlGrammar @@ -21,34 +19,7 @@ class MariaDbGrammar extends MySqlGrammar public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) { if (version_compare($connection->getServerVersion(), '10.5.2', '<')) { - $column = collect($connection->getSchemaBuilder()->getColumns($blueprint->getTable())) - ->firstWhere('name', $command->from); - - $modifiers = $this->addModifiers($column['type'], $blueprint, new ColumnDefinition([ - 'change' => true, - 'type' => match ($column['type_name']) { - 'bigint' => 'bigInteger', - 'int' => 'integer', - 'mediumint' => 'mediumInteger', - 'smallint' => 'smallInteger', - 'tinyint' => 'tinyInteger', - default => $column['type_name'], - }, - 'nullable' => $column['nullable'], - 'default' => $column['default'] && str_starts_with(strtolower($column['default']), 'current_timestamp') - ? new Expression($column['default']) - : $column['default'], - 'autoIncrement' => $column['auto_increment'], - 'collation' => $column['collation'], - 'comment' => $column['comment'], - ])); - - return sprintf('alter table %s change %s %s %s', - $this->wrapTable($blueprint), - $this->wrap($command->from), - $this->wrap($command->to), - $modifiers - ); + return $this->compileLegacyRenameColumn($blueprint, $command, $connection); } return parent::compileRenameColumn($blueprint, $command, $connection); diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 7fed371ea109..0c39a4b1e3f5 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -324,43 +324,56 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne if (($connection->isMaria() && version_compare($version, '10.5.2', '<')) || (! $connection->isMaria() && version_compare($version, '8.0.3', '<'))) { - $column = collect($connection->getSchemaBuilder()->getColumns($blueprint->getTable())) - ->firstWhere('name', $command->from); - - $modifiers = $this->addModifiers($column['type'], $blueprint, new ColumnDefinition([ - 'change' => true, - 'type' => match ($column['type_name']) { - 'bigint' => 'bigInteger', - 'int' => 'integer', - 'mediumint' => 'mediumInteger', - 'smallint' => 'smallInteger', - 'tinyint' => 'tinyInteger', - default => $column['type_name'], - }, - 'nullable' => $column['nullable'], - 'default' => $column['default'] && str_starts_with(strtolower($column['default']), 'current_timestamp') - ? new Expression($column['default']) - : $column['default'], - 'autoIncrement' => $column['auto_increment'], - 'collation' => $column['collation'], - 'comment' => $column['comment'], - 'virtualAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'virtual' - ? $column['generation']['expression'] : null, - 'storedAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'stored' - ? $column['generation']['expression'] : null, - ])); - - return sprintf('alter table %s change %s %s %s', - $this->wrapTable($blueprint), - $this->wrap($command->from), - $this->wrap($command->to), - $modifiers - ); + return $this->compileLegacyRenameColumn($blueprint, $command, $connection); } return parent::compileRenameColumn($blueprint, $command, $connection); } + /** + * Compile a rename column command for legacy versions of MySQL. + * + * @param \Illuminate\Database\Schema\Blueprint $blueprint + * @param \Illuminate\Support\Fluent $command + * @param \Illuminate\Database\Connection $connection + * @return string + */ + protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection) + { + $column = collect($connection->getSchemaBuilder()->getColumns($blueprint->getTable())) + ->firstWhere('name', $command->from); + + $modifiers = $this->addModifiers($column['type'], $blueprint, new ColumnDefinition([ + 'change' => true, + 'type' => match ($column['type_name']) { + 'bigint' => 'bigInteger', + 'int' => 'integer', + 'mediumint' => 'mediumInteger', + 'smallint' => 'smallInteger', + 'tinyint' => 'tinyInteger', + default => $column['type_name'], + }, + 'nullable' => $column['nullable'], + 'default' => $column['default'] && str_starts_with(strtolower($column['default']), 'current_timestamp') + ? new Expression($column['default']) + : $column['default'], + 'autoIncrement' => $column['auto_increment'], + 'collation' => $column['collation'], + 'comment' => $column['comment'], + 'virtualAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'virtual' + ? $column['generation']['expression'] : null, + 'storedAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'stored' + ? $column['generation']['expression'] : null, + ])); + + return sprintf('alter table %s change %s %s %s', + $this->wrapTable($blueprint), + $this->wrap($command->from), + $this->wrap($command->to), + $modifiers + ); + } + /** * Compile a change column command into a series of SQL statements. * diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index 0fc9318d3269..6026b219b373 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -5,6 +5,7 @@ use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Builder; +use Illuminate\Database\Schema\Grammars\MariaDbGrammar; use Illuminate\Database\Schema\Grammars\MySqlGrammar; use Illuminate\Database\Schema\Grammars\PostgresGrammar; use Illuminate\Database\Schema\Grammars\SQLiteGrammar; @@ -229,7 +230,7 @@ public function testNativeRenameColumnOnLegacyMariaDB() "alter table `users` change `name` `title` varchar(255) collate 'utf8mb4_unicode_ci' null default 'foo'", "alter table `users` change `id` `key` bigint unsigned not null auto_increment comment 'lorem ipsum'", 'alter table `users` change `generated` `new_generated` int as (expression) stored not null', - ], $blueprint->toSql($connection, new MySqlGrammar)); + ], $blueprint->toSql($connection, new MariaDbGrammar)); } public function testDropColumn() From 654656d0250416623aeeb0b5b879956c03890fb0 Mon Sep 17 00:00:00 2001 From: Julius Kiekbusch Date: Thu, 4 Apr 2024 19:36:49 +0200 Subject: [PATCH 071/123] Add explicit nullable type declaration (#50922) --- .../Auth/Access/AuthorizationException.php | 2 +- src/Illuminate/Auth/Access/Gate.php | 4 +-- .../Auth/Passwords/PasswordBroker.php | 2 +- src/Illuminate/Auth/RequestGuard.php | 2 +- src/Illuminate/Auth/SessionGuard.php | 4 +-- .../Broadcasting/BroadcastManager.php | 6 ++--- src/Illuminate/Bus/Batch.php | 2 +- src/Illuminate/Bus/Dispatcher.php | 2 +- src/Illuminate/Cache/RedisTagSet.php | 2 +- src/Illuminate/Collections/Arr.php | 4 +-- src/Illuminate/Collections/Collection.php | 6 ++--- src/Illuminate/Collections/Enumerable.php | 20 +++++++------- src/Illuminate/Collections/LazyCollection.php | 6 ++--- .../Collections/Traits/EnumeratesValues.php | 10 +++---- .../Conditionable/Traits/Conditionable.php | 4 +-- src/Illuminate/Container/Container.php | 8 +++--- src/Illuminate/Contracts/Auth/Access/Gate.php | 2 +- .../Contracts/Auth/PasswordBroker.php | 2 +- .../Contracts/Container/Container.php | 6 ++--- .../Contracts/Notifications/Dispatcher.php | 2 +- .../Contracts/Process/InvokedProcess.php | 2 +- .../Contracts/Process/ProcessResult.php | 4 +-- src/Illuminate/Database/Capsule/Manager.php | 2 +- src/Illuminate/Database/Eloquent/Builder.php | 6 ++--- .../Database/Eloquent/Casts/Attribute.php | 4 +-- .../Concerns/QueriesRelationships.php | 26 +++++++++---------- src/Illuminate/Database/Eloquent/Model.php | 4 +-- .../Eloquent/Relations/BelongsToMany.php | 4 +-- .../Eloquent/Relations/HasManyThrough.php | 6 ++--- .../Database/Eloquent/Relations/Relation.php | 4 +-- src/Illuminate/Database/MariaDbConnection.php | 2 +- .../Database/Migrations/Migrator.php | 2 +- src/Illuminate/Database/MySqlConnection.php | 2 +- .../Database/PostgresConnection.php | 2 +- src/Illuminate/Database/Query/Builder.php | 6 ++--- src/Illuminate/Database/SQLiteConnection.php | 2 +- src/Illuminate/Database/Schema/Blueprint.php | 2 +- src/Illuminate/Database/Schema/Builder.php | 2 +- .../Database/Schema/SchemaState.php | 2 +- .../Database/SqlServerConnection.php | 2 +- src/Illuminate/Events/Dispatcher.php | 2 +- src/Illuminate/Foundation/Application.php | 2 +- .../Foundation/Configuration/Middleware.php | 6 ++--- .../Foundation/Console/AboutCommand.php | 6 ++--- .../Foundation/Http/FormRequest.php | 2 +- .../Concerns/InteractsWithContainer.php | 6 ++--- .../Validation/ValidatesRequests.php | 2 +- src/Illuminate/Http/Client/Factory.php | 2 +- src/Illuminate/Http/Client/PendingRequest.php | 4 +-- src/Illuminate/Http/Client/Pool.php | 2 +- .../Http/Concerns/InteractsWithInput.php | 6 ++--- .../Http/Exceptions/PostTooLargeException.php | 2 +- .../Exceptions/ThrottleRequestsException.php | 2 +- src/Illuminate/Http/RedirectResponse.php | 2 +- src/Illuminate/Http/Request.php | 2 +- src/Illuminate/Log/Logger.php | 2 +- src/Illuminate/Mail/Mailables/Address.php | 2 +- src/Illuminate/Mail/Mailables/Content.php | 2 +- src/Illuminate/Mail/Mailables/Envelope.php | 12 ++++----- src/Illuminate/Mail/Mailables/Headers.php | 2 +- src/Illuminate/Mail/Mailer.php | 2 +- .../Mail/Transport/ArrayTransport.php | 2 +- .../Mail/Transport/LogTransport.php | 2 +- .../Notifications/ChannelManager.php | 2 +- .../Notifications/NotificationSender.php | 2 +- .../Notifications/RoutesNotifications.php | 2 +- .../Notifications/SendQueuedNotifications.php | 2 +- src/Illuminate/Pipeline/Hub.php | 2 +- src/Illuminate/Pipeline/Pipeline.php | 2 +- src/Illuminate/Process/Factory.php | 2 +- src/Illuminate/Process/FakeInvokedProcess.php | 2 +- src/Illuminate/Process/FakeProcessResult.php | 4 +-- src/Illuminate/Process/InvokedProcess.php | 2 +- src/Illuminate/Process/PendingProcess.php | 4 +-- src/Illuminate/Process/ProcessResult.php | 4 +-- src/Illuminate/Queue/Capsule/Manager.php | 2 +- src/Illuminate/Queue/Worker.php | 2 +- .../Redis/Connections/PhpRedisConnection.php | 6 ++--- .../Limiters/ConcurrencyLimiterBuilder.php | 2 +- .../Redis/Limiters/DurationLimiterBuilder.php | 2 +- src/Illuminate/Routing/Router.php | 4 +-- .../Session/DatabaseSessionHandler.php | 2 +- .../Session/Middleware/StartSession.php | 4 +-- .../Session/SymfonySessionDecorator.php | 4 +-- src/Illuminate/Support/Composer.php | 4 +-- src/Illuminate/Support/Facades/Bus.php | 2 +- src/Illuminate/Support/Facades/Process.php | 2 +- src/Illuminate/Support/ServiceProvider.php | 2 +- src/Illuminate/Support/Str.php | 10 +++---- .../Support/Testing/Fakes/BusFake.php | 2 +- .../Testing/Fakes/NotificationFake.php | 2 +- src/Illuminate/Support/helpers.php | 4 +-- .../Testing/AssertableJsonString.php | 2 +- .../Testing/Fluent/AssertableJson.php | 4 +-- .../Testing/Fluent/Concerns/Debugging.php | 4 +-- .../Testing/Fluent/Concerns/Has.php | 6 ++--- .../Testing/Fluent/Concerns/Interaction.php | 2 +- .../Testing/Fluent/Concerns/Matching.php | 4 +-- src/Illuminate/Testing/TestResponse.php | 2 +- .../Validation/Concerns/FormatsMessages.php | 2 +- src/Illuminate/Validation/Factory.php | 2 +- src/Illuminate/Validation/Validator.php | 4 +-- .../View/Compilers/BladeCompiler.php | 4 +-- .../View/Engines/CompilerEngine.php | 2 +- src/Illuminate/View/FileViewFinder.php | 2 +- src/Illuminate/View/View.php | 2 +- tests/Auth/AuthAccessGateTest.php | 8 +++--- .../ContainerResolveNonInstantiableTest.php | 2 +- tests/Container/ContextualBindingTest.php | 2 +- tests/Routing/RoutingRouteTest.php | 12 ++++----- tests/Support/SupportCarbonTest.php | 2 +- tests/Support/SupportReflectsClosuresTest.php | 2 +- 112 files changed, 206 insertions(+), 206 deletions(-) diff --git a/src/Illuminate/Auth/Access/AuthorizationException.php b/src/Illuminate/Auth/Access/AuthorizationException.php index 17101b4d07d5..1454bde2a01d 100644 --- a/src/Illuminate/Auth/Access/AuthorizationException.php +++ b/src/Illuminate/Auth/Access/AuthorizationException.php @@ -29,7 +29,7 @@ class AuthorizationException extends Exception * @param \Throwable|null $previous * @return void */ - public function __construct($message = null, $code = null, Throwable $previous = null) + public function __construct($message = null, $code = null, ?Throwable $previous = null) { parent::__construct($message ?? 'This action is unauthorized.', 0, $previous); diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 1f0a72007e9d..2f0c6c6c1151 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -100,7 +100,7 @@ public function __construct(Container $container, array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [], - callable $guessPolicyNamesUsingCallback = null) + ?callable $guessPolicyNamesUsingCallback = null) { $this->policies = $policies; $this->container = $container; @@ -224,7 +224,7 @@ public function define($ability, $callback) * @param array|null $abilities * @return $this */ - public function resource($name, $class, array $abilities = null) + public function resource($name, $class, ?array $abilities = null) { $abilities = $abilities ?: [ 'viewAny' => 'viewAny', diff --git a/src/Illuminate/Auth/Passwords/PasswordBroker.php b/src/Illuminate/Auth/Passwords/PasswordBroker.php index a0d1d194ba9c..eb213c498876 100755 --- a/src/Illuminate/Auth/Passwords/PasswordBroker.php +++ b/src/Illuminate/Auth/Passwords/PasswordBroker.php @@ -45,7 +45,7 @@ public function __construct(TokenRepositoryInterface $tokens, UserProvider $user * @param \Closure|null $callback * @return string */ - public function sendResetLink(array $credentials, Closure $callback = null) + public function sendResetLink(array $credentials, ?Closure $callback = null) { // First we will check to see if we found a user at the given credentials and // if we did not we will redirect back to this current URI with a piece of diff --git a/src/Illuminate/Auth/RequestGuard.php b/src/Illuminate/Auth/RequestGuard.php index d0af83cb4f4f..7c1dfdc553e0 100644 --- a/src/Illuminate/Auth/RequestGuard.php +++ b/src/Illuminate/Auth/RequestGuard.php @@ -33,7 +33,7 @@ class RequestGuard implements Guard * @param \Illuminate\Contracts\Auth\UserProvider|null $provider * @return void */ - public function __construct(callable $callback, Request $request, UserProvider $provider = null) + public function __construct(callable $callback, Request $request, ?UserProvider $provider = null) { $this->request = $request; $this->callback = $callback; diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index a88e213dbb5c..ebcf0de61fb0 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -131,8 +131,8 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth public function __construct($name, UserProvider $provider, Session $session, - Request $request = null, - Timebox $timebox = null, + ?Request $request = null, + ?Timebox $timebox = null, bool $rehashOnLogin = true) { $this->name = $name; diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 6bac6647548a..1704c9f2bfdc 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -64,7 +64,7 @@ public function __construct($app) * @param array|null $attributes * @return void */ - public function routes(array $attributes = null) + public function routes(?array $attributes = null) { if ($this->app instanceof CachesRoutes && $this->app->routesAreCached()) { return; @@ -86,7 +86,7 @@ public function routes(array $attributes = null) * @param array|null $attributes * @return void */ - public function userRoutes(array $attributes = null) + public function userRoutes(?array $attributes = null) { if ($this->app instanceof CachesRoutes && $this->app->routesAreCached()) { return; @@ -110,7 +110,7 @@ public function userRoutes(array $attributes = null) * @param array|null $attributes * @return void */ - public function channelRoutes(array $attributes = null) + public function channelRoutes(?array $attributes = null) { $this->routes($attributes); } diff --git a/src/Illuminate/Bus/Batch.php b/src/Illuminate/Bus/Batch.php index e08b4a975ae4..a5d6fc63f941 100644 --- a/src/Illuminate/Bus/Batch.php +++ b/src/Illuminate/Bus/Batch.php @@ -450,7 +450,7 @@ public function delete() * @param \Throwable|null $e * @return void */ - protected function invokeHandlerCallback($handler, Batch $batch, Throwable $e = null) + protected function invokeHandlerCallback($handler, Batch $batch, ?Throwable $e = null) { try { return $handler($batch, $e); diff --git a/src/Illuminate/Bus/Dispatcher.php b/src/Illuminate/Bus/Dispatcher.php index 86b19dfea394..68fad13897c6 100644 --- a/src/Illuminate/Bus/Dispatcher.php +++ b/src/Illuminate/Bus/Dispatcher.php @@ -58,7 +58,7 @@ class Dispatcher implements QueueingDispatcher * @param \Closure|null $queueResolver * @return void */ - public function __construct(Container $container, Closure $queueResolver = null) + public function __construct(Container $container, ?Closure $queueResolver = null) { $this->container = $container; $this->queueResolver = $queueResolver; diff --git a/src/Illuminate/Cache/RedisTagSet.php b/src/Illuminate/Cache/RedisTagSet.php index b5fd0e2593bc..072a01bc2365 100644 --- a/src/Illuminate/Cache/RedisTagSet.php +++ b/src/Illuminate/Cache/RedisTagSet.php @@ -15,7 +15,7 @@ class RedisTagSet extends TagSet * @param string $updateWhen * @return void */ - public function addEntry(string $key, int $ttl = null, $updateWhen = null) + public function addEntry(string $key, ?int $ttl = null, $updateWhen = null) { $ttl = is_null($ttl) ? -1 : Carbon::now()->addSeconds($ttl)->getTimestamp(); diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 5d473c26575b..605f71499b93 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -190,7 +190,7 @@ public static function exists($array, $key) * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ - public static function first($array, callable $callback = null, $default = null) + public static function first($array, ?callable $callback = null, $default = null) { if (is_null($callback)) { if (empty($array)) { @@ -221,7 +221,7 @@ public static function first($array, callable $callback = null, $default = null) * @param mixed $default * @return mixed */ - public static function last($array, callable $callback = null, $default = null) + public static function last($array, ?callable $callback = null, $default = null) { if (is_null($callback)) { return empty($array) ? value($default) : end($array); diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index c7f15209ef3b..966caaa2c1a1 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -381,7 +381,7 @@ public function except($keys) * @param (callable(TValue, TKey): bool)|null $callback * @return static */ - public function filter(callable $callback = null) + public function filter(?callable $callback = null) { if ($callback) { return new static(Arr::where($this->items, $callback)); @@ -399,7 +399,7 @@ public function filter(callable $callback = null) * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ - public function first(callable $callback = null, $default = null) + public function first(?callable $callback = null, $default = null) { return Arr::first($this->items, $callback, $default); } @@ -747,7 +747,7 @@ public function keys() * @param TLastDefault|(\Closure(): TLastDefault) $default * @return TValue|TLastDefault */ - public function last(callable $callback = null, $default = null) + public function last(?callable $callback = null, $default = null) { return Arr::last($this->items, $callback, $default); } diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index 6a16ac03093b..f52b67e7e9d7 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -38,7 +38,7 @@ public static function make($items = []); * @param callable|null $callback * @return static */ - public static function times($number, callable $callback = null); + public static function times($number, ?callable $callback = null); /** * Create a collection with the given range. @@ -297,7 +297,7 @@ public function except($keys); * @param (callable(TValue): bool)|null $callback * @return static */ - public function filter(callable $callback = null); + public function filter(?callable $callback = null); /** * Apply the callback if the given "value" is (or resolves to) truthy. @@ -309,7 +309,7 @@ public function filter(callable $callback = null); * @param (callable($this): TWhenReturnType)|null $default * @return $this|TWhenReturnType */ - public function when($value, callable $callback = null, callable $default = null); + public function when($value, ?callable $callback = null, ?callable $default = null); /** * Apply the callback if the collection is empty. @@ -320,7 +320,7 @@ public function when($value, callable $callback = null, callable $default = null * @param (callable($this): TWhenEmptyReturnType)|null $default * @return $this|TWhenEmptyReturnType */ - public function whenEmpty(callable $callback, callable $default = null); + public function whenEmpty(callable $callback, ?callable $default = null); /** * Apply the callback if the collection is not empty. @@ -331,7 +331,7 @@ public function whenEmpty(callable $callback, callable $default = null); * @param (callable($this): TWhenNotEmptyReturnType)|null $default * @return $this|TWhenNotEmptyReturnType */ - public function whenNotEmpty(callable $callback, callable $default = null); + public function whenNotEmpty(callable $callback, ?callable $default = null); /** * Apply the callback if the given "value" is (or resolves to) truthy. @@ -343,7 +343,7 @@ public function whenNotEmpty(callable $callback, callable $default = null); * @param (callable($this): TUnlessReturnType)|null $default * @return $this|TUnlessReturnType */ - public function unless($value, callable $callback, callable $default = null); + public function unless($value, callable $callback, ?callable $default = null); /** * Apply the callback unless the collection is empty. @@ -354,7 +354,7 @@ public function unless($value, callable $callback, callable $default = null); * @param (callable($this): TUnlessEmptyReturnType)|null $default * @return $this|TUnlessEmptyReturnType */ - public function unlessEmpty(callable $callback, callable $default = null); + public function unlessEmpty(callable $callback, ?callable $default = null); /** * Apply the callback unless the collection is not empty. @@ -365,7 +365,7 @@ public function unlessEmpty(callable $callback, callable $default = null); * @param (callable($this): TUnlessNotEmptyReturnType)|null $default * @return $this|TUnlessNotEmptyReturnType */ - public function unlessNotEmpty(callable $callback, callable $default = null); + public function unlessNotEmpty(callable $callback, ?callable $default = null); /** * Filter items by the given key value pair. @@ -477,7 +477,7 @@ public function whereInstanceOf($type); * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ - public function first(callable $callback = null, $default = null); + public function first(?callable $callback = null, $default = null); /** * Get the first item by the given key value pair. @@ -645,7 +645,7 @@ public function keys(); * @param TLastDefault|(\Closure(): TLastDefault) $default * @return TValue|TLastDefault */ - public function last(callable $callback = null, $default = null); + public function last(?callable $callback = null, $default = null); /** * Run a map over each of the items. diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 9387c86ec6b2..2debb010abda 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -428,7 +428,7 @@ public function except($keys) * @param (callable(TValue, TKey): bool)|null $callback * @return static */ - public function filter(callable $callback = null) + public function filter(?callable $callback = null) { if (is_null($callback)) { $callback = fn ($value) => (bool) $value; @@ -452,7 +452,7 @@ public function filter(callable $callback = null) * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ - public function first(callable $callback = null, $default = null) + public function first(?callable $callback = null, $default = null) { $iterator = $this->getIterator(); @@ -732,7 +732,7 @@ public function keys() * @param TLastDefault|(\Closure(): TLastDefault) $default * @return TValue|TLastDefault */ - public function last(callable $callback = null, $default = null) + public function last(?callable $callback = null, $default = null) { $needle = $placeholder = new stdClass; diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 39d14ebdde0a..041f80c080a7 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -163,7 +163,7 @@ public static function empty() * @param (callable(int): TTimesValue)|null $callback * @return static */ - public static function times($number, callable $callback = null) + public static function times($number, ?callable $callback = null) { if ($number < 1) { return new static; @@ -530,7 +530,7 @@ public function sum($callback = null) * @param (callable($this): TWhenEmptyReturnType)|null $default * @return $this|TWhenEmptyReturnType */ - public function whenEmpty(callable $callback, callable $default = null) + public function whenEmpty(callable $callback, ?callable $default = null) { return $this->when($this->isEmpty(), $callback, $default); } @@ -544,7 +544,7 @@ public function whenEmpty(callable $callback, callable $default = null) * @param (callable($this): TWhenNotEmptyReturnType)|null $default * @return $this|TWhenNotEmptyReturnType */ - public function whenNotEmpty(callable $callback, callable $default = null) + public function whenNotEmpty(callable $callback, ?callable $default = null) { return $this->when($this->isNotEmpty(), $callback, $default); } @@ -558,7 +558,7 @@ public function whenNotEmpty(callable $callback, callable $default = null) * @param (callable($this): TUnlessEmptyReturnType)|null $default * @return $this|TUnlessEmptyReturnType */ - public function unlessEmpty(callable $callback, callable $default = null) + public function unlessEmpty(callable $callback, ?callable $default = null) { return $this->whenNotEmpty($callback, $default); } @@ -572,7 +572,7 @@ public function unlessEmpty(callable $callback, callable $default = null) * @param (callable($this): TUnlessNotEmptyReturnType)|null $default * @return $this|TUnlessNotEmptyReturnType */ - public function unlessNotEmpty(callable $callback, callable $default = null) + public function unlessNotEmpty(callable $callback, ?callable $default = null) { return $this->whenEmpty($callback, $default); } diff --git a/src/Illuminate/Conditionable/Traits/Conditionable.php b/src/Illuminate/Conditionable/Traits/Conditionable.php index 19307437cbaa..5e3194bbcb6a 100644 --- a/src/Illuminate/Conditionable/Traits/Conditionable.php +++ b/src/Illuminate/Conditionable/Traits/Conditionable.php @@ -18,7 +18,7 @@ trait Conditionable * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default * @return $this|TWhenReturnType */ - public function when($value = null, callable $callback = null, callable $default = null) + public function when($value = null, ?callable $callback = null, ?callable $default = null) { $value = $value instanceof Closure ? $value($this) : $value; @@ -50,7 +50,7 @@ public function when($value = null, callable $callback = null, callable $default * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default * @return $this|TUnlessReturnType */ - public function unless($value = null, callable $callback = null, callable $default = null) + public function unless($value = null, ?callable $callback = null, ?callable $default = null) { $value = $value instanceof Closure ? $value($this) : $value; diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 5ffab77ee511..b854c5162e53 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -1140,7 +1140,7 @@ protected function unresolvablePrimitive(ReflectionParameter $parameter) * @param \Closure|null $callback * @return void */ - public function beforeResolving($abstract, Closure $callback = null) + public function beforeResolving($abstract, ?Closure $callback = null) { if (is_string($abstract)) { $abstract = $this->getAlias($abstract); @@ -1160,7 +1160,7 @@ public function beforeResolving($abstract, Closure $callback = null) * @param \Closure|null $callback * @return void */ - public function resolving($abstract, Closure $callback = null) + public function resolving($abstract, ?Closure $callback = null) { if (is_string($abstract)) { $abstract = $this->getAlias($abstract); @@ -1180,7 +1180,7 @@ public function resolving($abstract, Closure $callback = null) * @param \Closure|null $callback * @return void */ - public function afterResolving($abstract, Closure $callback = null) + public function afterResolving($abstract, ?Closure $callback = null) { if (is_string($abstract)) { $abstract = $this->getAlias($abstract); @@ -1419,7 +1419,7 @@ public static function getInstance() * @param \Illuminate\Contracts\Container\Container|null $container * @return \Illuminate\Contracts\Container\Container|static */ - public static function setInstance(ContainerContract $container = null) + public static function setInstance(?ContainerContract $container = null) { return static::$instance = $container; } diff --git a/src/Illuminate/Contracts/Auth/Access/Gate.php b/src/Illuminate/Contracts/Auth/Access/Gate.php index eb605d8279fd..4bafab3f4dc5 100644 --- a/src/Illuminate/Contracts/Auth/Access/Gate.php +++ b/src/Illuminate/Contracts/Auth/Access/Gate.php @@ -29,7 +29,7 @@ public function define($ability, $callback); * @param array|null $abilities * @return $this */ - public function resource($name, $class, array $abilities = null); + public function resource($name, $class, ?array $abilities = null); /** * Define a policy class for a given class type. diff --git a/src/Illuminate/Contracts/Auth/PasswordBroker.php b/src/Illuminate/Contracts/Auth/PasswordBroker.php index bbbe9b508688..c6b202329e39 100644 --- a/src/Illuminate/Contracts/Auth/PasswordBroker.php +++ b/src/Illuminate/Contracts/Auth/PasswordBroker.php @@ -48,7 +48,7 @@ interface PasswordBroker * @param \Closure|null $callback * @return string */ - public function sendResetLink(array $credentials, Closure $callback = null); + public function sendResetLink(array $credentials, ?Closure $callback = null); /** * Reset the password for the given token. diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index 1472a2e5fc71..47c5f8b55278 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -197,7 +197,7 @@ public function resolved($abstract); * @param \Closure|null $callback * @return void */ - public function beforeResolving($abstract, Closure $callback = null); + public function beforeResolving($abstract, ?Closure $callback = null); /** * Register a new resolving callback. @@ -206,7 +206,7 @@ public function beforeResolving($abstract, Closure $callback = null); * @param \Closure|null $callback * @return void */ - public function resolving($abstract, Closure $callback = null); + public function resolving($abstract, ?Closure $callback = null); /** * Register a new after resolving callback. @@ -215,5 +215,5 @@ public function resolving($abstract, Closure $callback = null); * @param \Closure|null $callback * @return void */ - public function afterResolving($abstract, Closure $callback = null); + public function afterResolving($abstract, ?Closure $callback = null); } diff --git a/src/Illuminate/Contracts/Notifications/Dispatcher.php b/src/Illuminate/Contracts/Notifications/Dispatcher.php index 35ea6b6aca70..17f58be02eb5 100644 --- a/src/Illuminate/Contracts/Notifications/Dispatcher.php +++ b/src/Illuminate/Contracts/Notifications/Dispatcher.php @@ -21,5 +21,5 @@ public function send($notifiables, $notification); * @param array|null $channels * @return void */ - public function sendNow($notifiables, $notification, array $channels = null); + public function sendNow($notifiables, $notification, ?array $channels = null); } diff --git a/src/Illuminate/Contracts/Process/InvokedProcess.php b/src/Illuminate/Contracts/Process/InvokedProcess.php index d272d377296b..87a92c047704 100644 --- a/src/Illuminate/Contracts/Process/InvokedProcess.php +++ b/src/Illuminate/Contracts/Process/InvokedProcess.php @@ -60,5 +60,5 @@ public function latestErrorOutput(); * @param callable|null $output * @return \Illuminate\Console\Process\ProcessResult */ - public function wait(callable $output = null); + public function wait(?callable $output = null); } diff --git a/src/Illuminate/Contracts/Process/ProcessResult.php b/src/Illuminate/Contracts/Process/ProcessResult.php index bb21ecd8902e..5f0d651543ef 100644 --- a/src/Illuminate/Contracts/Process/ProcessResult.php +++ b/src/Illuminate/Contracts/Process/ProcessResult.php @@ -68,7 +68,7 @@ public function seeInErrorOutput(string $output); * @param callable|null $callback * @return $this */ - public function throw(callable $callback = null); + public function throw(?callable $callback = null); /** * Throw an exception if the process failed and the given condition is true. @@ -77,5 +77,5 @@ public function throw(callable $callback = null); * @param callable|null $callback * @return $this */ - public function throwIf(bool $condition, callable $callback = null); + public function throwIf(bool $condition, ?callable $callback = null); } diff --git a/src/Illuminate/Database/Capsule/Manager.php b/src/Illuminate/Database/Capsule/Manager.php index b877e7c6d20d..cfc47eb5abcf 100755 --- a/src/Illuminate/Database/Capsule/Manager.php +++ b/src/Illuminate/Database/Capsule/Manager.php @@ -27,7 +27,7 @@ class Manager * @param \Illuminate\Container\Container|null $container * @return void */ - public function __construct(Container $container = null) + public function __construct(?Container $container = null) { $this->setupContainer($container ?: new Container); diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 7fd229f1624a..bcc3d73a0065 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -202,7 +202,7 @@ public function withoutGlobalScope($scope) * @param array|null $scopes * @return $this */ - public function withoutGlobalScopes(array $scopes = null) + public function withoutGlobalScopes(?array $scopes = null) { if (! is_array($scopes)) { $scopes = array_keys($this->scopes); @@ -524,7 +524,7 @@ public function findOrNew($id, $columns = ['*']) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static[]|static|mixed */ - public function findOr($id, $columns = ['*'], Closure $callback = null) + public function findOr($id, $columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; @@ -627,7 +627,7 @@ public function firstOrFail($columns = ['*']) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|static|mixed */ - public function firstOr($columns = ['*'], Closure $callback = null) + public function firstOr($columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; diff --git a/src/Illuminate/Database/Eloquent/Casts/Attribute.php b/src/Illuminate/Database/Eloquent/Casts/Attribute.php index 3f9fd19e2bd7..4fe2d807b690 100644 --- a/src/Illuminate/Database/Eloquent/Casts/Attribute.php +++ b/src/Illuminate/Database/Eloquent/Casts/Attribute.php @@ -39,7 +39,7 @@ class Attribute * @param callable|null $set * @return void */ - public function __construct(callable $get = null, callable $set = null) + public function __construct(?callable $get = null, ?callable $set = null) { $this->get = $get; $this->set = $set; @@ -52,7 +52,7 @@ public function __construct(callable $get = null, callable $set = null) * @param callable|null $set * @return static */ - public static function make(callable $get = null, callable $set = null): static + public static function make(?callable $get = null, ?callable $set = null): static { return new static($get, $set); } diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index de43f9839824..4322327cb472 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -29,7 +29,7 @@ trait QueriesRelationships * * @throws \RuntimeException */ - public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null) + public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null) { if (is_string($relation)) { if (str_contains($relation, '.')) { @@ -122,7 +122,7 @@ public function orHas($relation, $operator = '>=', $count = 1) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function doesntHave($relation, $boolean = 'and', Closure $callback = null) + public function doesntHave($relation, $boolean = 'and', ?Closure $callback = null) { return $this->has($relation, '<', 1, $boolean, $callback); } @@ -147,7 +147,7 @@ public function orDoesntHave($relation) * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ - public function whereHas($relation, Closure $callback = null, $operator = '>=', $count = 1) + public function whereHas($relation, ?Closure $callback = null, $operator = '>=', $count = 1) { return $this->has($relation, $operator, $count, 'and', $callback); } @@ -163,7 +163,7 @@ public function whereHas($relation, Closure $callback = null, $operator = '>=', * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ - public function withWhereHas($relation, Closure $callback = null, $operator = '>=', $count = 1) + public function withWhereHas($relation, ?Closure $callback = null, $operator = '>=', $count = 1) { return $this->whereHas(Str::before($relation, ':'), $callback, $operator, $count) ->with($callback ? [$relation => fn ($query) => $callback($query)] : $relation); @@ -178,7 +178,7 @@ public function withWhereHas($relation, Closure $callback = null, $operator = '> * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ - public function orWhereHas($relation, Closure $callback = null, $operator = '>=', $count = 1) + public function orWhereHas($relation, ?Closure $callback = null, $operator = '>=', $count = 1) { return $this->has($relation, $operator, $count, 'or', $callback); } @@ -190,7 +190,7 @@ public function orWhereHas($relation, Closure $callback = null, $operator = '>=' * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function whereDoesntHave($relation, Closure $callback = null) + public function whereDoesntHave($relation, ?Closure $callback = null) { return $this->doesntHave($relation, 'and', $callback); } @@ -202,7 +202,7 @@ public function whereDoesntHave($relation, Closure $callback = null) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function orWhereDoesntHave($relation, Closure $callback = null) + public function orWhereDoesntHave($relation, ?Closure $callback = null) { return $this->doesntHave($relation, 'or', $callback); } @@ -218,7 +218,7 @@ public function orWhereDoesntHave($relation, Closure $callback = null) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null) + public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null) { if (is_string($relation)) { $relation = $this->getRelationWithoutConstraints($relation); @@ -301,7 +301,7 @@ public function orHasMorph($relation, $types, $operator = '>=', $count = 1) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function doesntHaveMorph($relation, $types, $boolean = 'and', Closure $callback = null) + public function doesntHaveMorph($relation, $types, $boolean = 'and', ?Closure $callback = null) { return $this->hasMorph($relation, $types, '<', 1, $boolean, $callback); } @@ -328,7 +328,7 @@ public function orDoesntHaveMorph($relation, $types) * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ - public function whereHasMorph($relation, $types, Closure $callback = null, $operator = '>=', $count = 1) + public function whereHasMorph($relation, $types, ?Closure $callback = null, $operator = '>=', $count = 1) { return $this->hasMorph($relation, $types, $operator, $count, 'and', $callback); } @@ -343,7 +343,7 @@ public function whereHasMorph($relation, $types, Closure $callback = null, $oper * @param int $count * @return \Illuminate\Database\Eloquent\Builder|static */ - public function orWhereHasMorph($relation, $types, Closure $callback = null, $operator = '>=', $count = 1) + public function orWhereHasMorph($relation, $types, ?Closure $callback = null, $operator = '>=', $count = 1) { return $this->hasMorph($relation, $types, $operator, $count, 'or', $callback); } @@ -356,7 +356,7 @@ public function orWhereHasMorph($relation, $types, Closure $callback = null, $op * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function whereDoesntHaveMorph($relation, $types, Closure $callback = null) + public function whereDoesntHaveMorph($relation, $types, ?Closure $callback = null) { return $this->doesntHaveMorph($relation, $types, 'and', $callback); } @@ -369,7 +369,7 @@ public function whereDoesntHaveMorph($relation, $types, Closure $callback = null * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Builder|static */ - public function orWhereDoesntHaveMorph($relation, $types, Closure $callback = null) + public function orWhereDoesntHaveMorph($relation, $types, ?Closure $callback = null) { return $this->doesntHaveMorph($relation, $types, 'or', $callback); } diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index d93193e12536..85a71966cce0 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1722,7 +1722,7 @@ public function refresh() * @param array|null $except * @return static */ - public function replicate(array $except = null) + public function replicate(?array $except = null) { $defaults = array_values(array_filter([ $this->getKeyName(), @@ -1750,7 +1750,7 @@ public function replicate(array $except = null) * @param array|null $except * @return static */ - public function replicateQuietly(array $except = null) + public function replicateQuietly(?array $except = null) { return static::withoutEvents(fn () => $this->replicate($except)); } diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index a030b059a60b..70290c4da557 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -754,7 +754,7 @@ public function findOrFail($id, $columns = ['*']) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|mixed */ - public function findOr($id, $columns = ['*'], Closure $callback = null) + public function findOr($id, $columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; @@ -828,7 +828,7 @@ public function firstOrFail($columns = ['*']) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|static|mixed */ - public function firstOr($columns = ['*'], Closure $callback = null) + public function firstOr($columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 55f9aacd1e2c..cf94493c8142 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -123,7 +123,7 @@ public function addConstraints() * @param \Illuminate\Database\Eloquent\Builder|null $query * @return void */ - protected function performJoin(Builder $query = null) + protected function performJoin(?Builder $query = null) { $query = $query ?: $this->query; @@ -364,7 +364,7 @@ public function firstOrFail($columns = ['*']) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|static|mixed */ - public function firstOr($columns = ['*'], Closure $callback = null) + public function firstOr($columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; @@ -451,7 +451,7 @@ public function findOrFail($id, $columns = ['*']) * @param \Closure|null $callback * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|mixed */ - public function findOr($id, $columns = ['*'], Closure $callback = null) + public function findOr($id, $columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 7fea6b70d95b..b5e8864f0937 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -461,7 +461,7 @@ public static function enforceMorphMap(array $map, $merge = true) * @param bool $merge * @return array */ - public static function morphMap(array $map = null, $merge = true) + public static function morphMap(?array $map = null, $merge = true) { $map = static::buildMorphMapFromModels($map); @@ -479,7 +479,7 @@ public static function morphMap(array $map = null, $merge = true) * @param string[]|null $models * @return array|null */ - protected static function buildMorphMapFromModels(array $models = null) + protected static function buildMorphMapFromModels(?array $models = null) { if (is_null($models) || ! array_is_list($models)) { return $models; diff --git a/src/Illuminate/Database/MariaDbConnection.php b/src/Illuminate/Database/MariaDbConnection.php index 58e124d50c10..721641b66c1c 100755 --- a/src/Illuminate/Database/MariaDbConnection.php +++ b/src/Illuminate/Database/MariaDbConnection.php @@ -77,7 +77,7 @@ protected function getDefaultSchemaGrammar() * @param callable|null $processFactory * @return \Illuminate\Database\Schema\MariaDbSchemaState */ - public function getSchemaState(Filesystem $files = null, callable $processFactory = null) + public function getSchemaState(?Filesystem $files = null, ?callable $processFactory = null) { return new MariaDbSchemaState($this, $files, $processFactory); } diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index e650959419f9..c7391a8d6ae3 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -90,7 +90,7 @@ class Migrator public function __construct(MigrationRepositoryInterface $repository, Resolver $resolver, Filesystem $files, - Dispatcher $dispatcher = null) + ?Dispatcher $dispatcher = null) { $this->files = $files; $this->events = $dispatcher; diff --git a/src/Illuminate/Database/MySqlConnection.php b/src/Illuminate/Database/MySqlConnection.php index 00d212e9481d..147551338fd7 100755 --- a/src/Illuminate/Database/MySqlConnection.php +++ b/src/Illuminate/Database/MySqlConnection.php @@ -105,7 +105,7 @@ protected function getDefaultSchemaGrammar() * @param callable|null $processFactory * @return \Illuminate\Database\Schema\MySqlSchemaState */ - public function getSchemaState(Filesystem $files = null, callable $processFactory = null) + public function getSchemaState(?Filesystem $files = null, ?callable $processFactory = null) { return new MySqlSchemaState($this, $files, $processFactory); } diff --git a/src/Illuminate/Database/PostgresConnection.php b/src/Illuminate/Database/PostgresConnection.php index ac7aefb937ea..8f1d098907c2 100755 --- a/src/Illuminate/Database/PostgresConnection.php +++ b/src/Illuminate/Database/PostgresConnection.php @@ -92,7 +92,7 @@ protected function getDefaultSchemaGrammar() * @param callable|null $processFactory * @return \Illuminate\Database\Schema\PostgresSchemaState */ - public function getSchemaState(Filesystem $files = null, callable $processFactory = null) + public function getSchemaState(?Filesystem $files = null, ?callable $processFactory = null) { return new PostgresSchemaState($this, $files, $processFactory); } diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0a407d8f2184..1061dd075099 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -247,8 +247,8 @@ class Builder implements BuilderContract * @return void */ public function __construct(ConnectionInterface $connection, - Grammar $grammar = null, - Processor $processor = null) + ?Grammar $grammar = null, + ?Processor $processor = null) { $this->connection = $connection; $this->grammar = $grammar ?: $connection->getQueryGrammar(); @@ -2814,7 +2814,7 @@ public function find($id, $columns = ['*']) * @param \Closure|null $callback * @return mixed|static */ - public function findOr($id, $columns = ['*'], Closure $callback = null) + public function findOr($id, $columns = ['*'], ?Closure $callback = null) { if ($columns instanceof Closure) { $callback = $columns; diff --git a/src/Illuminate/Database/SQLiteConnection.php b/src/Illuminate/Database/SQLiteConnection.php index 536fca3164b9..07ca896e7ebf 100755 --- a/src/Illuminate/Database/SQLiteConnection.php +++ b/src/Illuminate/Database/SQLiteConnection.php @@ -114,7 +114,7 @@ protected function getDefaultSchemaGrammar() * * @throws \RuntimeException */ - public function getSchemaState(Filesystem $files = null, callable $processFactory = null) + public function getSchemaState(?Filesystem $files = null, ?callable $processFactory = null) { return new SqliteSchemaState($this, $files, $processFactory); } diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index c7f55eee23f5..1de396db26d6 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -86,7 +86,7 @@ class Blueprint * @param string $prefix * @return void */ - public function __construct($table, Closure $callback = null, $prefix = '') + public function __construct($table, ?Closure $callback = null, $prefix = '') { $this->table = $table; $this->prefix = $prefix; diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 808b791b66af..a18822da9179 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -571,7 +571,7 @@ protected function build(Blueprint $blueprint) * @param \Closure|null $callback * @return \Illuminate\Database\Schema\Blueprint */ - protected function createBlueprint($table, Closure $callback = null) + protected function createBlueprint($table, ?Closure $callback = null) { $prefix = $this->connection->getConfig('prefix_indexes') ? $this->connection->getConfig('prefix') diff --git a/src/Illuminate/Database/Schema/SchemaState.php b/src/Illuminate/Database/Schema/SchemaState.php index 58d9c3a438aa..c21f4ba762e4 100644 --- a/src/Illuminate/Database/Schema/SchemaState.php +++ b/src/Illuminate/Database/Schema/SchemaState.php @@ -51,7 +51,7 @@ abstract class SchemaState * @param callable|null $processFactory * @return void */ - public function __construct(Connection $connection, Filesystem $files = null, callable $processFactory = null) + public function __construct(Connection $connection, ?Filesystem $files = null, ?callable $processFactory = null) { $this->connection = $connection; diff --git a/src/Illuminate/Database/SqlServerConnection.php b/src/Illuminate/Database/SqlServerConnection.php index f977df57cc68..a0644bf5c75a 100755 --- a/src/Illuminate/Database/SqlServerConnection.php +++ b/src/Illuminate/Database/SqlServerConnection.php @@ -124,7 +124,7 @@ protected function getDefaultSchemaGrammar() * * @throws \RuntimeException */ - public function getSchemaState(Filesystem $files = null, callable $processFactory = null) + public function getSchemaState(?Filesystem $files = null, ?callable $processFactory = null) { throw new RuntimeException('Schema dumping is not supported when using SQL Server.'); } diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 22993c36f94f..c418fc4d06b8 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -72,7 +72,7 @@ class Dispatcher implements DispatcherContract * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ - public function __construct(ContainerContract $container = null) + public function __construct(?ContainerContract $container = null) { $this->container = $container ?: new Container; } diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index a96232ba4b3e..2d19ee562fed 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -224,7 +224,7 @@ public function __construct($basePath = null) * @param string|null $basePath * @return \Illuminate\Foundation\Configuration\ApplicationBuilder */ - public static function configure(string $basePath = null) + public static function configure(?string $basePath = null) { $basePath = match (true) { is_string($basePath) => $basePath, diff --git a/src/Illuminate/Foundation/Configuration/Middleware.php b/src/Illuminate/Foundation/Configuration/Middleware.php index cf58263d830a..7d1216d23c85 100644 --- a/src/Illuminate/Foundation/Configuration/Middleware.php +++ b/src/Illuminate/Foundation/Configuration/Middleware.php @@ -518,7 +518,7 @@ public function redirectUsersTo(callable|string $redirect) * @param callable|string $users * @return $this */ - public function redirectTo(callable|string $guests = null, callable|string $users = null) + public function redirectTo(callable|string|null $guests = null, callable|string|null $users = null) { $guests = is_string($guests) ? fn () => $guests : $guests; $users = is_string($users) ? fn () => $users : $users; @@ -612,7 +612,7 @@ public function trimStrings(array $except = []) * @param bool $subdomains * @return $this */ - public function trustHosts(array|callable $at = null, bool $subdomains = true) + public function trustHosts(array|callable|null $at = null, bool $subdomains = true) { $this->trustHosts = true; @@ -630,7 +630,7 @@ public function trustHosts(array|callable $at = null, bool $subdomains = true) * @param int|null $headers * @return $this */ - public function trustProxies(array|string $at = null, int $headers = null) + public function trustProxies(array|string|null $at = null, ?int $headers = null) { if (! is_null($at)) { TrustProxies::at($at); diff --git a/src/Illuminate/Foundation/Console/AboutCommand.php b/src/Illuminate/Foundation/Console/AboutCommand.php index 20c24e8e7c11..1a078a68f5df 100644 --- a/src/Illuminate/Foundation/Console/AboutCommand.php +++ b/src/Illuminate/Foundation/Console/AboutCommand.php @@ -232,7 +232,7 @@ protected function hasPhpFiles(string $path): bool * @param string|null $value * @return void */ - public static function add(string $section, $data, string $value = null) + public static function add(string $section, $data, ?string $value = null) { static::$customDataResolvers[] = fn () => static::addToSection($section, $data, $value); } @@ -245,7 +245,7 @@ public static function add(string $section, $data, string $value = null) * @param string|null $value * @return void */ - protected static function addToSection(string $section, $data, string $value = null) + protected static function addToSection(string $section, $data, ?string $value = null) { if (is_array($data)) { foreach ($data as $key => $value) { @@ -279,7 +279,7 @@ protected function sections() * @param (\Closure(mixed):(mixed))|null $json * @return \Closure(bool):mixed */ - public static function format($value, Closure $console = null, Closure $json = null) + public static function format($value, ?Closure $console = null, ?Closure $json = null) { return function ($isJson) use ($value, $console, $json) { if ($isJson === true && $json instanceof Closure) { diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 4824c27c1799..87a1e2048555 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -226,7 +226,7 @@ protected function failedAuthorization() * @param array|null $keys * @return \Illuminate\Support\ValidatedInput|array */ - public function safe(array $keys = null) + public function safe(?array $keys = null) { return is_array($keys) ? $this->validator->safe()->only($keys) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php index 6c517d336ebf..b4aad547cc38 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php @@ -58,7 +58,7 @@ protected function instance($abstract, $instance) * @param \Closure|null $mock * @return \Mockery\MockInterface */ - protected function mock($abstract, Closure $mock = null) + protected function mock($abstract, ?Closure $mock = null) { return $this->instance($abstract, Mockery::mock(...array_filter(func_get_args()))); } @@ -70,7 +70,7 @@ protected function mock($abstract, Closure $mock = null) * @param \Closure|null $mock * @return \Mockery\MockInterface */ - protected function partialMock($abstract, Closure $mock = null) + protected function partialMock($abstract, ?Closure $mock = null) { return $this->instance($abstract, Mockery::mock(...array_filter(func_get_args()))->makePartial()); } @@ -82,7 +82,7 @@ protected function partialMock($abstract, Closure $mock = null) * @param \Closure|null $mock * @return \Mockery\MockInterface */ - protected function spy($abstract, Closure $mock = null) + protected function spy($abstract, ?Closure $mock = null) { return $this->instance($abstract, Mockery::spy(...array_filter(func_get_args()))); } diff --git a/src/Illuminate/Foundation/Validation/ValidatesRequests.php b/src/Illuminate/Foundation/Validation/ValidatesRequests.php index bf2aecdd3986..4d7aad2a65d1 100644 --- a/src/Illuminate/Foundation/Validation/ValidatesRequests.php +++ b/src/Illuminate/Foundation/Validation/ValidatesRequests.php @@ -18,7 +18,7 @@ trait ValidatesRequests * * @throws \Illuminate\Validation\ValidationException */ - public function validateWith($validator, Request $request = null) + public function validateWith($validator, ?Request $request = null) { $request = $request ?: request(); diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 6ae3c54297bb..4f8a48a50696 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -84,7 +84,7 @@ class Factory * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher * @return void */ - public function __construct(Dispatcher $dispatcher = null) + public function __construct(?Dispatcher $dispatcher = null) { $this->dispatcher = $dispatcher; diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index ea1894557183..b1264922c419 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -222,7 +222,7 @@ class PendingRequest * @param array $middleware * @return void */ - public function __construct(Factory $factory = null, $middleware = []) + public function __construct(?Factory $factory = null, $middleware = []) { $this->factory = $factory; $this->middleware = new Collection($middleware); @@ -691,7 +691,7 @@ public function beforeSending($callback) * @param callable|null $callback * @return $this */ - public function throw(callable $callback = null) + public function throw(?callable $callback = null) { $this->throwCallback = $callback ?: fn () => null; diff --git a/src/Illuminate/Http/Client/Pool.php b/src/Illuminate/Http/Client/Pool.php index 0704df33226a..b5f00258fbab 100644 --- a/src/Illuminate/Http/Client/Pool.php +++ b/src/Illuminate/Http/Client/Pool.php @@ -36,7 +36,7 @@ class Pool * @param \Illuminate\Http\Client\Factory|null $factory * @return void */ - public function __construct(Factory $factory = null) + public function __construct(?Factory $factory = null) { $this->factory = $factory ?: new Factory(); $this->handler = Utils::chooseHandler(); diff --git a/src/Illuminate/Http/Concerns/InteractsWithInput.php b/src/Illuminate/Http/Concerns/InteractsWithInput.php index 20150719db3d..d7c40dc5773e 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithInput.php +++ b/src/Illuminate/Http/Concerns/InteractsWithInput.php @@ -122,7 +122,7 @@ public function hasAny($keys) * @param callable|null $default * @return $this|mixed */ - public function whenHas($key, callable $callback, callable $default = null) + public function whenHas($key, callable $callback, ?callable $default = null) { if ($this->has($key)) { return $callback(data_get($this->all(), $key)) ?: $this; @@ -200,7 +200,7 @@ public function anyFilled($keys) * @param callable|null $default * @return $this|mixed */ - public function whenFilled($key, callable $callback, callable $default = null) + public function whenFilled($key, callable $callback, ?callable $default = null) { if ($this->filled($key)) { return $callback(data_get($this->all(), $key)) ?: $this; @@ -234,7 +234,7 @@ public function missing($key) * @param callable|null $default * @return $this|mixed */ - public function whenMissing($key, callable $callback, callable $default = null) + public function whenMissing($key, callable $callback, ?callable $default = null) { if ($this->missing($key)) { return $callback(data_get($this->all(), $key)) ?: $this; diff --git a/src/Illuminate/Http/Exceptions/PostTooLargeException.php b/src/Illuminate/Http/Exceptions/PostTooLargeException.php index d5bbc60dc44c..560b8af411b0 100644 --- a/src/Illuminate/Http/Exceptions/PostTooLargeException.php +++ b/src/Illuminate/Http/Exceptions/PostTooLargeException.php @@ -16,7 +16,7 @@ class PostTooLargeException extends HttpException * @param int $code * @return void */ - public function __construct($message = '', Throwable $previous = null, array $headers = [], $code = 0) + public function __construct($message = '', ?Throwable $previous = null, array $headers = [], $code = 0) { parent::__construct(413, $message, $previous, $headers, $code); } diff --git a/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php b/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php index d6c6e336806a..98dc78ddbd3e 100644 --- a/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php +++ b/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php @@ -16,7 +16,7 @@ class ThrottleRequestsException extends TooManyRequestsHttpException * @param int $code * @return void */ - public function __construct($message = '', Throwable $previous = null, array $headers = [], $code = 0) + public function __construct($message = '', ?Throwable $previous = null, array $headers = [], $code = 0) { parent::__construct(null, $message, $previous, $code, $headers); } diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index 6edd57efe9a5..5c506ba6b00b 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -71,7 +71,7 @@ public function withCookies(array $cookies) * @param array|null $input * @return $this */ - public function withInput(array $input = null) + public function withInput(?array $input = null) { $this->session->flashInput($this->removeFilesFromInput( ! is_null($input) ? $input : $this->request->input() diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 4cbe95c94161..f5a351c4d915 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -501,7 +501,7 @@ public static function createFromBase(SymfonyRequest $request) * @return static */ #[\Override] - public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null): static + public function duplicate(?array $query = null, ?array $request = null, ?array $attributes = null, ?array $cookies = null, ?array $files = null, ?array $server = null): static { return parent::duplicate($query, $request, $attributes, $cookies, $this->filterFiles($files), $server); } diff --git a/src/Illuminate/Log/Logger.php b/src/Illuminate/Log/Logger.php index 1dd9ff4443ab..799228a65045 100755 --- a/src/Illuminate/Log/Logger.php +++ b/src/Illuminate/Log/Logger.php @@ -43,7 +43,7 @@ class Logger implements LoggerInterface * @param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher * @return void */ - public function __construct(LoggerInterface $logger, Dispatcher $dispatcher = null) + public function __construct(LoggerInterface $logger, ?Dispatcher $dispatcher = null) { $this->logger = $logger; $this->dispatcher = $dispatcher; diff --git a/src/Illuminate/Mail/Mailables/Address.php b/src/Illuminate/Mail/Mailables/Address.php index be54a24a7413..7a9ed2aa66cd 100644 --- a/src/Illuminate/Mail/Mailables/Address.php +++ b/src/Illuminate/Mail/Mailables/Address.php @@ -25,7 +25,7 @@ class Address * @param string|null $name * @return void */ - public function __construct(string $address, string $name = null) + public function __construct(string $address, ?string $name = null) { $this->address = $address; $this->name = $name; diff --git a/src/Illuminate/Mail/Mailables/Content.php b/src/Illuminate/Mail/Mailables/Content.php index 182b2b5b6bf1..80826243d04c 100644 --- a/src/Illuminate/Mail/Mailables/Content.php +++ b/src/Illuminate/Mail/Mailables/Content.php @@ -64,7 +64,7 @@ class Content * * @named-arguments-supported */ - public function __construct(string $view = null, string $html = null, string $text = null, $markdown = null, array $with = [], string $htmlString = null) + public function __construct(?string $view = null, ?string $html = null, ?string $text = null, $markdown = null, array $with = [], ?string $htmlString = null) { $this->view = $view; $this->html = $html; diff --git a/src/Illuminate/Mail/Mailables/Envelope.php b/src/Illuminate/Mail/Mailables/Envelope.php index c5126f5ff2e4..b41d5c07973c 100644 --- a/src/Illuminate/Mail/Mailables/Envelope.php +++ b/src/Illuminate/Mail/Mailables/Envelope.php @@ -89,7 +89,7 @@ class Envelope * * @named-arguments-supported */ - public function __construct(Address|string $from = null, $to = [], $cc = [], $bcc = [], $replyTo = [], string $subject = null, array $tags = [], array $metadata = [], Closure|array $using = []) + public function __construct(Address|string|null $from = null, $to = [], $cc = [], $bcc = [], $replyTo = [], ?string $subject = null, array $tags = [], array $metadata = [], Closure|array $using = []) { $this->from = is_string($from) ? new Address($from) : $from; $this->to = $this->normalizeAddresses($to); @@ -266,7 +266,7 @@ public function using(Closure $callback) * @param string|null $name * @return bool */ - public function isFrom(string $address, string $name = null) + public function isFrom(string $address, ?string $name = null) { if (is_null($name)) { return $this->from->address === $address; @@ -283,7 +283,7 @@ public function isFrom(string $address, string $name = null) * @param string|null $name * @return bool */ - public function hasTo(string $address, string $name = null) + public function hasTo(string $address, ?string $name = null) { return $this->hasRecipient($this->to, $address, $name); } @@ -295,7 +295,7 @@ public function hasTo(string $address, string $name = null) * @param string|null $name * @return bool */ - public function hasCc(string $address, string $name = null) + public function hasCc(string $address, ?string $name = null) { return $this->hasRecipient($this->cc, $address, $name); } @@ -307,7 +307,7 @@ public function hasCc(string $address, string $name = null) * @param string|null $name * @return bool */ - public function hasBcc(string $address, string $name = null) + public function hasBcc(string $address, ?string $name = null) { return $this->hasRecipient($this->bcc, $address, $name); } @@ -319,7 +319,7 @@ public function hasBcc(string $address, string $name = null) * @param string|null $name * @return bool */ - public function hasReplyTo(string $address, string $name = null) + public function hasReplyTo(string $address, ?string $name = null) { return $this->hasRecipient($this->replyTo, $address, $name); } diff --git a/src/Illuminate/Mail/Mailables/Headers.php b/src/Illuminate/Mail/Mailables/Headers.php index 71080873a819..160f47804be3 100644 --- a/src/Illuminate/Mail/Mailables/Headers.php +++ b/src/Illuminate/Mail/Mailables/Headers.php @@ -40,7 +40,7 @@ class Headers * * @named-arguments-supported */ - public function __construct(string $messageId = null, array $references = [], array $text = []) + public function __construct(?string $messageId = null, array $references = [], array $text = []) { $this->messageId = $messageId; $this->references = $references; diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index bb8a82069132..351d341868be 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -97,7 +97,7 @@ class Mailer implements MailerContract, MailQueueContract * @param \Illuminate\Contracts\Events\Dispatcher|null $events * @return void */ - public function __construct(string $name, Factory $views, TransportInterface $transport, Dispatcher $events = null) + public function __construct(string $name, Factory $views, TransportInterface $transport, ?Dispatcher $events = null) { $this->name = $name; $this->views = $views; diff --git a/src/Illuminate/Mail/Transport/ArrayTransport.php b/src/Illuminate/Mail/Transport/ArrayTransport.php index 36e27d1f369c..67da10780663 100644 --- a/src/Illuminate/Mail/Transport/ArrayTransport.php +++ b/src/Illuminate/Mail/Transport/ArrayTransport.php @@ -31,7 +31,7 @@ public function __construct() /** * {@inheritdoc} */ - public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage { return $this->messages[] = new SentMessage($message, $envelope ?? Envelope::create($message)); } diff --git a/src/Illuminate/Mail/Transport/LogTransport.php b/src/Illuminate/Mail/Transport/LogTransport.php index 848733700586..2dff1490fea5 100644 --- a/src/Illuminate/Mail/Transport/LogTransport.php +++ b/src/Illuminate/Mail/Transport/LogTransport.php @@ -33,7 +33,7 @@ public function __construct(LoggerInterface $logger) /** * {@inheritdoc} */ - public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage { $string = Str::of($message->toString()); diff --git a/src/Illuminate/Notifications/ChannelManager.php b/src/Illuminate/Notifications/ChannelManager.php index 8eb9c251024d..0ad7dae671a8 100644 --- a/src/Illuminate/Notifications/ChannelManager.php +++ b/src/Illuminate/Notifications/ChannelManager.php @@ -47,7 +47,7 @@ public function send($notifiables, $notification) * @param array|null $channels * @return void */ - public function sendNow($notifiables, $notification, array $channels = null) + public function sendNow($notifiables, $notification, ?array $channels = null) { (new NotificationSender( $this, $this->container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale) diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index 698d19dcb95f..f82f02279372 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -87,7 +87,7 @@ public function send($notifiables, $notification) * @param array|null $channels * @return void */ - public function sendNow($notifiables, $notification, array $channels = null) + public function sendNow($notifiables, $notification, ?array $channels = null) { $notifiables = $this->formatNotifiables($notifiables); diff --git a/src/Illuminate/Notifications/RoutesNotifications.php b/src/Illuminate/Notifications/RoutesNotifications.php index 15aa673ff137..2744f3161127 100644 --- a/src/Illuminate/Notifications/RoutesNotifications.php +++ b/src/Illuminate/Notifications/RoutesNotifications.php @@ -25,7 +25,7 @@ public function notify($instance) * @param array|null $channels * @return void */ - public function notifyNow($instance, array $channels = null) + public function notifyNow($instance, ?array $channels = null) { app(Dispatcher::class)->sendNow($this, $instance, $channels); } diff --git a/src/Illuminate/Notifications/SendQueuedNotifications.php b/src/Illuminate/Notifications/SendQueuedNotifications.php index f63d7bf9afe4..3eca3cccea90 100644 --- a/src/Illuminate/Notifications/SendQueuedNotifications.php +++ b/src/Illuminate/Notifications/SendQueuedNotifications.php @@ -73,7 +73,7 @@ class SendQueuedNotifications implements ShouldQueue * @param array|null $channels * @return void */ - public function __construct($notifiables, $notification, array $channels = null) + public function __construct($notifiables, $notification, ?array $channels = null) { $this->channels = $channels; $this->notification = $notification; diff --git a/src/Illuminate/Pipeline/Hub.php b/src/Illuminate/Pipeline/Hub.php index 91e9b3f306b8..54b380b038a1 100644 --- a/src/Illuminate/Pipeline/Hub.php +++ b/src/Illuminate/Pipeline/Hub.php @@ -28,7 +28,7 @@ class Hub implements HubContract * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ - public function __construct(Container $container = null) + public function __construct(?Container $container = null) { $this->container = $container; } diff --git a/src/Illuminate/Pipeline/Pipeline.php b/src/Illuminate/Pipeline/Pipeline.php index 0f32b6121125..ccae5189deeb 100644 --- a/src/Illuminate/Pipeline/Pipeline.php +++ b/src/Illuminate/Pipeline/Pipeline.php @@ -47,7 +47,7 @@ class Pipeline implements PipelineContract * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ - public function __construct(Container $container = null) + public function __construct(?Container $container = null) { $this->container = $container; } diff --git a/src/Illuminate/Process/Factory.php b/src/Illuminate/Process/Factory.php index 9db688237667..08fb0390c3a4 100644 --- a/src/Illuminate/Process/Factory.php +++ b/src/Illuminate/Process/Factory.php @@ -85,7 +85,7 @@ public function sequence(array $processes = []) * @param \Closure|array|null $callback * @return $this */ - public function fake(Closure|array $callback = null) + public function fake(Closure|array|null $callback = null) { $this->recording = true; diff --git a/src/Illuminate/Process/FakeInvokedProcess.php b/src/Illuminate/Process/FakeInvokedProcess.php index bc1e6521a77e..7c445a73f4ff 100644 --- a/src/Illuminate/Process/FakeInvokedProcess.php +++ b/src/Illuminate/Process/FakeInvokedProcess.php @@ -258,7 +258,7 @@ public function latestErrorOutput() * @param callable|null $output * @return \Illuminate\Contracts\Process\ProcessResult */ - public function wait(callable $output = null) + public function wait(?callable $output = null) { $this->outputHandler = $output ?: $this->outputHandler; diff --git a/src/Illuminate/Process/FakeProcessResult.php b/src/Illuminate/Process/FakeProcessResult.php index 73efc697f14e..72342b078aa9 100644 --- a/src/Illuminate/Process/FakeProcessResult.php +++ b/src/Illuminate/Process/FakeProcessResult.php @@ -175,7 +175,7 @@ public function seeInErrorOutput(string $output) * * @throws \Illuminate\Process\Exceptions\ProcessFailedException */ - public function throw(callable $callback = null) + public function throw(?callable $callback = null) { if ($this->successful()) { return $this; @@ -199,7 +199,7 @@ public function throw(callable $callback = null) * * @throws \Throwable */ - public function throwIf(bool $condition, callable $callback = null) + public function throwIf(bool $condition, ?callable $callback = null) { if ($condition) { return $this->throw($callback); diff --git a/src/Illuminate/Process/InvokedProcess.php b/src/Illuminate/Process/InvokedProcess.php index f0d3feb7bfa3..6f2a67095b0b 100644 --- a/src/Illuminate/Process/InvokedProcess.php +++ b/src/Illuminate/Process/InvokedProcess.php @@ -108,7 +108,7 @@ public function latestErrorOutput() * * @throws \Illuminate\Process\Exceptions\ProcessTimedOutException */ - public function wait(callable $output = null) + public function wait(?callable $output = null) { try { $this->process->wait($output); diff --git a/src/Illuminate/Process/PendingProcess.php b/src/Illuminate/Process/PendingProcess.php index 53ffdd130def..48a28f6b335a 100644 --- a/src/Illuminate/Process/PendingProcess.php +++ b/src/Illuminate/Process/PendingProcess.php @@ -241,7 +241,7 @@ public function options(array $options) * @throws \Illuminate\Process\Exceptions\ProcessTimedOutException * @throws \RuntimeException */ - public function run(array|string $command = null, callable $output = null) + public function run(array|string|null $command = null, ?callable $output = null) { $this->command = $command ?: $this->command; @@ -271,7 +271,7 @@ public function run(array|string $command = null, callable $output = null) * * @throws \RuntimeException */ - public function start(array|string $command = null, callable $output = null) + public function start(array|string|null $command = null, ?callable $output = null) { $this->command = $command ?: $this->command; diff --git a/src/Illuminate/Process/ProcessResult.php b/src/Illuminate/Process/ProcessResult.php index 2d17d822afa5..9bbf9c4aacc5 100644 --- a/src/Illuminate/Process/ProcessResult.php +++ b/src/Illuminate/Process/ProcessResult.php @@ -116,7 +116,7 @@ public function seeInErrorOutput(string $output) * * @throws \Illuminate\Process\Exceptions\ProcessFailedException */ - public function throw(callable $callback = null) + public function throw(?callable $callback = null) { if ($this->successful()) { return $this; @@ -140,7 +140,7 @@ public function throw(callable $callback = null) * * @throws \Throwable */ - public function throwIf(bool $condition, callable $callback = null) + public function throwIf(bool $condition, ?callable $callback = null) { if ($condition) { return $this->throw($callback); diff --git a/src/Illuminate/Queue/Capsule/Manager.php b/src/Illuminate/Queue/Capsule/Manager.php index c5ceb872666f..f6c263d17c6b 100644 --- a/src/Illuminate/Queue/Capsule/Manager.php +++ b/src/Illuminate/Queue/Capsule/Manager.php @@ -28,7 +28,7 @@ class Manager * @param \Illuminate\Container\Container|null $container * @return void */ - public function __construct(Container $container = null) + public function __construct(?Container $container = null) { $this->setupContainer($container ?: new Container); diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 2e7474f71c1e..c9f335a66467 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -111,7 +111,7 @@ public function __construct(QueueManager $manager, Dispatcher $events, ExceptionHandler $exceptions, callable $isDownForMaintenance, - callable $resetScope = null) + ?callable $resetScope = null) { $this->events = $events; $this->manager = $manager; diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index f3f99a346a75..d33b3cea660d 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -36,7 +36,7 @@ class PhpRedisConnection extends Connection implements ConnectionContract * @param array $config * @return void */ - public function __construct($client, callable $connector = null, array $config = []) + public function __construct($client, ?callable $connector = null, array $config = []) { $this->client = $client; $this->config = $config; @@ -396,7 +396,7 @@ public function sscan($key, $cursor, $options = []) * @param callable|null $callback * @return \Redis|array */ - public function pipeline(callable $callback = null) + public function pipeline(?callable $callback = null) { $pipeline = $this->client()->pipeline(); @@ -411,7 +411,7 @@ public function pipeline(callable $callback = null) * @param callable|null $callback * @return \Redis|array */ - public function transaction(callable $callback = null) + public function transaction(?callable $callback = null) { $transaction = $this->client()->multi(); diff --git a/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php b/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php index fd2bf1215af1..8ff02768297f 100644 --- a/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php +++ b/src/Illuminate/Redis/Limiters/ConcurrencyLimiterBuilder.php @@ -125,7 +125,7 @@ public function sleep($sleep) * * @throws \Illuminate\Contracts\Redis\LimiterTimeoutException */ - public function then(callable $callback, callable $failure = null) + public function then(callable $callback, ?callable $failure = null) { try { return (new ConcurrencyLimiter( diff --git a/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php b/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php index ddb321848fbf..8eedc1177c58 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiterBuilder.php @@ -125,7 +125,7 @@ public function sleep($sleep) * * @throws \Illuminate\Contracts\Redis\LimiterTimeoutException */ - public function then(callable $callback, callable $failure = null) + public function then(callable $callback, ?callable $failure = null) { try { return (new DurationLimiter( diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 4ddc0cc76c35..dac895dad212 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -140,7 +140,7 @@ class Router implements BindingRegistrar, RegistrarContract * @param \Illuminate\Container\Container|null $container * @return void */ - public function __construct(Dispatcher $events, Container $container = null) + public function __construct(Dispatcher $events, ?Container $container = null) { $this->events = $events; $this->routes = new RouteCollection; @@ -1161,7 +1161,7 @@ public function bind($key, $binder) * @param \Closure|null $callback * @return void */ - public function model($key, $class, Closure $callback = null) + public function model($key, $class, ?Closure $callback = null) { $this->bind($key, RouteBinding::forModel($this->container, $class, $callback)); } diff --git a/src/Illuminate/Session/DatabaseSessionHandler.php b/src/Illuminate/Session/DatabaseSessionHandler.php index 12aa3efe8cd1..0770c22f46e9 100644 --- a/src/Illuminate/Session/DatabaseSessionHandler.php +++ b/src/Illuminate/Session/DatabaseSessionHandler.php @@ -59,7 +59,7 @@ class DatabaseSessionHandler implements ExistenceAwareInterface, SessionHandlerI * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ - public function __construct(ConnectionInterface $connection, $table, $minutes, Container $container = null) + public function __construct(ConnectionInterface $connection, $table, $minutes, ?Container $container = null) { $this->table = $table; $this->minutes = $minutes; diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 5077cf6f5b90..f4671adef07a 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -35,7 +35,7 @@ class StartSession * @param callable|null $cacheFactoryResolver * @return void */ - public function __construct(SessionManager $manager, callable $cacheFactoryResolver = null) + public function __construct(SessionManager $manager, ?callable $cacheFactoryResolver = null) { $this->manager = $manager; $this->cacheFactoryResolver = $cacheFactoryResolver; @@ -286,7 +286,7 @@ protected function sessionConfigured() * @param array|null $config * @return bool */ - protected function sessionIsPersistent(array $config = null) + protected function sessionIsPersistent(?array $config = null) { $config = $config ?: $this->manager->getSessionConfig(); diff --git a/src/Illuminate/Session/SymfonySessionDecorator.php b/src/Illuminate/Session/SymfonySessionDecorator.php index 978816683fe7..55dde71a7cbe 100644 --- a/src/Illuminate/Session/SymfonySessionDecorator.php +++ b/src/Illuminate/Session/SymfonySessionDecorator.php @@ -71,7 +71,7 @@ public function setName(string $name): void /** * {@inheritdoc} */ - public function invalidate(int $lifetime = null): bool + public function invalidate(?int $lifetime = null): bool { $this->store->invalidate(); @@ -81,7 +81,7 @@ public function invalidate(int $lifetime = null): bool /** * {@inheritdoc} */ - public function migrate(bool $destroy = false, int $lifetime = null): bool + public function migrate(bool $destroy = false, ?int $lifetime = null): bool { $this->store->migrate($destroy); diff --git a/src/Illuminate/Support/Composer.php b/src/Illuminate/Support/Composer.php index 93da9b5eeced..ad976c0d8edf 100644 --- a/src/Illuminate/Support/Composer.php +++ b/src/Illuminate/Support/Composer.php @@ -63,7 +63,7 @@ protected function hasPackage($package) * @param string|null $composerBinary * @return bool */ - public function requirePackages(array $packages, bool $dev = false, Closure|OutputInterface $output = null, $composerBinary = null) + public function requirePackages(array $packages, bool $dev = false, Closure|OutputInterface|null $output = null, $composerBinary = null) { $command = collect([ ...$this->findComposer($composerBinary), @@ -92,7 +92,7 @@ public function requirePackages(array $packages, bool $dev = false, Closure|Outp * @param string|null $composerBinary * @return bool */ - public function removePackages(array $packages, bool $dev = false, Closure|OutputInterface $output = null, $composerBinary = null) + public function removePackages(array $packages, bool $dev = false, Closure|OutputInterface|null $output = null, $composerBinary = null) { $command = collect([ ...$this->findComposer($composerBinary), diff --git a/src/Illuminate/Support/Facades/Bus.php b/src/Illuminate/Support/Facades/Bus.php index 13fe1c9fedfc..6c22e027ea79 100644 --- a/src/Illuminate/Support/Facades/Bus.php +++ b/src/Illuminate/Support/Facades/Bus.php @@ -60,7 +60,7 @@ class Bus extends Facade * @param \Illuminate\Bus\BatchRepository|null $batchRepository * @return \Illuminate\Support\Testing\Fakes\BusFake */ - public static function fake($jobsToFake = [], BatchRepository $batchRepository = null) + public static function fake($jobsToFake = [], ?BatchRepository $batchRepository = null) { $actualDispatcher = static::isFake() ? static::getFacadeRoot()->dispatcher diff --git a/src/Illuminate/Support/Facades/Process.php b/src/Illuminate/Support/Facades/Process.php index 43b5b93a6578..4f3546d07c00 100644 --- a/src/Illuminate/Support/Facades/Process.php +++ b/src/Illuminate/Support/Facades/Process.php @@ -65,7 +65,7 @@ protected static function getFacadeAccessor() * @param \Closure|array|null $callback * @return \Illuminate\Process\Factory */ - public static function fake(Closure|array $callback = null) + public static function fake(Closure|array|null $callback = null) { return tap(static::getFacadeRoot(), function ($fake) use ($callback) { static::swap($fake->fake($callback)); diff --git a/src/Illuminate/Support/ServiceProvider.php b/src/Illuminate/Support/ServiceProvider.php index 8fa295563b4f..593366765719 100755 --- a/src/Illuminate/Support/ServiceProvider.php +++ b/src/Illuminate/Support/ServiceProvider.php @@ -485,7 +485,7 @@ public static function defaultProviders() * @param string $path * @return bool */ - public static function addProviderToBootstrapFile(string $provider, string $path = null) + public static function addProviderToBootstrapFile(string $provider, ?string $path = null) { $path ??= app()->getBootstrapProvidersPath(); diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 679e86bbb3f6..39570a4bf002 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -970,7 +970,7 @@ public static function random($length = 16) * @param callable|null $factory * @return void */ - public static function createRandomStringsUsing(callable $factory = null) + public static function createRandomStringsUsing(?callable $factory = null) { static::$randomStringFactory = $factory; } @@ -1723,7 +1723,7 @@ public static function orderedUuid() * @param callable|null $factory * @return void */ - public static function createUuidsUsing(callable $factory = null) + public static function createUuidsUsing(?callable $factory = null) { static::$uuidFactory = $factory; } @@ -1768,7 +1768,7 @@ public static function createUuidsUsingSequence(array $sequence, $whenMissing = * @param \Closure|null $callback * @return \Ramsey\Uuid\UuidInterface */ - public static function freezeUuids(Closure $callback = null) + public static function freezeUuids(?Closure $callback = null) { $uuid = Str::uuid(); @@ -1830,7 +1830,7 @@ public static function createUlidsNormally() * @param callable|null $factory * @return void */ - public static function createUlidsUsing(callable $factory = null) + public static function createUlidsUsing(?callable $factory = null) { static::$ulidFactory = $factory; } @@ -1875,7 +1875,7 @@ public static function createUlidsUsingSequence(array $sequence, $whenMissing = * @param Closure|null $callback * @return Ulid */ - public static function freezeUlids(Closure $callback = null) + public static function freezeUlids(?Closure $callback = null) { $ulid = Str::ulid(); diff --git a/src/Illuminate/Support/Testing/Fakes/BusFake.php b/src/Illuminate/Support/Testing/Fakes/BusFake.php index e62fac4b08a8..780b2929c3bf 100644 --- a/src/Illuminate/Support/Testing/Fakes/BusFake.php +++ b/src/Illuminate/Support/Testing/Fakes/BusFake.php @@ -88,7 +88,7 @@ class BusFake implements Fake, QueueingDispatcher * @param \Illuminate\Bus\BatchRepository|null $batchRepository * @return void */ - public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = [], BatchRepository $batchRepository = null) + public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = [], ?BatchRepository $batchRepository = null) { $this->dispatcher = $dispatcher; $this->jobsToFake = Arr::wrap($jobsToFake); diff --git a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php index df00c465ff3c..510a4a1acb73 100644 --- a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php +++ b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php @@ -288,7 +288,7 @@ public function send($notifiables, $notification) * @param array|null $channels * @return void */ - public function sendNow($notifiables, $notification, array $channels = null) + public function sendNow($notifiables, $notification, ?array $channels = null) { if (! $notifiables instanceof Collection && ! is_array($notifiables)) { $notifiables = [$notifiables]; diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 172291ad228a..5cf93d7a9341 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -239,7 +239,7 @@ function once(callable $callback) * @param callable|null $callback * @return mixed */ - function optional($value = null, callable $callback = null) + function optional($value = null, ?callable $callback = null) { if (is_null($callback)) { return new Optional($value); @@ -479,7 +479,7 @@ function windows_os() * @param (callable(TValue): (TReturn))|null $callback * @return ($callback is null ? TValue : TReturn) */ - function with($value, callable $callback = null) + function with($value, ?callable $callback = null) { return is_null($callback) ? $value : $callback($value); } diff --git a/src/Illuminate/Testing/AssertableJsonString.php b/src/Illuminate/Testing/AssertableJsonString.php index 12f8f47f7e33..4be1299180b3 100644 --- a/src/Illuminate/Testing/AssertableJsonString.php +++ b/src/Illuminate/Testing/AssertableJsonString.php @@ -267,7 +267,7 @@ public function assertPathCanonicalizing($path, $expect) * @param array|null $responseData * @return $this */ - public function assertStructure(array $structure = null, $responseData = null) + public function assertStructure(?array $structure = null, $responseData = null) { if (is_null($structure)) { return $this->assertSimilar($this->decoded); diff --git a/src/Illuminate/Testing/Fluent/AssertableJson.php b/src/Illuminate/Testing/Fluent/AssertableJson.php index 5fd76d9a7de3..9afc94c7fd36 100644 --- a/src/Illuminate/Testing/Fluent/AssertableJson.php +++ b/src/Illuminate/Testing/Fluent/AssertableJson.php @@ -42,7 +42,7 @@ class AssertableJson implements Arrayable * @param string|null $path * @return void */ - protected function __construct(array $props, string $path = null) + protected function __construct(array $props, ?string $path = null) { $this->path = $path; $this->props = $props; @@ -69,7 +69,7 @@ protected function dotPath(string $key = ''): string * @param string|null $key * @return mixed */ - protected function prop(string $key = null) + protected function prop(?string $key = null) { return Arr::get($this->props, $key); } diff --git a/src/Illuminate/Testing/Fluent/Concerns/Debugging.php b/src/Illuminate/Testing/Fluent/Concerns/Debugging.php index 98726fbbdbbd..70d5ab310655 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Debugging.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Debugging.php @@ -14,7 +14,7 @@ trait Debugging * @param string|null $prop * @return $this */ - public function dump(string $prop = null): self + public function dump(?string $prop = null): self { dump($this->prop($prop)); @@ -27,5 +27,5 @@ public function dump(string $prop = null): self * @param string|null $key * @return mixed */ - abstract protected function prop(string $key = null); + 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 7765f4a061a5..20bfe9d189e3 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Has.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -15,7 +15,7 @@ trait Has * @param int|null $length * @return $this */ - public function count($key, int $length = null): self + public function count($key, ?int $length = null): self { if (is_null($length)) { $path = $this->dotPath(); @@ -48,7 +48,7 @@ public function count($key, int $length = null): self * @param \Closure|null $callback * @return $this */ - public function has($key, $length = null, Closure $callback = null): self + public function has($key, $length = null, ?Closure $callback = null): self { $prop = $this->prop(); @@ -185,7 +185,7 @@ abstract protected function interactsWith(string $key): void; * @param string|null $key * @return mixed */ - abstract protected function prop(string $key = null); + abstract protected function prop(?string $key = null); /** * Instantiate a new "scope" at the path of the given key. diff --git a/src/Illuminate/Testing/Fluent/Concerns/Interaction.php b/src/Illuminate/Testing/Fluent/Concerns/Interaction.php index 15e7e9508f55..fc811fd95dd7 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Interaction.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Interaction.php @@ -63,5 +63,5 @@ public function etc(): self * @param string|null $key * @return mixed */ - abstract protected function prop(string $key = null); + 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 9ff7a31823ea..cab4cb11dd70 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -224,7 +224,7 @@ abstract protected function dotPath(string $key = ''): string; * @param \Closure|null $scope * @return $this */ - abstract public function has(string $key, $value = null, Closure $scope = null); + abstract public function has(string $key, $value = null, ?Closure $scope = null); /** * Retrieve a prop within the current scope using "dot" notation. @@ -232,5 +232,5 @@ abstract public function has(string $key, $value = null, Closure $scope = null); * @param string|null $key * @return mixed */ - abstract protected function prop(string $key = null); + abstract protected function prop(?string $key = null); } diff --git a/src/Illuminate/Testing/TestResponse.php b/src/Illuminate/Testing/TestResponse.php index 7cc4261b24e0..e111559070f7 100644 --- a/src/Illuminate/Testing/TestResponse.php +++ b/src/Illuminate/Testing/TestResponse.php @@ -810,7 +810,7 @@ public function assertJsonMissingPath(string $path) * @param array|null $responseData * @return $this */ - public function assertJsonStructure(array $structure = null, $responseData = null) + public function assertJsonStructure(?array $structure = null, $responseData = null) { $this->decodeResponseJson()->assertStructure($structure, $responseData); diff --git a/src/Illuminate/Validation/Concerns/FormatsMessages.php b/src/Illuminate/Validation/Concerns/FormatsMessages.php index 2d68828d1b3a..39b68f9c61ce 100644 --- a/src/Illuminate/Validation/Concerns/FormatsMessages.php +++ b/src/Illuminate/Validation/Concerns/FormatsMessages.php @@ -361,7 +361,7 @@ protected function replacePositionPlaceholder($message, $attribute) * @param \Closure|null $modifier * @return string */ - protected function replaceIndexOrPositionPlaceholder($message, $attribute, $placeholder, Closure $modifier = null) + protected function replaceIndexOrPositionPlaceholder($message, $attribute, $placeholder, ?Closure $modifier = null) { $segments = explode('.', $attribute); diff --git a/src/Illuminate/Validation/Factory.php b/src/Illuminate/Validation/Factory.php index fcb669e176f6..6ebfcac50d2d 100755 --- a/src/Illuminate/Validation/Factory.php +++ b/src/Illuminate/Validation/Factory.php @@ -87,7 +87,7 @@ class Factory implements FactoryContract * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ - public function __construct(Translator $translator, Container $container = null) + public function __construct(Translator $translator, ?Container $container = null) { $this->container = $container; $this->translator = $translator; diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index c8ff4c6e912f..838cd2ebceb8 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -561,7 +561,7 @@ public function validateWithBag(string $errorBag) * @param array|null $keys * @return \Illuminate\Support\ValidatedInput|array */ - public function safe(array $keys = null) + public function safe(?array $keys = null) { return is_array($keys) ? (new ValidatedInput($this->validated()))->only($keys) @@ -1432,7 +1432,7 @@ public function addCustomAttributes(array $attributes) * @param callable|null $formatter * @return $this */ - public function setImplicitAttributesFormatter(callable $formatter = null) + public function setImplicitAttributesFormatter(?callable $formatter = null) { $this->implicitAttributesFormatter = $formatter; diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index c006bbd0f5c2..a7bb59e2bc51 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -808,7 +808,7 @@ public function getClassComponentAliases() * @param string|null $prefix * @return void */ - public function anonymousComponentPath(string $path, string $prefix = null) + public function anonymousComponentPath(string $path, ?string $prefix = null) { $prefixHash = md5($prefix ?: $path); @@ -830,7 +830,7 @@ public function anonymousComponentPath(string $path, string $prefix = null) * @param string|null $prefix * @return void */ - public function anonymousComponentNamespace(string $directory, string $prefix = null) + public function anonymousComponentNamespace(string $directory, ?string $prefix = null) { $prefix ??= $directory; diff --git a/src/Illuminate/View/Engines/CompilerEngine.php b/src/Illuminate/View/Engines/CompilerEngine.php index 95197953c868..82953f1dc8e5 100755 --- a/src/Illuminate/View/Engines/CompilerEngine.php +++ b/src/Illuminate/View/Engines/CompilerEngine.php @@ -40,7 +40,7 @@ class CompilerEngine extends PhpEngine * @param \Illuminate\Filesystem\Filesystem|null $files * @return void */ - public function __construct(CompilerInterface $compiler, Filesystem $files = null) + public function __construct(CompilerInterface $compiler, ?Filesystem $files = null) { parent::__construct($files ?: new Filesystem); diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 5502fe5ae870..107bf7c36bdc 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -50,7 +50,7 @@ class FileViewFinder implements ViewFinderInterface * @param array|null $extensions * @return void */ - public function __construct(Filesystem $files, array $paths, array $extensions = null) + public function __construct(Filesystem $files, array $paths, ?array $extensions = null) { $this->files = $files; $this->paths = array_map([$this, 'resolvePath'], $paths); diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php index 597fb1ec0d0b..0751a8dff5ba 100755 --- a/src/Illuminate/View/View.php +++ b/src/Illuminate/View/View.php @@ -154,7 +154,7 @@ protected function allFragments() * * @throws \Throwable */ - public function render(callable $callback = null) + public function render(?callable $callback = null) { try { $contents = $this->renderContents(); diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 8c2f617c1fff..717c09aeb751 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -785,7 +785,7 @@ public function testAllowIfAuthorizesCallbackResponseAllowed() public function testAllowsIfCallbackAcceptsGuestsWhenAuthenticated() { - $response = $this->getBasicGate()->allowIf(function (stdClass $user = null) { + $response = $this->getBasicGate()->allowIf(function (?stdClass $user = null) { return $user !== null; }); @@ -796,7 +796,7 @@ public function testAllowIfCallbackAcceptsGuestsWhenUnauthenticated() { $gate = $this->getBasicGate()->forUser(null); - $response = $gate->allowIf(function (stdClass $user = null) { + $response = $gate->allowIf(function (?stdClass $user = null) { return $user === null; }); @@ -923,7 +923,7 @@ public function testDenyIfAuthorizesCallbackResponseAllowed() public function testDenyIfCallbackAcceptsGuestsWhenAuthenticated() { - $response = $this->getBasicGate()->denyIf(function (stdClass $user = null) { + $response = $this->getBasicGate()->denyIf(function (?stdClass $user = null) { return $user === null; }); @@ -934,7 +934,7 @@ public function testDenyIfCallbackAcceptsGuestsWhenUnauthenticated() { $gate = $this->getBasicGate()->forUser(null); - $response = $gate->denyIf(function (stdClass $user = null) { + $response = $gate->denyIf(function (?stdClass $user = null) { return $user !== null; }); diff --git a/tests/Container/ContainerResolveNonInstantiableTest.php b/tests/Container/ContainerResolveNonInstantiableTest.php index 28f8f18fc923..5d568cb10e8e 100644 --- a/tests/Container/ContainerResolveNonInstantiableTest.php +++ b/tests/Container/ContainerResolveNonInstantiableTest.php @@ -44,7 +44,7 @@ class ParentClass */ public $i; - public function __construct(TestInterface $testObject = null, int $i = 0) + public function __construct(?TestInterface $testObject = null, int $i = 0) { $this->i = $i; } diff --git a/tests/Container/ContextualBindingTest.php b/tests/Container/ContextualBindingTest.php index 4c8efa496c9b..4313b25900a1 100644 --- a/tests/Container/ContextualBindingTest.php +++ b/tests/Container/ContextualBindingTest.php @@ -579,7 +579,7 @@ class ContainerTestContextWithOptionalInnerDependency { public $inner; - public function __construct(ContainerTestContextInjectOne $inner = null) + public function __construct(?ContainerTestContextInjectOne $inner = null) { $this->inner = $inner; } diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index d75f92be6dd9..3811b6fd350f 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -1874,7 +1874,7 @@ public function testImplicitBindingsWithOptionalParameterWithExistingKeyInUri() $router = $this->getRouter(); $router->get('foo/{bar?}', [ 'middleware' => SubstituteBindings::class, - 'uses' => function (RoutingTestUserModel $bar = null) { + 'uses' => function (?RoutingTestUserModel $bar = null) { $this->assertInstanceOf(RoutingTestUserModel::class, $bar); return $bar->value; @@ -1888,7 +1888,7 @@ public function testImplicitBindingsWithMissingModelHandledByMissing() $router = $this->getRouter(); $router->get('foo/{bar}', [ 'middleware' => SubstituteBindings::class, - 'uses' => function (RouteModelBindingNullStub $bar = null) { + 'uses' => function (?RouteModelBindingNullStub $bar = null) { $this->assertInstanceOf(RouteModelBindingNullStub::class, $bar); return $bar->first(); @@ -1912,7 +1912,7 @@ public function testImplicitBindingsWithMissingModelHandledByMissingOnGroupLevel ->group(function () use ($router) { $router->get('foo/{bar}', [ 'middleware' => SubstituteBindings::class, - 'uses' => function (RouteModelBindingNullStub $bar = null) { + 'uses' => function (?RouteModelBindingNullStub $bar = null) { $this->assertInstanceOf(RouteModelBindingNullStub::class, $bar); return $bar->first(); @@ -1932,7 +1932,7 @@ public function testImplicitBindingsWithOptionalParameterWithNoKeyInUri() $router = $this->getRouter(); $router->get('foo/{bar?}', [ 'middleware' => SubstituteBindings::class, - 'uses' => function (RoutingTestUserModel $bar = null) { + 'uses' => function (?RoutingTestUserModel $bar = null) { $this->assertNull($bar); }, ]); @@ -1960,7 +1960,7 @@ public function testImplicitBindingsWithOptionalParameterWithNonExistingKeyInUri $router = $this->getRouter(); $router->get('foo/{bar?}', [ 'middleware' => SubstituteBindings::class, - 'uses' => function (RoutingTestNonExistingUserModel $bar = null) { + 'uses' => function (?RoutingTestNonExistingUserModel $bar = null) { $this->fail('ModelNotFoundException was expected.'); }, ]); @@ -2338,7 +2338,7 @@ public function reversedArguments($two, $one) // } - public function withModels(Request $request, RoutingTestUserModel $user, $defaultNull = null, RoutingTestTeamModel $team = null) + public function withModels(Request $request, RoutingTestUserModel $user, $defaultNull = null, ?RoutingTestTeamModel $team = null) { // } diff --git a/tests/Support/SupportCarbonTest.php b/tests/Support/SupportCarbonTest.php index 46bf5a2a468f..6244192916fe 100644 --- a/tests/Support/SupportCarbonTest.php +++ b/tests/Support/SupportCarbonTest.php @@ -41,7 +41,7 @@ public function testInstance() public function testCarbonIsMacroableWhenNotCalledStatically() { - Carbon::macro('diffInDecades', function (Carbon $dt = null, $abs = true) { + Carbon::macro('diffInDecades', function (?Carbon $dt = null, $abs = true) { return (int) ($this->diffInYears($dt, $abs) / 10); }); diff --git a/tests/Support/SupportReflectsClosuresTest.php b/tests/Support/SupportReflectsClosuresTest.php index 0cbd1340f833..49cf3aa753de 100644 --- a/tests/Support/SupportReflectsClosuresTest.php +++ b/tests/Support/SupportReflectsClosuresTest.php @@ -23,7 +23,7 @@ public function testReflectsClosures() // }); - $this->assertParameterTypes([null, ExampleParameter::class], function ($one, ExampleParameter $two = null) { + $this->assertParameterTypes([null, ExampleParameter::class], function ($one, ?ExampleParameter $two = null) { // }); From 982c494d6c563bc42c59bff0353ae9afbf457bc1 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:09:35 +0330 Subject: [PATCH 072/123] [11.x] improvement test for repeat method (#50916) * Test: improvement test for repeat method * fix: using assertSame, fix code style , test valueError exception * test(SupportStrTest): split expectException into another test method for Str::repeat method --- tests/Support/SupportStrTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 9670e9672ef3..4d96baec5615 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -8,6 +8,7 @@ use PHPUnit\Framework\TestCase; use Ramsey\Uuid\UuidInterface; use ReflectionClass; +use ValueError; class SupportStrTest extends TestCase { @@ -1196,10 +1197,18 @@ public function testInlineMarkdown() public function testRepeat() { + $this->assertSame('', Str::repeat('Hello', 0)); + $this->assertSame('Hello', Str::repeat('Hello', 1)); $this->assertSame('aaaaa', Str::repeat('a', 5)); $this->assertSame('', Str::repeat('', 5)); } + public function testRepeatWhenTimesIsNegative() + { + $this->expectException(ValueError::class); + Str::repeat('Hello', -2); + } + #[DataProvider('specialCharacterProvider')] public function testTransliterate(string $value, string $expected): void { From 30025117b5e2a3c123fccacc204c52a0951d9fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Thu, 4 Apr 2024 19:39:55 +0200 Subject: [PATCH 073/123] [11.x] Add setters to cache stores (#50912) * Add setPrefix() to ApcStore and DatabaseStore * Add setDirectory() setter to FileStore --- src/Illuminate/Cache/ApcStore.php | 11 +++++++++++ src/Illuminate/Cache/DatabaseStore.php | 11 +++++++++++ src/Illuminate/Cache/FileStore.php | 13 +++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/Illuminate/Cache/ApcStore.php b/src/Illuminate/Cache/ApcStore.php index 5779635b203b..50e4c62adcbe 100755 --- a/src/Illuminate/Cache/ApcStore.php +++ b/src/Illuminate/Cache/ApcStore.php @@ -123,4 +123,15 @@ public function getPrefix() { return $this->prefix; } + + /** + * Set the cache key prefix. + * + * @param string $prefix + * @return void + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + } } diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index e5b72107ce96..442e6356d387 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -387,6 +387,17 @@ public function getPrefix() return $this->prefix; } + /** + * Set the cache key prefix. + * + * @param string $prefix + * @return void + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + } + /** * Serialize the given value. * diff --git a/src/Illuminate/Cache/FileStore.php b/src/Illuminate/Cache/FileStore.php index 9d5e2e95c872..5e3fba081caa 100755 --- a/src/Illuminate/Cache/FileStore.php +++ b/src/Illuminate/Cache/FileStore.php @@ -380,6 +380,19 @@ public function getDirectory() return $this->directory; } + /** + * Set the working directory of the cache. + * + * @param string $directory + * @return $this + */ + public function setDirectory($directory) + { + $this->directory = $directory; + + return $this; + } + /** * Set the cache directory where locks should be stored. * From a98a17b15871037aed16f61478c1df0b5d07d3cc Mon Sep 17 00:00:00 2001 From: "Md. Mottasin Lemon" <68915904+lmottasin@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:40:56 +0600 Subject: [PATCH 074/123] [11.x] Add some test for make:enum when Enums or Enumerations folder already exists (#50911) * feat: add test for enum make when Enums or Enumerations folder exists * wip Signed-off-by: Mior Muhammad Zaki --------- Signed-off-by: Mior Muhammad Zaki Co-authored-by: Mior Muhammad Zaki --- .../Generators/EnumMakeCommandTest.php | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/Integration/Generators/EnumMakeCommandTest.php b/tests/Integration/Generators/EnumMakeCommandTest.php index 43feaeba2da5..0aba736c80e5 100644 --- a/tests/Integration/Generators/EnumMakeCommandTest.php +++ b/tests/Integration/Generators/EnumMakeCommandTest.php @@ -6,6 +6,13 @@ class EnumMakeCommandTest extends TestCase { + protected $files = [ + 'app/IntEnum.php', + 'app/StatusEnum.php', + 'app/StringEnum.php', + 'app/*/OrderStatusEnum.php', + ]; + public function testItCanGenerateEnumFile() { $this->artisan('make:enum', ['name' => 'StatusEnum']) @@ -38,4 +45,44 @@ public function testItCanGenerateEnumFileWithInt() 'enum IntEnum: int', ], 'app/IntEnum.php'); } + + public function testItCanGenerateEnumFileInEnumsFolder() + { + $enumsFolderPath = app_path('Enums'); + + /** @var \Illuminate\Filesystem\Filesystem $files */ + $files = $this->app['files']; + + $files->ensureDirectoryExists($enumsFolderPath); + + $this->artisan('make:enum', ['name' => 'OrderStatusEnum']) + ->assertExitCode(0); + + $this->assertFileContains([ + 'namespace App\Enums;', + 'enum OrderStatusEnum', + ], 'app/Enums/OrderStatusEnum.php'); + + $files->deleteDirectory($enumsFolderPath); + } + + public function testItCanGenerateEnumFileInEnumerationsFolder() + { + $enumerationsFolderPath = app_path('Enumerations'); + + /** @var \Illuminate\Filesystem\Filesystem $files */ + $files = $this->app['files']; + + $files->ensureDirectoryExists($enumerationsFolderPath); + + $this->artisan('make:enum', ['name' => 'OrderStatusEnum']) + ->assertExitCode(0); + + $this->assertFileContains([ + 'namespace App\Enumerations;', + 'enum OrderStatusEnum', + ], 'app/Enumerations/OrderStatusEnum.php'); + + $files->deleteDirectory($enumerationsFolderPath); + } } From 2298bc341f3edcf95aa54ac03687b763414dce76 Mon Sep 17 00:00:00 2001 From: Apos Spanos <5887954+apspan@users.noreply.github.com> Date: Thu, 4 Apr 2024 20:45:10 +0300 Subject: [PATCH 075/123] [10.x] Laravel 10x optional withSize for hasTable (#50888) * make withsize optional for SQLiteBuilder's getTables * refactoring SQLiteBuilder::getTables Signed-off-by: Apos Spanos * correcting SQLiteBuilder::getTables Signed-off-by: Apos Spanos --------- Signed-off-by: Apos Spanos --- src/Illuminate/Database/Schema/Builder.php | 2 +- src/Illuminate/Database/Schema/SQLiteBuilder.php | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 51b97f690618..4a8839442951 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -162,7 +162,7 @@ public function hasTable($table) { $table = $this->connection->getTablePrefix().$table; - foreach ($this->getTables() as $value) { + foreach ($this->getTables(false) as $value) { if (strtolower($table) === strtolower($value['name'])) { return true; } diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 8ae272d767b6..e7d6e8c905eb 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -34,16 +34,17 @@ public function dropDatabaseIfExists($name) /** * Get the tables for the database. * + * @param bool $withSize * @return array */ - public function getTables() + public function getTables($withSize = true) { - $withSize = false; - - try { - $withSize = $this->connection->scalar($this->grammar->compileDbstatExists()); - } catch (QueryException $e) { - // + if ($withSize) { + try { + $withSize = $this->connection->scalar($this->grammar->compileDbstatExists()); + } catch (QueryException $e) { + $withSize = false; + } } return $this->connection->getPostProcessor()->processTables( From 29acd212d3ed95c92111318e3f37d74a5c47c9b9 Mon Sep 17 00:00:00 2001 From: macocci7 Date: Fri, 5 Apr 2024 02:53:55 +0900 Subject: [PATCH 076/123] [11.x] Fix prompting for missing array arguments on artisan command (#50850) * [11.x] Fixed prompting for missing array arguments on artisan command * fixed prompting for missing array arguments on artisan command * fixed testing failure fixed:tests/Console/ConsoleApplicationTest.php * Update src/Illuminate/Console/Concerns/PromptsForMissingInput.php Co-authored-by: Jess Archer * Maintain array type when prompting for missing array argument --------- Co-authored-by: Jess Archer --- .../Concerns/PromptsForMissingInput.php | 19 ++++++--- tests/Console/ConsoleApplicationTest.php | 41 +++++++++++++++++++ .../FakeCommandWithArrayInputPrompting.php | 33 +++++++++++++++ 3 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 tests/Console/Fixtures/FakeCommandWithArrayInputPrompting.php diff --git a/src/Illuminate/Console/Concerns/PromptsForMissingInput.php b/src/Illuminate/Console/Concerns/PromptsForMissingInput.php index 59a92d162d70..c4b5f96e0dd0 100644 --- a/src/Illuminate/Console/Concerns/PromptsForMissingInput.php +++ b/src/Illuminate/Console/Concerns/PromptsForMissingInput.php @@ -4,6 +4,8 @@ use Closure; use Illuminate\Contracts\Console\PromptsForMissingInput as PromptsForMissingInputContract; +use Illuminate\Support\Arr; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -37,25 +39,30 @@ protected function interact(InputInterface $input, OutputInterface $output) protected function promptForMissingArguments(InputInterface $input, OutputInterface $output) { $prompted = collect($this->getDefinition()->getArguments()) - ->filter(fn ($argument) => $argument->isRequired() && is_null($input->getArgument($argument->getName()))) - ->filter(fn ($argument) => $argument->getName() !== 'command') - ->each(function ($argument) use ($input) { + ->reject(fn (InputArgument $argument) => $argument->getName() === 'command') + ->filter(fn (InputArgument $argument) => $argument->isRequired() && match (true) { + $argument->isArray() => empty($input->getArgument($argument->getName())), + default => is_null($input->getArgument($argument->getName())), + }) + ->each(function (InputArgument $argument) use ($input) { $label = $this->promptForMissingArgumentsUsing()[$argument->getName()] ?? 'What is '.lcfirst($argument->getDescription() ?: ('the '.$argument->getName())).'?'; if ($label instanceof Closure) { - return $input->setArgument($argument->getName(), $label()); + return $input->setArgument($argument->getName(), $argument->isArray() ? Arr::wrap($label()) : $label()); } if (is_array($label)) { [$label, $placeholder] = $label; } - $input->setArgument($argument->getName(), text( + $answer = text( label: $label, placeholder: $placeholder ?? '', validate: fn ($value) => empty($value) ? "The {$argument->getName()} is required." : null, - )); + ); + + $input->setArgument($argument->getName(), $argument->isArray() ? [$answer] : $answer); }) ->isNotEmpty(); diff --git a/tests/Console/ConsoleApplicationTest.php b/tests/Console/ConsoleApplicationTest.php index 9edc18accf65..b3ffdf7fa9e4 100755 --- a/tests/Console/ConsoleApplicationTest.php +++ b/tests/Console/ConsoleApplicationTest.php @@ -8,6 +8,7 @@ use Illuminate\Contracts\Foundation\Application as ApplicationContract; use Illuminate\Events\Dispatcher as EventsDispatcher; use Illuminate\Foundation\Application as FoundationApplication; +use Illuminate\Tests\Console\Fixtures\FakeCommandWithArrayInputPrompting; use Illuminate\Tests\Console\Fixtures\FakeCommandWithInputPrompting; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -160,6 +161,7 @@ public function testCommandInputPromptsWhenRequiredArgumentIsMissing() $statusCode = $app->call('fake-command-for-testing'); $this->assertTrue($command->prompted); + $this->assertSame('foo', $command->argument('name')); $this->assertSame(0, $statusCode); } @@ -178,6 +180,45 @@ public function testCommandInputDoesntPromptWhenRequiredArgumentIsPassed() ]); $this->assertFalse($command->prompted); + $this->assertSame('foo', $command->argument('name')); + $this->assertSame(0, $statusCode); + } + + public function testCommandInputPromptsWhenRequiredArgumentsAreMissing() + { + $app = new Application( + $laravel = new \Illuminate\Foundation\Application(__DIR__), + $events = m::mock(Dispatcher::class, ['dispatch' => null, 'fire' => null]), + 'testing' + ); + + $app->addCommands([$command = new FakeCommandWithArrayInputPrompting()]); + + $command->setLaravel($laravel); + + $statusCode = $app->call('fake-command-for-testing-array'); + + $this->assertTrue($command->prompted); + $this->assertSame(['foo'], $command->argument('names')); + $this->assertSame(0, $statusCode); + } + + public function testCommandInputDoesntPromptWhenRequiredArgumentsArePassed() + { + $app = new Application( + $app = new \Illuminate\Foundation\Application(__DIR__), + $events = m::mock(Dispatcher::class, ['dispatch' => null, 'fire' => null]), + 'testing' + ); + + $app->addCommands([$command = new FakeCommandWithArrayInputPrompting()]); + + $statusCode = $app->call('fake-command-for-testing-array', [ + 'names' => ['foo', 'bar', 'baz'], + ]); + + $this->assertFalse($command->prompted); + $this->assertSame(['foo', 'bar', 'baz'], $command->argument('names')); $this->assertSame(0, $statusCode); } diff --git a/tests/Console/Fixtures/FakeCommandWithArrayInputPrompting.php b/tests/Console/Fixtures/FakeCommandWithArrayInputPrompting.php new file mode 100644 index 000000000000..36373eddf8da --- /dev/null +++ b/tests/Console/Fixtures/FakeCommandWithArrayInputPrompting.php @@ -0,0 +1,33 @@ +prompted = true; + + return 'foo'; + }); + } + + public function handle(): int + { + return self::SUCCESS; + } +} From e22bff095f35b3cc1be8ca1fe9d13bb2ed249680 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:42:11 +0330 Subject: [PATCH 077/123] test: improvement tests for Str::kebab method (#50926) --- tests/Support/SupportStrTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 4d96baec5615..78d970cc5091 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -533,6 +533,9 @@ public function testIsMatch() public function testKebab() { $this->assertSame('laravel-php-framework', Str::kebab('LaravelPhpFramework')); + $this->assertSame('laravel-php-framework', Str::kebab('Laravel Php Framework')); + $this->assertSame('laravel❤-php-framework', Str::kebab('Laravel ❤ Php Framework')); + $this->assertSame('', Str::kebab('')); } public function testLower() From 92beae32b64be7c89e6df71cb1f56e42cc734b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Guimar=C3=A3es?= Date: Fri, 5 Apr 2024 11:17:07 -0300 Subject: [PATCH 078/123] [11.x] Add strict-mode safe hasAttribute method to Eloquent (#50909) * add hasAttribute method * fix test --- .../Eloquent/Concerns/HasAttributes.php | 25 +++++++++++++++---- ...tBelongsToManyWithCastedAttributesTest.php | 2 ++ tests/Database/DatabaseEloquentModelTest.php | 13 ++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 94e6e95f5288..57f9e8f202a7 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -433,6 +433,25 @@ protected function getArrayableItems(array $values) return $values; } + /** + * Determine whether an attribute exists on the model. + * + * @param string $key + * @return bool + */ + public function hasAttribute($key) + { + if (! $key) { + return false; + } + + return array_key_exists($key, $this->attributes) || + array_key_exists($key, $this->casts) || + $this->hasGetMutator($key) || + $this->hasAttributeMutator($key) || + $this->isClassCastable($key); + } + /** * Get an attribute from the model. * @@ -448,11 +467,7 @@ public function getAttribute($key) // If the attribute exists in the attribute array or has a "get" mutator we will // get the attribute's value. Otherwise, we will proceed as if the developers // are asking for a relationship's value. This covers both types of values. - if (array_key_exists($key, $this->attributes) || - array_key_exists($key, $this->casts) || - $this->hasGetMutator($key) || - $this->hasAttributeMutator($key) || - $this->isClassCastable($key)) { + if ($this->hasAttribute($key)) { return $this->getAttributeValue($key); } diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php index 34f89e8c49ef..96c3e24b2a48 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -21,6 +21,7 @@ public function testModelsAreProperlyMatchedToParents() { $relation = $this->getRelation(); $model1 = m::mock(Model::class); + $model1->shouldReceive('hasAttribute')->passthru(); $model1->shouldReceive('getAttribute')->with('parent_key')->andReturn(1); $model1->shouldReceive('getAttribute')->with('foo')->passthru(); $model1->shouldReceive('hasGetMutator')->andReturn(false); @@ -29,6 +30,7 @@ public function testModelsAreProperlyMatchedToParents() $model1->shouldReceive('getRelationValue', 'relationLoaded', 'relationResolver', 'setRelation', 'isRelation')->passthru(); $model2 = m::mock(Model::class); + $model2->shouldReceive('hasAttribute')->passthru(); $model2->shouldReceive('getAttribute')->with('parent_key')->andReturn(2); $model2->shouldReceive('getAttribute')->with('foo')->passthru(); $model2->shouldReceive('hasGetMutator')->andReturn(false); diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 2b8f11eaee8e..7c5e22bd7c3e 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -3024,6 +3024,19 @@ public function testDiscardChanges() $this->assertNull($user->getOriginal('name')); $this->assertNull($user->getAttribute('name')); } + + public function testHasAttribute() + { + $user = new EloquentModelStub([ + 'name' => 'Mateus', + ]); + + $this->assertTrue($user->hasAttribute('name')); + $this->assertTrue($user->hasAttribute('password')); + $this->assertTrue($user->hasAttribute('castedFloat')); + $this->assertFalse($user->hasAttribute('nonexistent')); + $this->assertFalse($user->hasAttribute('belongsToStub')); + } } class EloquentTestObserverStub From 6315391a2152362290dad4f607225b537865fb0c Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 5 Apr 2024 14:17:33 +0000 Subject: [PATCH 079/123] Apply fixes from StyleCI --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 57f9e8f202a7..8a125ba1147d 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -436,7 +436,7 @@ protected function getArrayableItems(array $values) /** * Determine whether an attribute exists on the model. * - * @param string $key + * @param string $key * @return bool */ public function hasAttribute($key) From b2062043448923cf3c1ecae34c23df2f3442e043 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 5 Apr 2024 09:24:47 -0500 Subject: [PATCH 080/123] [11.x] add function to get faked events (#50905) * add function to get faked events this function will return an array of all Events that have been faked. this can be helpful when originally writing the tests to get a grasp of which events you may need to intercept. both the `QueueFake` and `NotificationFake` have similar methods to let you see what has been intercepted by the fake. https://github.com/laravel/framework/blob/11.x/src/Illuminate/Support/Testing/Fakes/QueueFake.php#L512 https://github.com/laravel/framework/blob/11.x/src/Illuminate/Support/Testing/Fakes/NotificationFake.php#L357 * Update EventFake.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Testing/Fakes/EventFake.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 4a4fc7c5b22d..e6b956eb8572 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -404,6 +404,16 @@ public function until($event, $payload = []) return $this->dispatch($event, $payload, true); } + /** + * Get the events that have been dispatched. + * + * @return array + */ + public function dispatchedEvents() + { + return $this->events; + } + /** * Handle dynamic method calls to the dispatcher. * From 3bbe262470f82b30dc8f18e2fd631abad4806a1a Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Fri, 5 Apr 2024 14:25:19 +0000 Subject: [PATCH 081/123] Update facade docblocks --- src/Illuminate/Support/Facades/Event.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Event.php b/src/Illuminate/Support/Facades/Event.php index 3694d0304455..9f0c4952f164 100755 --- a/src/Illuminate/Support/Facades/Event.php +++ b/src/Illuminate/Support/Facades/Event.php @@ -34,6 +34,7 @@ * @method static void assertNothingDispatched() * @method static \Illuminate\Support\Collection dispatched(string $event, callable|null $callback = null) * @method static bool hasDispatched(string $event) + * @method static array dispatchedEvents() * * @see \Illuminate\Events\Dispatcher * @see \Illuminate\Support\Testing\Fakes\EventFake From 47c1de993e16fa48279b86735d6910c86d3575bc Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:03:09 +0330 Subject: [PATCH 082/123] [11.x] improvement tests for Arr::prepend (#50949) * test: improvement tests for Arr::prepend * fix code style --- tests/Support/SupportArrTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 0f17fdf32fdd..9df13ff7befb 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -9,6 +9,7 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; use stdClass; +use TypeError; class SupportArrTest extends TestCase { @@ -758,6 +759,29 @@ public function testPrepend() $array = Arr::prepend(['one' => 1, 'two' => 2], 0, null); $this->assertEquals([null => 0, 'one' => 1, 'two' => 2], $array); + + $array = Arr::prepend(['one', 'two'], null, ''); + $this->assertEquals(['' => null, 'one', 'two'], $array); + + $array = Arr::prepend([], 'zero'); + $this->assertEquals(['zero'], $array); + + $array = Arr::prepend([''], 'zero'); + $this->assertEquals(['zero', ''], $array); + + $array = Arr::prepend(['one', 'two'], ['zero']); + $this->assertEquals([['zero'], 'one', 'two'], $array); + + $array = Arr::prepend(['one', 'two'], ['zero'], 'key'); + $this->assertEquals(['key' => ['zero'], 'one', 'two'], $array); + } + + public function testPrependWhenKeyIsArray() + { + $this->expectException(TypeError::class); + $this->expectExceptionMessage('Illegal offset type'); + + Arr::prepend(['one' => 1, 'two' => 2], 'zero', [0]); } public function testPull() From 92fe58a2f1e6306bde0ca394b06c557626c828c2 Mon Sep 17 00:00:00 2001 From: Seth Phat Date: Mon, 8 Apr 2024 00:36:30 +0700 Subject: [PATCH 083/123] Supports Throwable (#50944) --- src/Illuminate/Support/helpers.php | 4 ++-- tests/Support/SupportHelpersTest.php | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 5cf93d7a9341..be59c1fe353b 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -278,7 +278,7 @@ function preg_replace_array($pattern, array $replacements, $subject) * @param callable|null $when * @return mixed * - * @throws \Exception + * @throws \Throwable */ function retry($times, callable $callback, $sleepMilliseconds = 0, $when = null) { @@ -298,7 +298,7 @@ function retry($times, callable $callback, $sleepMilliseconds = 0, $when = null) try { return $callback($attempts); - } catch (Exception $e) { + } catch (Throwable $e) { if ($times < 1 || ($when && ! $when($e))) { throw $e; } diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index 6d1149bdeb04..6183449af631 100755 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -5,6 +5,7 @@ use ArrayAccess; use ArrayIterator; use Countable; +use Error; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Env; use Illuminate\Support\Optional; @@ -1008,6 +1009,29 @@ public function testRetryWithBackoff() ]); } + public function testRetryWithAThrowableBase() + { + Sleep::fake(); + + $attempts = retry(2, function ($attempts) { + if ($attempts > 1) { + return $attempts; + } + + throw new Error('This is an error'); + }, 100); + + // Make sure we made two attempts + $this->assertEquals(2, $attempts); + + // Make sure we waited 100ms for the first attempt + Sleep::assertSleptTimes(1); + + Sleep::assertSequence([ + Sleep::usleep(100_000), + ]); + } + public function testTransform() { $this->assertEquals(10, transform(5, function ($value) { From 421393f861fe283d79c59f5a87f003c8e5d2dc5e Mon Sep 17 00:00:00 2001 From: findseat <166101790+findseat@users.noreply.github.com> Date: Mon, 8 Apr 2024 01:36:46 +0800 Subject: [PATCH 084/123] chore: remove repetitive words (#50943) Signed-off-by: findseat --- src/Illuminate/Bus/DynamoBatchRepository.php | 2 +- src/Illuminate/Foundation/Vite.php | 2 +- src/Illuminate/Routing/Router.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Bus/DynamoBatchRepository.php b/src/Illuminate/Bus/DynamoBatchRepository.php index b0dc34a10733..c93d7ae7881a 100644 --- a/src/Illuminate/Bus/DynamoBatchRepository.php +++ b/src/Illuminate/Bus/DynamoBatchRepository.php @@ -525,7 +525,7 @@ public function getDynamoClient(): DynamoDbClient } /** - * The the name of the table that contains the batch records. + * The name of the table that contains the batch records. * * @return string */ diff --git a/src/Illuminate/Foundation/Vite.php b/src/Illuminate/Foundation/Vite.php index 0116a5bf7025..97e79b6d03cb 100644 --- a/src/Illuminate/Foundation/Vite.php +++ b/src/Illuminate/Foundation/Vite.php @@ -712,7 +712,7 @@ protected function assetPath($path, $secure = null) } /** - * Get the the manifest file for the given build directory. + * Get the manifest file for the given build directory. * * @param string $buildDirectory * @return array diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index dac895dad212..d7b90fc3dcc9 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -964,7 +964,7 @@ public function substituteImplicitBindings($route) } /** - * Register a callback to to run after implicit bindings are substituted. + * Register a callback to run after implicit bindings are substituted. * * @param callable $callback * @return $this From 53a5aab7da8b0b56ac2ee07e02a77edb9595e9f4 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:06:57 +0330 Subject: [PATCH 085/123] test: improvement tests for Arr::map (#50941) --- tests/Support/SupportArrTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 9df13ff7befb..1b85cfaf31f8 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -707,6 +707,23 @@ public function testMap() $this->assertEquals(['first' => 'taylor', 'last' => 'otwell'], $data); } + public function testMapWithEmptyArray() + { + $mapped = Arr::map([], static function ($value, $key) { + return $key.'-'.$value; + }); + $this->assertEquals([], $mapped); + } + + public function testMapNullValues() + { + $data = ['first' => 'taylor', 'last' => null]; + $mapped = Arr::map($data, static function ($value, $key) { + return $key.'-'.$value; + }); + $this->assertEquals(['first' => 'first-taylor', 'last' => 'last-'], $mapped); + } + public function testMapWithKeys() { $data = [ From 5d3fa1cd53d9c88fc61fe9bda2b960259caa300d Mon Sep 17 00:00:00 2001 From: Daniel Polito Date: Sun, 7 Apr 2024 14:47:00 -0300 Subject: [PATCH 086/123] [10.x] Add `serializeAndRestore()` to `NotificationFake` (#50935) * Add serializeAndRestore() to NotificationFake * Fix Style * Fix * formatting --------- Co-authored-by: Taylor Otwell --- .../Testing/Fakes/NotificationFake.php | 36 ++++++++++++++++++- .../SupportTestingNotificationFakeTest.php | 31 ++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php index df00c465ff3c..ee610a401069 100644 --- a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php +++ b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php @@ -6,6 +6,7 @@ use Exception; use Illuminate\Contracts\Notifications\Dispatcher as NotificationDispatcher; use Illuminate\Contracts\Notifications\Factory as NotificationFactory; +use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Support\Collection; @@ -32,6 +33,13 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact */ public $locale; + /** + * Indicates if notifications should be serialized and restored when pushed to the queue. + * + * @var bool + */ + protected $serializeAndRestore = false; + /** * Assert if a notification was sent on-demand based on a truth-test callback. * @@ -313,7 +321,9 @@ public function sendNow($notifiables, $notification, array $channels = null) } $this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [ - 'notification' => $notification, + 'notification' => $this->serializeAndRestore && $notification instanceof ShouldQueue + ? $this->serializeAndRestoreNotification($notification) + : $notification, 'channels' => $notifiableChannels, 'notifiable' => $notifiable, 'locale' => $notification->locale ?? $this->locale ?? value(function () use ($notifiable) { @@ -349,6 +359,30 @@ public function locale($locale) return $this; } + /** + * Specify if notification should be serialized and restored when being "pushed" to the queue. + * + * @param bool $serializeAndRestore + * @return $this + */ + public function serializeAndRestore(bool $serializeAndRestore = true) + { + $this->serializeAndRestore = $serializeAndRestore; + + return $this; + } + + /** + * Serialize and unserialize the notification to simulate the queueing process. + * + * @param mixed $notification + * @return mixed + */ + protected function serializeAndRestoreNotification($notification) + { + return unserialize(serialize($notification)); + } + /** * Get the notifications that have been sent. * diff --git a/tests/Support/SupportTestingNotificationFakeTest.php b/tests/Support/SupportTestingNotificationFakeTest.php index 878296c18e42..10fce3dbde54 100644 --- a/tests/Support/SupportTestingNotificationFakeTest.php +++ b/tests/Support/SupportTestingNotificationFakeTest.php @@ -3,6 +3,8 @@ namespace Illuminate\Tests\Support; use Exception; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Foundation\Auth\User; use Illuminate\Notifications\AnonymousNotifiable; @@ -221,6 +223,16 @@ public function testAssertSentToWhenNotifiableHasFalsyShouldSend() $this->fake->assertNotSentTo($user, NotificationWithFalsyShouldSendStub::class); } + + public function testAssertItCanSerializeAndRestoreNotifications() + { + $this->fake->serializeAndRestore(); + $this->fake->send($this->user, new NotificationWithSerialization('hello')); + + $this->fake->assertSentTo($this->user, NotificationWithSerialization::class, function ($notification) { + return $notification->value === 'hello-serialized-unserialized'; + }); + } } class NotificationStub extends Notification @@ -256,3 +268,22 @@ public function preferredLocale() return 'au'; } } + +class NotificationWithSerialization extends NotificationStub implements ShouldQueue +{ + use Queueable; + + public function __construct(public $value) + { + } + + public function __serialize(): array + { + return ['value' => $this->value.'-serialized']; + } + + public function __unserialize(array $data): void + { + $this->value = $data['value'].'-unserialized'; + } +} From 7ba6047a3e13ea0ce4d441f5b53c6b131da36d2b Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Sun, 7 Apr 2024 17:47:33 +0000 Subject: [PATCH 087/123] Update facade docblocks --- src/Illuminate/Support/Facades/Notification.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Notification.php b/src/Illuminate/Support/Facades/Notification.php index a588bd5467ed..8b30997e7923 100644 --- a/src/Illuminate/Support/Facades/Notification.php +++ b/src/Illuminate/Support/Facades/Notification.php @@ -31,6 +31,7 @@ * @method static void assertCount(int $expectedCount) * @method static \Illuminate\Support\Collection sent(mixed $notifiable, string $notification, callable|null $callback = null) * @method static bool hasSent(mixed $notifiable, string $notification) + * @method static \Illuminate\Support\Testing\Fakes\NotificationFake serializeAndRestore(bool $serializeAndRestore = true) * @method static array sentNotifications() * @method static void macro(string $name, object|callable $macro) * @method static void mixin(object $mixin, bool $replace = true) From 0b824ba237ae6de344fc3f676f6b31e9d3de59c8 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 8 Apr 2024 11:44:23 +0200 Subject: [PATCH 088/123] Revert "[11.x] improvement tests for Arr::prepend (#50949)" (#50958) This reverts commit 47c1de993e16fa48279b86735d6910c86d3575bc. --- tests/Support/SupportArrTest.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 1b85cfaf31f8..3f9056250973 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -9,7 +9,6 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; use stdClass; -use TypeError; class SupportArrTest extends TestCase { @@ -776,29 +775,6 @@ public function testPrepend() $array = Arr::prepend(['one' => 1, 'two' => 2], 0, null); $this->assertEquals([null => 0, 'one' => 1, 'two' => 2], $array); - - $array = Arr::prepend(['one', 'two'], null, ''); - $this->assertEquals(['' => null, 'one', 'two'], $array); - - $array = Arr::prepend([], 'zero'); - $this->assertEquals(['zero'], $array); - - $array = Arr::prepend([''], 'zero'); - $this->assertEquals(['zero', ''], $array); - - $array = Arr::prepend(['one', 'two'], ['zero']); - $this->assertEquals([['zero'], 'one', 'two'], $array); - - $array = Arr::prepend(['one', 'two'], ['zero'], 'key'); - $this->assertEquals(['key' => ['zero'], 'one', 'two'], $array); - } - - public function testPrependWhenKeyIsArray() - { - $this->expectException(TypeError::class); - $this->expectExceptionMessage('Illegal offset type'); - - Arr::prepend(['one' => 1, 'two' => 2], 'zero', [0]); } public function testPull() From 7abab3a8fe3d5504ba6def4b942d6b6aac50d012 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 8 Apr 2024 20:40:42 +0800 Subject: [PATCH 089/123] Test Improvements (#50960) * Test Improvements * wip --- tests/Integration/Foundation/Console/AboutCommandTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Foundation/Console/AboutCommandTest.php b/tests/Integration/Foundation/Console/AboutCommandTest.php index 6795d3bafeb2..d671ba8207c4 100644 --- a/tests/Integration/Foundation/Console/AboutCommandTest.php +++ b/tests/Integration/Foundation/Console/AboutCommandTest.php @@ -11,13 +11,13 @@ class AboutCommandTest extends TestCase { public function testItCanDisplayAboutCommandAsJson() { - $process = remote('about --json')->mustRun(); + $process = remote('about --json', ['APP_ENV' => 'local'])->mustRun(); tap(json_decode($process->getOutput(), true), function ($output) { Assert::assertArraySubset([ 'application_name' => 'Laravel', 'php_version' => PHP_VERSION, - 'environment' => 'testing', + 'environment' => 'local', 'debug_mode' => true, 'url' => 'localhost', 'maintenance_mode' => false, From 4c26433fab5c7824a3dbd6e42cd12e40c63a8da6 Mon Sep 17 00:00:00 2001 From: Shin <2082119+shinsenter@users.noreply.github.com> Date: Mon, 8 Apr 2024 22:33:41 +0900 Subject: [PATCH 090/123] Update PendingRequest.php (#50955) This commit fixes this error: ``` Call to undefined method Illuminate\Http\Client\ConnectionException::toException() ``` --- src/Illuminate/Http/Client/PendingRequest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index b1264922c419..1a10ce9a22cb 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -1055,7 +1055,11 @@ protected function handlePromiseResponse(Response|ConnectionException|TransferEx } if ($attempt < $this->tries && $shouldRetry) { - $options['delay'] = value($this->retryDelay, $attempt, $response->toException()); + $options['delay'] = value( + $this->retryDelay, + $attempt, + $response instanceof Response ? $response->toException() : $response + ); return $this->makePromise($method, $url, $options, $attempt + 1); } From cd5866d5786456239453a23e6a79821286cd6a9e Mon Sep 17 00:00:00 2001 From: naopusyu <97194355+naopusyu@users.noreply.github.com> Date: Tue, 9 Apr 2024 01:40:35 +0900 Subject: [PATCH 091/123] remove unknown parameter (#50965) --- src/Illuminate/Database/Schema/Blueprint.php | 1 - src/Illuminate/Foundation/Configuration/Middleware.php | 2 -- src/Illuminate/Http/Client/PendingRequest.php | 1 - src/Illuminate/Http/Client/Response.php | 2 -- 4 files changed, 6 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 1de396db26d6..3dc3e24ab343 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -296,7 +296,6 @@ public function engine($engine) /** * Specify that the InnoDB storage engine should be used for the table (MySQL only). * - * @param string $engine * @return void */ public function innoDb() diff --git a/src/Illuminate/Foundation/Configuration/Middleware.php b/src/Illuminate/Foundation/Configuration/Middleware.php index 7d1216d23c85..22195364f43e 100644 --- a/src/Illuminate/Foundation/Configuration/Middleware.php +++ b/src/Illuminate/Foundation/Configuration/Middleware.php @@ -303,7 +303,6 @@ public function replaceInGroup(string $group, string $search, string $replace) /** * Modify the middleware in the "web" group. * - * @param string $group * @param array|string $append * @param array|string $prepend * @param array|string $remove @@ -318,7 +317,6 @@ public function web(array|string $append = [], array|string $prepend = [], array /** * Modify the middleware in the "api" group. * - * @param string $group * @param array|string $append * @param array|string $prepend * @param array|string $remove diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 1a10ce9a22cb..457731401051 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -702,7 +702,6 @@ public function throw(?callable $callback = null) * Throw an exception if a server or client error occurred and the given condition evaluates to true. * * @param callable|bool $condition - * @param callable|null $throwCallback * @return $this */ public function throwIf($condition) diff --git a/src/Illuminate/Http/Client/Response.php b/src/Illuminate/Http/Client/Response.php index baa774c15efb..79f4d8a439fa 100644 --- a/src/Illuminate/Http/Client/Response.php +++ b/src/Illuminate/Http/Client/Response.php @@ -277,7 +277,6 @@ public function toException() /** * Throw an exception if a server or client error occurred. * - * @param \Closure|null $callback * @return $this * * @throws \Illuminate\Http\Client\RequestException @@ -301,7 +300,6 @@ public function throw() * Throw an exception if a server or client error occurred and the given condition evaluates to true. * * @param \Closure|bool $condition - * @param \Closure|null $throwCallback * @return $this * * @throws \Illuminate\Http\Client\RequestException From 2bfbac92f9a3bb41bff09587e7d5d293b6f6aa7b Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Mon, 8 Apr 2024 16:41:34 +0000 Subject: [PATCH 092/123] Update facade docblocks --- src/Illuminate/Support/Facades/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index 80695680f6ca..baa76c007ba4 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -60,7 +60,7 @@ * @method static \Illuminate\Http\Client\PendingRequest withResponseMiddleware(callable $middleware) * @method static \Illuminate\Http\Client\PendingRequest beforeSending(callable $callback) * @method static \Illuminate\Http\Client\PendingRequest throw(callable|null $callback = null) - * @method static \Illuminate\Http\Client\PendingRequest throwIf(callable|bool $condition, callable|null $throwCallback = null) + * @method static \Illuminate\Http\Client\PendingRequest throwIf(callable|bool $condition) * @method static \Illuminate\Http\Client\PendingRequest throwUnless(bool $condition) * @method static \Illuminate\Http\Client\PendingRequest dump() * @method static \Illuminate\Http\Client\PendingRequest dd() From 81d8154874400f2625553a606c2d801d0f014a9a Mon Sep 17 00:00:00 2001 From: naopusyu <97194355+naopusyu@users.noreply.github.com> Date: Tue, 9 Apr 2024 02:47:24 +0900 Subject: [PATCH 093/123] fix doc comment (#50967) --- src/Illuminate/Mail/Mailer.php | 2 +- src/Illuminate/Queue/Jobs/FakeJob.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index 351d341868be..418265e597e0 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -360,7 +360,7 @@ protected function sendMailable(MailableContract $mailable) /** * Send a new message synchronously using a view. * - * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param \Illuminate\Contracts\Mail\Mailable|string|array $mailable * @param array $data * @param \Closure|string|null $callback * @return \Illuminate\Mail\SentMessage|null diff --git a/src/Illuminate/Queue/Jobs/FakeJob.php b/src/Illuminate/Queue/Jobs/FakeJob.php index f72c01e8fa1d..8866afda072f 100644 --- a/src/Illuminate/Queue/Jobs/FakeJob.php +++ b/src/Illuminate/Queue/Jobs/FakeJob.php @@ -65,7 +65,7 @@ public function delete() /** * Delete the job, call the "failed" method, and raise the failed job event. * - * @param \Throwable|null $e + * @param \Throwable|null $exception * @return void */ public function fail($exception = null) From bc448b9d16aef2823d855b1a2493b0c70f0c44dd Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:50:48 +0200 Subject: [PATCH 094/123] Fix (#50979) --- src/Illuminate/Foundation/Configuration/ApplicationBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php index 5419666cee3f..756055ca527e 100644 --- a/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php +++ b/src/Illuminate/Foundation/Configuration/ApplicationBuilder.php @@ -289,7 +289,7 @@ protected function withCommandRouting(array $paths) /** * Register the scheduled tasks for the application. * - * @param callable(Schedule $schedule): void $callback + * @param callable(\Illuminate\Console\Scheduling\Schedule $schedule): void $callback * @return $this */ public function withSchedule(callable $callback) From eda70687d4411096165e0f4d273f0d471d65cb84 Mon Sep 17 00:00:00 2001 From: Jurian Arie <28654085+JurianArie@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:10:57 +0200 Subject: [PATCH 095/123] Allow time to be faked in database lock (#50981) --- src/Illuminate/Cache/DatabaseLock.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Cache/DatabaseLock.php b/src/Illuminate/Cache/DatabaseLock.php index cf08dcf98cbd..715d141c0d45 100644 --- a/src/Illuminate/Cache/DatabaseLock.php +++ b/src/Illuminate/Cache/DatabaseLock.php @@ -75,7 +75,7 @@ public function acquire() $updated = $this->connection->table($this->table) ->where('key', $this->name) ->where(function ($query) { - return $query->where('owner', $this->owner)->orWhere('expiration', '<=', time()); + return $query->where('owner', $this->owner)->orWhere('expiration', '<=', $this->currentTime()); })->update([ 'owner' => $this->owner, 'expiration' => $this->expiresAt(), @@ -85,7 +85,7 @@ public function acquire() } if (random_int(1, $this->lottery[1]) <= $this->lottery[0]) { - $this->connection->table($this->table)->where('expiration', '<=', time())->delete(); + $this->connection->table($this->table)->where('expiration', '<=', $this->currentTime())->delete(); } return $acquired; @@ -100,7 +100,7 @@ protected function expiresAt() { $lockTimeout = $this->seconds > 0 ? $this->seconds : $this->defaultTimeoutInSeconds; - return time() + $lockTimeout; + return $this->currentTime() + $lockTimeout; } /** From e0f2f6c9be8805579787d5bcfb77fd6baa42a16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Potock=C3=BD?= Date: Tue, 9 Apr 2024 16:13:11 +0200 Subject: [PATCH 096/123] [11.x] Introduce method `Http::createPendingRequest()` (#50980) * Introduce method `\Illuminate\Http\Client\Factory::createPendingRequest()` * Fix passing stubs & stray requests * Update comments --- src/Illuminate/Http/Client/Factory.php | 16 +++++++++++++--- tests/Http/HttpClientTest.php | 7 +++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php index 4f8a48a50696..b6679f200671 100644 --- a/src/Illuminate/Http/Client/Factory.php +++ b/src/Illuminate/Http/Client/Factory.php @@ -418,6 +418,18 @@ public function recorded($callback = null) * * @return \Illuminate\Http\Client\PendingRequest */ + public function createPendingRequest() + { + return tap($this->newPendingRequest(), function ($request) { + $request->stub($this->stubCallbacks)->preventStrayRequests($this->preventStrayRequests); + }); + } + + /** + * Instantiate a new pending request instance for this factory. + * + * @return \Illuminate\Http\Client\PendingRequest + */ protected function newPendingRequest() { return (new PendingRequest($this, $this->globalMiddleware))->withOptions(value($this->globalOptions)); @@ -456,8 +468,6 @@ public function __call($method, $parameters) return $this->macroCall($method, $parameters); } - return tap($this->newPendingRequest(), function ($request) { - $request->stub($this->stubCallbacks)->preventStrayRequests($this->preventStrayRequests); - })->{$method}(...$parameters); + return $this->createPendingRequest()->{$method}(...$parameters); } } diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 6590bf78f143..75fd630a418f 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -3025,6 +3025,13 @@ public function testItCanHaveGlobalDefaultValues() $this->assertSame(['false'], $headers['X-Foo']); $this->assertSame(['true'], $headers['X-Bar']); } + + public function testItCanCreatePendingRequest() + { + $factory = new Factory(); + + $this->assertInstanceOf(PendingRequest::class, $factory->createPendingRequest()); + } } class CustomFactory extends Factory From 3ce487b4306be66ba51106a1592c94aed61f633c Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Tue, 9 Apr 2024 14:13:50 +0000 Subject: [PATCH 097/123] Update facade docblocks --- 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 baa76c007ba4..840af21be610 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -20,6 +20,7 @@ * @method static void assertSentCount(int $count) * @method static void assertSequencesAreEmpty() * @method static \Illuminate\Support\Collection recorded(callable $callback = null) + * @method static \Illuminate\Http\Client\PendingRequest createPendingRequest() * @method static \Illuminate\Contracts\Events\Dispatcher|null getDispatcher() * @method static array getGlobalMiddleware() * @method static void macro(string $name, object|callable $macro) From 0b67185066ca476fa7ca7e3721b316842861daa7 Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:54:04 +0330 Subject: [PATCH 098/123] [11.x] improvement test for prepend method (#50968) * test: improvement test for prepend method * refactor: add use TypeError * wip testPrependWhenKeyIsArray method * wip --- .../Database/Concerns/BuildsQueries.php | 2 ++ tests/Support/SupportArrTest.php | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 0d45b0a6f6fc..67de06ec96d4 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -139,6 +139,8 @@ public function chunkByIdDesc($count, callable $callback, $column = null, $alias * @param string|null $alias * @param bool $descending * @return bool + * + * @throws \RuntimeException */ public function orderedChunkById($count, callable $callback, $column = null, $alias = null, $descending = false) { diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 3f9056250973..5a3f15b057d4 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -775,6 +775,21 @@ public function testPrepend() $array = Arr::prepend(['one' => 1, 'two' => 2], 0, null); $this->assertEquals([null => 0, 'one' => 1, 'two' => 2], $array); + + $array = Arr::prepend(['one', 'two'], null, ''); + $this->assertEquals(['' => null, 'one', 'two'], $array); + + $array = Arr::prepend([], 'zero'); + $this->assertEquals(['zero'], $array); + + $array = Arr::prepend([''], 'zero'); + $this->assertEquals(['zero', ''], $array); + + $array = Arr::prepend(['one', 'two'], ['zero']); + $this->assertEquals([['zero'], 'one', 'two'], $array); + + $array = Arr::prepend(['one', 'two'], ['zero'], 'key'); + $this->assertEquals(['key' => ['zero'], 'one', 'two'], $array); } public function testPull() From 89515a9f41c6108e8bf670049968448a36405ecf Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:54:17 +0330 Subject: [PATCH 099/123] test: improvement test for Arr::collapse method (#50966) --- tests/Support/SupportArrTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 5a3f15b057d4..cca30dfcb3e1 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -38,11 +38,26 @@ public function testAdd() public function testCollapse() { + // Normal case: a two-dimensional array with different elements $data = [['foo', 'bar'], ['baz']]; $this->assertEquals(['foo', 'bar', 'baz'], Arr::collapse($data)); + // Case including numeric and string elements $array = [[1], [2], [3], ['foo', 'bar'], collect(['baz', 'boom'])]; $this->assertEquals([1, 2, 3, 'foo', 'bar', 'baz', 'boom'], Arr::collapse($array)); + + // Case with empty two-dimensional arrays + $emptyArray = [[], [], []]; + $this->assertEquals([], Arr::collapse($emptyArray)); + + // Case with both empty arrays and arrays with elements + $mixedArray = [[], [1, 2], [], ['foo', 'bar']]; + $this->assertEquals([1, 2, 'foo', 'bar'], Arr::collapse($mixedArray)); + + // Case including collections and arrays + $collection = collect(['baz', 'boom']); + $mixedArray = [[1], [2], [3], ['foo', 'bar'], $collection]; + $this->assertEquals([1, 2, 3, 'foo', 'bar', 'baz', 'boom'], Arr::collapse($mixedArray)); } public function testCrossJoin() From d2a8471d3443313b970cd65f452edaed3a425dea Mon Sep 17 00:00:00 2001 From: "S.a Mahmoudzadeh" <36761585+saMahmoudzadeh@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:57:49 +0330 Subject: [PATCH 100/123] fix: Add some @throws (#50969) --- src/Illuminate/Foundation/helpers.php | 1 + src/Illuminate/Routing/ResponseFactory.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index b19b0d85397e..365c76516c0f 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -34,6 +34,7 @@ * * @throws \Symfony\Component\HttpKernel\Exception\HttpException * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @throws \Illuminate\Http\Exceptions\HttpResponseException */ function abort($code, $message = '', array $headers = []) { diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index 84c69225e370..0c90965c897f 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -152,6 +152,8 @@ public function streamJson($data, $status = 200, $headers = [], $encodingOptions * @param array $headers * @param string|null $disposition * @return \Symfony\Component\HttpFoundation\StreamedResponse + * + * @throws \Illuminate\Routing\Exceptions\StreamedResponseException */ public function streamDownload($callback, $name = null, array $headers = [], $disposition = 'attachment') { From f36f19427c6411104348e4a2f42b37a68f37330a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20R=C3=BCsweg?= Date: Tue, 9 Apr 2024 16:32:27 +0200 Subject: [PATCH 101/123] [11.x] Fix PHP_MAXPATHLEN check for existing check of files for views (#50962) * Add test for \PHP_MAXPATHLEN errors A PHP warning can occur if the filename is a little less than (or equal to) \PHP_MAXPATHLEN [1] AND open_basedir [2] is configured (otherwise PHP will not throw this error [3]). By searching for the filename and appending a suffix (and also using the absolute path), we may exceed the limit. If the limit is exceeded, PHP throws a warning message [4] and Laravel aborts the execution of the code. [1] https://www.php.net/manual/en/reserved.constants.php#constant.php-maxpathlen [2] https://www.php.net/manual/en/ini.core.php#ini.open-basedir [3] https://github.com/php/php-src/blob/7c860628cd2bf11ee867bfb41b3fd0314c5177c5/main/fopen_wrappers.c#L302 [4] File name is longer than the maximum allowed path length on this platform * Fix `PHP_MAXPATHLEN` check for existing check of files for views A PHP warning can occur if the filename is a little less than (or equal to) \PHP_MAXPATHLEN [1] AND open_basedir [2] is configured (otherwise PHP will not throw this error [3]). By searching for the filename and appending a suffix (and also using the absolute path), we may exceed the limit. If the limit is exceeded, PHP throws a warning message [4] and Laravel aborts the execution of the code. [1] https://www.php.net/manual/en/reserved.constants.php#constant.php-maxpathlen [2] https://www.php.net/manual/en/ini.core.php#ini.open-basedir [3] https://github.com/php/php-src/blob/7c860628cd2bf11ee867bfb41b3fd0314c5177c5/main/fopen_wrappers.c#L302 [4] File name is longer than the maximum allowed path length on this platform * Update FileViewFinder.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/View/Component.php | 2 +- src/Illuminate/View/FileViewFinder.php | 4 +++- tests/Integration/View/BladeTest.php | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/View/Component.php b/src/Illuminate/View/Component.php index dcbe764c506b..6768fdcbb1c2 100644 --- a/src/Illuminate/View/Component.php +++ b/src/Illuminate/View/Component.php @@ -170,7 +170,7 @@ protected function extractBladeViewFromString($contents) return static::$bladeViewCache[$key]; } - if (strlen($contents) <= PHP_MAXPATHLEN && $this->factory()->exists($contents)) { + if ($this->factory()->exists($contents)) { return static::$bladeViewCache[$key] = $contents; } diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 107bf7c36bdc..4b2f32679307 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -128,7 +128,9 @@ protected function findInPaths($name, $paths) { foreach ((array) $paths as $path) { foreach ($this->getPossibleViewFiles($name) as $file) { - if ($this->files->exists($viewPath = $path.'/'.$file)) { + $viewPath = $path.'/'.$file; + + if (strlen($viewPath) <= PHP_MAXPATHLEN && $this->files->exists($viewPath)) { return $viewPath; } } diff --git a/tests/Integration/View/BladeTest.php b/tests/Integration/View/BladeTest.php index 61dc2cb32814..cff73e6a7bca 100644 --- a/tests/Integration/View/BladeTest.php +++ b/tests/Integration/View/BladeTest.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\View; use Illuminate\View\Component; use Orchestra\Testbench\TestCase; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; @@ -26,6 +27,29 @@ public function test_rendering_blade_long_maxpathlen_string() $this->assertSame($longString.'a', $result); } + #[RunInSeparateProcess] + public function test_rendering_blade_long_maxpathlen_string_with_exact_length() + { + // The PHP_MAXPATHLEN restriction is only active, if + // open_basedir is set and active. Otherwise, the check + // for the PHP_MAXPATHLEN is not active. + if (ini_get('open_basedir') === '') { + $openBaseDir = windows_os() ? explode('\\', __DIR__)[0].'\\'.';'.sys_get_temp_dir() : '/'; + $iniSet = ini_set( + 'open_basedir', + $openBaseDir + ); + + $this->assertNotFalse($iniSet, 'Could not set config for open_basedir.'); + } + + $longString = str_repeat('x', PHP_MAXPATHLEN); + + $result = Blade::render($longString); + + $this->assertSame($longString, $result); + } + public function test_rendering_blade_component_instance() { $component = new HelloComponent('Taylor'); From 24f16baeef756e80eda33576847c08b485bfd5a7 Mon Sep 17 00:00:00 2001 From: Kacper Pruszynski Date: Tue, 9 Apr 2024 16:34:24 +0200 Subject: [PATCH 102/123] [11.x] Allow to remove scopes from BelongsToMany relation (#50945) (#50953) --- .../Eloquent/Relations/BelongsToMany.php | 2 +- ...aseEloquentBelongsToManyExpressionTest.php | 26 +++++++++++++++++++ ...tBelongsToManyWithCastedAttributesTest.php | 5 ++-- ...BelongsToManyWithDefaultAttributesTest.php | 7 ++--- ...oquentBelongsToManyWithoutTouchingTest.php | 5 +++- .../DatabaseEloquentMorphToManyTest.php | 13 +++++----- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 70290c4da557..26ca5b44a8b9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -1563,7 +1563,7 @@ public function getPivotColumns() */ public function qualifyPivotColumn($column) { - if ($this->getGrammar()->isExpression($column)) { + if ($this->query->getQuery()->getGrammar()->isExpression($column)) { return $column; } diff --git a/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php b/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php index 647757bb3ff3..53e09cfb82f6 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Database; +use Exception; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Eloquent\Relations\MorphToMany; @@ -52,6 +53,31 @@ public function testQualifiedColumnExpression(): void $this->assertEquals(3, $tags->first()->getKey()); } + public function testGlobalScopesAreAppliedToBelongsToManyRelation(): void + { + $this->seedData(); + $post = DatabaseEloquentBelongsToManyExpressionTestTestPost::query()->firstOrFail(); + DatabaseEloquentBelongsToManyExpressionTestTestTag::addGlobalScope( + 'default', + static fn () => throw new Exception('Default global scope.') + ); + + $this->expectExceptionMessage('Default global scope.'); + $post->tags()->get(); + } + + public function testGlobalScopesCanBeRemovedFromBelongsToManyRelation(): void + { + $this->seedData(); + $post = DatabaseEloquentBelongsToManyExpressionTestTestPost::query()->firstOrFail(); + DatabaseEloquentBelongsToManyExpressionTestTestTag::addGlobalScope( + 'default', + static fn () => throw new Exception('Default global scope.') + ); + + $this->assertNotEmpty($post->tags()->withoutGlobalScopes()->get()); + } + /** * Setup the database schema. * diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php index 96c3e24b2a48..d0e917a4583b 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -9,6 +9,7 @@ use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; +use stdClass; class DatabaseEloquentBelongsToManyWithCastedAttributesTest extends TestCase { @@ -64,8 +65,8 @@ protected function getRelation() $builder->shouldReceive('getModel')->andReturn($related); $related->shouldReceive('qualifyColumn'); $builder->shouldReceive('join', 'where'); - $builder->shouldReceive('getGrammar')->andReturn( - m::mock(Grammar::class, ['isExpression' => false]) + $builder->shouldReceive('getQuery')->andReturn( + m::mock(stdClass::class, ['getGrammar' => m::mock(Grammar::class, ['isExpression' => false])]) ); return new BelongsToMany( diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php index 90174ce3e771..1910dce8c1c3 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php @@ -31,8 +31,7 @@ public function testWithPivotValueMethodSetsDefaultArgumentsForInsertion() $query = m::mock(stdClass::class); $query->shouldReceive('from')->once()->with('club_user')->andReturn($query); $query->shouldReceive('insert')->once()->with([['club_id' => 1, 'user_id' => 1, 'is_admin' => 1]])->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->attach(1); } @@ -56,7 +55,9 @@ public function getRelationArguments() $builder->shouldReceive('join')->once()->with('club_user', 'users.id', '=', 'club_user.user_id'); $builder->shouldReceive('where')->once()->with('club_user.club_id', '=', 1); $builder->shouldReceive('where')->once()->with('club_user.is_admin', '=', 1, 'and'); - $builder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); + + $builder->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); + $mockQueryBuilder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); return [$builder, $parent, 'club_user', 'club_id', 'user_id', 'id', 'id', null, false]; } diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php index 6eafa9668671..7b6ad7b510f8 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php @@ -10,6 +10,7 @@ use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; +use stdClass; class DatabaseEloquentBelongsToManyWithoutTouchingTest extends TestCase { @@ -32,7 +33,9 @@ public function testItWillNotTouchRelatedModelsWhenUpdatingChild(): void $parent->shouldReceive('getAttribute')->with('id')->andReturn(1); $builder->shouldReceive('getModel')->andReturn($related); $builder->shouldReceive('where'); - $builder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); + $builder->shouldReceive('getQuery')->andReturn( + m::mock(stdClass::class, ['getGrammar' => m::mock(Grammar::class, ['isExpression' => false])]) + ); $relation = new BelongsToMany($builder, $parent, 'article_users', 'user_id', 'article_id', 'id', 'id'); $builder->shouldReceive('update')->never(); diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 36f4466ee943..b5f747133d87 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -33,8 +33,7 @@ public function testAttachInsertsPivotTableRecord(): void $query = m::mock(stdClass::class); $query->shouldReceive('from')->once()->with('taggables')->andReturn($query); $query->shouldReceive('insert')->once()->with([['taggable_id' => 1, 'taggable_type' => get_class($relation->getParent()), 'tag_id' => 2, 'foo' => 'bar']])->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->expects($this->once())->method('touchIfTouching'); $relation->attach(2, ['foo' => 'bar']); @@ -49,8 +48,7 @@ public function testDetachRemovesPivotTableRecord(): void $query->shouldReceive('where')->once()->with('taggable_type', get_class($relation->getParent()))->andReturn($query); $query->shouldReceive('whereIn')->once()->with('taggables.tag_id', [1, 2, 3]); $query->shouldReceive('delete')->once()->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->expects($this->once())->method('touchIfTouching'); $this->assertTrue($relation->detach([1, 2, 3])); @@ -65,8 +63,7 @@ public function testDetachMethodClearsAllPivotRecordsWhenNoIDsAreGiven(): void $query->shouldReceive('where')->once()->with('taggable_type', get_class($relation->getParent()))->andReturn($query); $query->shouldReceive('whereIn')->never(); $query->shouldReceive('delete')->once()->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->expects($this->once())->method('touchIfTouching'); $this->assertTrue($relation->detach()); @@ -130,7 +127,9 @@ public function getRelationArguments(): array $grammar = m::mock(Grammar::class); $grammar->shouldReceive('isExpression')->with(m::type(Expression::class))->andReturnTrue(); $grammar->shouldReceive('isExpression')->with(m::type('string'))->andReturnFalse(); - $builder->shouldReceive('getGrammar')->andReturn($grammar); + $builder->shouldReceive('getQuery')->andReturn( + m::mock(stdClass::class, ['getGrammar' => $grammar]) + ); return [$builder, $parent, 'taggable', 'taggables', 'taggable_id', 'tag_id', 'id', 'id', 'relation_name', false]; } From 62477b3e06c7056d1a36d45937f5f93f2e76d8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Guimar=C3=A3es?= Date: Tue, 9 Apr 2024 11:44:41 -0300 Subject: [PATCH 103/123] [11.x] Throw exception if named rate limiter and model property do not exist (#50908) * Add tests * Fix test * fix test * Account for worst case scenario on tests * naive approach * working impl * add a more specific message if the user is authenticated * Use `hasAttribute` method to deal with accessors * use null-safe operator * trigger ci * formatting * fix tests --------- Co-authored-by: Taylor Otwell --- .../MissingRateLimiterException.php | 31 +++++ .../Routing/Middleware/ThrottleRequests.php | 20 +++- .../Integration/Http/ThrottleRequestsTest.php | 106 ++++++++++++++++++ 3 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php diff --git a/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php b/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php new file mode 100644 index 000000000000..ed683dd731ab --- /dev/null +++ b/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php @@ -0,0 +1,31 @@ +user() ? 1 : 0]; } - if (! is_numeric($maxAttempts) && $request->user()) { + if (! is_numeric($maxAttempts) && + $request->user()?->hasAttribute($maxAttempts) + ) { $maxAttempts = $request->user()->{$maxAttempts}; } + // If we still don't have a numeric value, there was no matching rate limiter... + if (! is_numeric($maxAttempts)) { + is_null($request->user()) + ? throw MissingRateLimiterException::forLimiter($maxAttempts) + : throw MissingRateLimiterException::forLimiterAndUser($maxAttempts, get_class($request->user())); + } + return (int) $maxAttempts; } @@ -271,9 +283,9 @@ protected function addHeaders(Response $response, $maxAttempts, $remainingAttemp * @return array */ protected function getHeaders($maxAttempts, - $remainingAttempts, - $retryAfter = null, - ?Response $response = null) + $remainingAttempts, + $retryAfter = null, + ?Response $response = null) { if ($response && ! is_null($response->headers->get('X-RateLimit-Remaining')) && diff --git a/tests/Integration/Http/ThrottleRequestsTest.php b/tests/Integration/Http/ThrottleRequestsTest.php index e966a471f2bf..4a601ad2d9b6 100644 --- a/tests/Integration/Http/ThrottleRequestsTest.php +++ b/tests/Integration/Http/ThrottleRequestsTest.php @@ -6,18 +6,26 @@ use Illuminate\Cache\RateLimiting\GlobalLimit; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Container\Container; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Foundation\Auth\User; +use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Http\Exceptions\ThrottleRequestsException; +use Illuminate\Routing\Exceptions\MissingRateLimiterException; use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Route; use Orchestra\Testbench\Attributes\WithConfig; +use Orchestra\Testbench\Attributes\WithMigration; use Orchestra\Testbench\TestCase; use PHPUnit\Framework\Attributes\DataProvider; use Throwable; #[WithConfig('hashing.driver', 'bcrypt')] +#[WithMigration] class ThrottleRequestsTest extends TestCase { + use RefreshDatabase; + public function testLockOpensImmediatelyAfterDecay() { Carbon::setTestNow(Carbon::create(2018, 1, 1, 0, 0, 0)); @@ -233,4 +241,102 @@ public function testItCanThrottlePerSecond() $response = $this->get('/'); $response->assertOk(); } + + public function testItFailsIfNamedLimiterDoesNotExist() + { + $this->expectException(MissingRateLimiterException::class); + $this->expectExceptionMessage('Rate limiter [test] is not defined.'); + + Route::get('/', fn () => 'ok')->middleware(ThrottleRequests::using('test')); + + $this->withoutExceptionHandling()->get('/'); + } + + public function testItFailsIfNamedLimiterDoesNotExistAndAuthenticatedUserDoesNotHaveFallbackProperty() + { + $this->expectException(MissingRateLimiterException::class); + $this->expectExceptionMessage('Rate limiter [' . User::class . '::rateLimiting] is not defined.'); + + Route::get('/', fn () => 'ok')->middleware(['auth', ThrottleRequests::using('rateLimiting')]); + + // The reason we're enabling strict mode and actually creating a user is to ensure we never even try to access + // a property within the user model that does not exist. If an application is in strict mode and there is + // no matching rate limiter, it should throw a rate limiter exception, not a property access exception. + Model::shouldBeStrict(); + $user = User::forceCreate([ + 'name' => 'Mateus', + 'email' => 'mateus@example.org', + 'password' => 'password', + ]); + + $this->withoutExceptionHandling()->actingAs($user)->get('/'); + } + + public function testItFallbacksToUserPropertyWhenThereIsNoNamedLimiterWhenAuthenticated() + { + $user = User::make()->forceFill([ + 'rateLimiting' => 1, + ]); + + Carbon::setTestNow(Carbon::create(2018, 1, 1, 0, 0, 0)); + + // The `rateLimiting` named limiter does not exist, but the `rateLimiting` property on the + // User model does, so it should fallback to that property within the authenticated model. + Route::get('/', fn () => 'yes')->middleware(['auth', ThrottleRequests::using('rateLimiting')]); + + $response = $this->withoutExceptionHandling()->actingAs($user)->get('/'); + $this->assertSame('yes', $response->getContent()); + $this->assertEquals(1, $response->headers->get('X-RateLimit-Limit')); + $this->assertEquals(0, $response->headers->get('X-RateLimit-Remaining')); + + Carbon::setTestNow(Carbon::create(2018, 1, 1, 0, 0, 58)); + + try { + $this->withoutExceptionHandling()->actingAs($user)->get('/'); + } catch (Throwable $e) { + $this->assertInstanceOf(ThrottleRequestsException::class, $e); + $this->assertEquals(429, $e->getStatusCode()); + $this->assertEquals(1, $e->getHeaders()['X-RateLimit-Limit']); + $this->assertEquals(0, $e->getHeaders()['X-RateLimit-Remaining']); + $this->assertEquals(2, $e->getHeaders()['Retry-After']); + $this->assertEquals(Carbon::now()->addSeconds(2)->getTimestamp(), $e->getHeaders()['X-RateLimit-Reset']); + } + } + + public function testItFallbacksToUserAccessorWhenThereIsNoNamedLimiterWhenAuthenticated() + { + $user = UserWithAcessor::make(); + + Carbon::setTestNow(Carbon::create(2018, 1, 1, 0, 0, 0)); + + // The `rateLimiting` named limiter does not exist, but the `rateLimiting` accessor (not property!) + // on the User model does, so it should fallback to that accessor within the authenticated model. + Route::get('/', fn () => 'yes')->middleware(['auth', ThrottleRequests::using('rateLimiting')]); + + $response = $this->withoutExceptionHandling()->actingAs($user)->get('/'); + $this->assertSame('yes', $response->getContent()); + $this->assertEquals(1, $response->headers->get('X-RateLimit-Limit')); + $this->assertEquals(0, $response->headers->get('X-RateLimit-Remaining')); + + Carbon::setTestNow(Carbon::create(2018, 1, 1, 0, 0, 58)); + + try { + $this->withoutExceptionHandling()->actingAs($user)->get('/'); + } catch (Throwable $e) { + $this->assertInstanceOf(ThrottleRequestsException::class, $e); + $this->assertEquals(429, $e->getStatusCode()); + $this->assertEquals(1, $e->getHeaders()['X-RateLimit-Limit']); + $this->assertEquals(0, $e->getHeaders()['X-RateLimit-Remaining']); + $this->assertEquals(2, $e->getHeaders()['Retry-After']); + $this->assertEquals(Carbon::now()->addSeconds(2)->getTimestamp(), $e->getHeaders()['X-RateLimit-Reset']); + } + } +} + +class UserWithAcessor extends User +{ + public function getRateLimitingAttribute(): int + { + return 1; + } } From ad817f5731fc77b316224155450f2d4b12a56a13 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Tue, 9 Apr 2024 14:45:03 +0000 Subject: [PATCH 104/123] Apply fixes from StyleCI --- .../Routing/Exceptions/MissingRateLimiterException.php | 4 ++-- src/Illuminate/Routing/Middleware/ThrottleRequests.php | 1 + tests/Integration/Http/ThrottleRequestsTest.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php b/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php index ed683dd731ab..3b71c444b837 100644 --- a/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php +++ b/src/Illuminate/Routing/Exceptions/MissingRateLimiterException.php @@ -20,8 +20,8 @@ public static function forLimiter(string $limiter) /** * Create a new exception for an invalid rate limiter based on a model property. * - * @param string $limiter - * @param class-string $model + * @param string $limiter + * @param class-string $model * @return static */ public static function forLimiterAndUser(string $limiter, string $model) diff --git a/src/Illuminate/Routing/Middleware/ThrottleRequests.php b/src/Illuminate/Routing/Middleware/ThrottleRequests.php index 8083660ff700..7158704c788b 100644 --- a/src/Illuminate/Routing/Middleware/ThrottleRequests.php +++ b/src/Illuminate/Routing/Middleware/ThrottleRequests.php @@ -177,6 +177,7 @@ protected function handleRequest($request, Closure $next, array $limits) * @param \Illuminate\Http\Request $request * @param int|string $maxAttempts * @return int + * * @throws \Illuminate\Routing\Exceptions\MissingRateLimiterException */ protected function resolveMaxAttempts($request, $maxAttempts) diff --git a/tests/Integration/Http/ThrottleRequestsTest.php b/tests/Integration/Http/ThrottleRequestsTest.php index 4a601ad2d9b6..91c57581b9fe 100644 --- a/tests/Integration/Http/ThrottleRequestsTest.php +++ b/tests/Integration/Http/ThrottleRequestsTest.php @@ -255,7 +255,7 @@ public function testItFailsIfNamedLimiterDoesNotExist() public function testItFailsIfNamedLimiterDoesNotExistAndAuthenticatedUserDoesNotHaveFallbackProperty() { $this->expectException(MissingRateLimiterException::class); - $this->expectExceptionMessage('Rate limiter [' . User::class . '::rateLimiting] is not defined.'); + $this->expectExceptionMessage('Rate limiter ['.User::class.'::rateLimiting] is not defined.'); Route::get('/', fn () => 'ok')->middleware(['auth', ThrottleRequests::using('rateLimiting')]); From a8b682e1371338848637f638aedaef2f7607d36f Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 9 Apr 2024 14:48:50 +0000 Subject: [PATCH 105/123] Update version to v10.48.5 --- 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 30d60b3f4976..9649f34af55b 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -40,7 +40,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '10.48.4'; + const VERSION = '10.48.5'; /** * The base path for the Laravel installation. From bc2a249e24f27199b3b4825562f8c1d325f3c9d8 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 9 Apr 2024 14:55:13 +0000 Subject: [PATCH 106/123] Update CHANGELOG --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bfa90903619..12909848e4c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Release Notes for 10.x -## [Unreleased](https://github.com/laravel/framework/compare/v10.48.4...10.x) +## [Unreleased](https://github.com/laravel/framework/compare/v10.48.5...10.x) + +## [v10.48.5](https://github.com/laravel/framework/compare/v10.48.4...v10.48.5) - 2024-04-09 + +### What's Changed + +* [10.x] Prevent Redis connection error report flood on queue worker by [@kasus](https://github.com/kasus) in https://github.com/laravel/framework/pull/50812 +* [10.x] Laravel 10x optional withSize for hasTable by [@apspan](https://github.com/apspan) in https://github.com/laravel/framework/pull/50888 +* [10.x] Add `serializeAndRestore()` to `NotificationFake` by [@dbpolito](https://github.com/dbpolito) in https://github.com/laravel/framework/pull/50935 ## [v10.48.4](https://github.com/laravel/framework/compare/v10.48.3...v10.48.4) - 2024-03-21 From cc039d5c211a6abe129b00ae5e1f319f83ea6a19 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 9 Apr 2024 16:57:08 +0200 Subject: [PATCH 107/123] Update CHANGELOG.md --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12909848e4c8..c52d6040c23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,6 @@ ## [v10.48.5](https://github.com/laravel/framework/compare/v10.48.4...v10.48.5) - 2024-04-09 -### What's Changed - * [10.x] Prevent Redis connection error report flood on queue worker by [@kasus](https://github.com/kasus) in https://github.com/laravel/framework/pull/50812 * [10.x] Laravel 10x optional withSize for hasTable by [@apspan](https://github.com/apspan) in https://github.com/laravel/framework/pull/50888 * [10.x] Add `serializeAndRestore()` to `NotificationFake` by [@dbpolito](https://github.com/dbpolito) in https://github.com/laravel/framework/pull/50935 From cbcb0ee3da8c5f98497d9a282609732251a7dd1e Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 9 Apr 2024 15:19:11 +0000 Subject: [PATCH 108/123] Update version to v11.3.0 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 2d19ee562fed..161dce41519f 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.2.0'; + const VERSION = '11.3.0'; /** * The base path for the Laravel installation. From 619e7627f823b80964efe8eb9c6350cb932040ed Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 9 Apr 2024 15:23:31 +0000 Subject: [PATCH 109/123] Update CHANGELOG --- CHANGELOG.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe23c2c387a..400989c4aa37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,36 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.2.0...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.3.0...11.x) + +## [v11.3.0](https://github.com/laravel/framework/compare/v11.2.0...v11.3.0) - 2024-04-09 + +* [10.x] Prevent Redis connection error report flood on queue worker by [@kasus](https://github.com/kasus) in https://github.com/laravel/framework/pull/50812 +* [11.x] Optimize SetCacheHeaders to ensure error responses aren't cached by [@MinaWilliam](https://github.com/MinaWilliam) in https://github.com/laravel/framework/pull/50903 +* [11.x] Add session `hasAny` method by [@mahmoudmohamedramadan](https://github.com/mahmoudmohamedramadan) in https://github.com/laravel/framework/pull/50897 +* [11.x] Add option to report throttled exception in ThrottlesExceptions middleware by [@JaZo](https://github.com/JaZo) in https://github.com/laravel/framework/pull/50896 +* [11.x] Add DeleteWhenMissingModels attribute by [@Neol3108](https://github.com/Neol3108) in https://github.com/laravel/framework/pull/50890 +* [11.x] Allow customizing TrimStrings::$except by [@grohiro](https://github.com/grohiro) in https://github.com/laravel/framework/pull/50901 +* [11.x] Add pull methods to Context by [@renegeuze](https://github.com/renegeuze) in https://github.com/laravel/framework/pull/50904 +* [11.x] Remove redundant code from MariaDbGrammar by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/50907 +* [11.x] Explicit nullable parameter declarations to fix PHP 8.4 deprecation by [@Jubeki](https://github.com/Jubeki) in https://github.com/laravel/framework/pull/50922 +* [11.x] Add setters to cache stores by [@stancl](https://github.com/stancl) in https://github.com/laravel/framework/pull/50912 +* [10.x] Laravel 10x optional withSize for hasTable by [@apspan](https://github.com/apspan) in https://github.com/laravel/framework/pull/50888 +* [11.x] Fix prompting for missing array arguments on artisan command by [@macocci7](https://github.com/macocci7) in https://github.com/laravel/framework/pull/50850 +* [11.x] Add strict-mode safe hasAttribute method to Eloquent by [@mateusjatenee](https://github.com/mateusjatenee) in https://github.com/laravel/framework/pull/50909 +* [11.x] add function to get faked events by [@browner12](https://github.com/browner12) in https://github.com/laravel/framework/pull/50905 +* [11.x] `retry` func - catch "Throwable" instead of Exception by [@sethsandaru](https://github.com/sethsandaru) in https://github.com/laravel/framework/pull/50944 +* chore: remove repetitive words by [@findseat](https://github.com/findseat) in https://github.com/laravel/framework/pull/50943 +* [10.x] Add `serializeAndRestore()` to `NotificationFake` by [@dbpolito](https://github.com/dbpolito) in https://github.com/laravel/framework/pull/50935 +* [11.x] Prevent crash when handling ConnectionException in HttpClient retry logic by [@shinsenter](https://github.com/shinsenter) in https://github.com/laravel/framework/pull/50955 +* [11.x] Remove unknown parameters by [@naopusyu](https://github.com/naopusyu) in https://github.com/laravel/framework/pull/50965 +* [11.x] Fixed typo in PHPDoc `[@param](https://github.com/param)` by [@naopusyu](https://github.com/naopusyu) in https://github.com/laravel/framework/pull/50967 +* [11.x] Fix dockblock by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/50979 +* [11.x] Allow time to be faked in database lock by [@JurianArie](https://github.com/JurianArie) in https://github.com/laravel/framework/pull/50981 +* [11.x] Introduce method `Http::createPendingRequest()` by [@Jacobs63](https://github.com/Jacobs63) in https://github.com/laravel/framework/pull/50980 +* [11.x] Add [@throws](https://github.com/throws) to some doc blocks by [@saMahmoudzadeh](https://github.com/saMahmoudzadeh) in https://github.com/laravel/framework/pull/50969 +* [11.x] Fix PHP_MAXPATHLEN check for existing check of files for views by [@joshuaruesweg](https://github.com/joshuaruesweg) in https://github.com/laravel/framework/pull/50962 +* [11.x] Allow to remove scopes from BelongsToMany relation by [@plumthedev](https://github.com/plumthedev) in https://github.com/laravel/framework/pull/50953 +* [11.x] Throw exception if named rate limiter and model property do not exist by [@mateusjatenee](https://github.com/mateusjatenee) in https://github.com/laravel/framework/pull/50908 ## [v11.2.0](https://github.com/laravel/framework/compare/v11.1.1...v11.2.0) - 2024-04-02 From d63d2b1f50b6bbf8beb88b7b4ad5a4d230244443 Mon Sep 17 00:00:00 2001 From: Alexander Zhuravlev Date: Wed, 10 Apr 2024 03:39:59 +1200 Subject: [PATCH 110/123] [11.x] Name of job set by displayName() must be honoured by Schedule (#50973) * Name of job set by displayName() must be honoured by Schedule * formatting --------- Co-authored-by: Taylor Otwell --- .../Console/Scheduling/Schedule.php | 22 ++++--- .../Fixtures/JobToTestWithSchedule.php | 14 +++++ tests/Console/Scheduling/ScheduleTest.php | 62 +++++++++++++++++++ 3 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 tests/Console/Fixtures/JobToTestWithSchedule.php create mode 100644 tests/Console/Scheduling/ScheduleTest.php diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index 684aec58fc4a..65292e2fc16e 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -154,15 +154,19 @@ public function command($command, array $parameters = []) */ public function job($job, $queue = null, $connection = null) { - return $this->call(function () use ($job, $queue, $connection) { - $job = is_string($job) ? Container::getInstance()->make($job) : $job; - - if ($job instanceof ShouldQueue) { - $this->dispatchToQueue($job, $queue ?? $job->queue, $connection ?? $job->connection); - } else { - $this->dispatchNow($job); - } - })->name(is_string($job) ? $job : get_class($job)); + $instance = is_string($job) + ? Container::getInstance()->make($job) + : $job; + + $name = method_exists($instance, 'displayName') + ? $instance->displayName() + : $instance::class; + + return $this->call(function () use ($instance, $queue, $connection) { + $instance instanceof ShouldQueue + ? $this->dispatchToQueue($instance, $queue ?? $instance->queue, $connection ?? $instance->connection) + : $this->dispatchNow($instance); + })->name($name); } /** diff --git a/tests/Console/Fixtures/JobToTestWithSchedule.php b/tests/Console/Fixtures/JobToTestWithSchedule.php new file mode 100644 index 000000000000..78924c79131b --- /dev/null +++ b/tests/Console/Fixtures/JobToTestWithSchedule.php @@ -0,0 +1,14 @@ +container = new Container; + Container::setInstance($this->container); + $this->eventMutex = m::mock(EventMutex::class); + $this->container->instance(EventMutex::class, $this->eventMutex); + $this->schedulingMutex = m::mock(SchedulingMutex::class); + $this->container->instance(SchedulingMutex::class, $this->schedulingMutex); + } + + #[DataProvider('jobHonoursDisplayNameIfMethodExistsProvider')] + public function testJobHonoursDisplayNameIfMethodExists(string|object $job, string $jobName): void + { + $schedule = new Schedule(); + $scheduledJob = $schedule->job($job); + self::assertSame($jobName, $scheduledJob->description); + } + + public static function jobHonoursDisplayNameIfMethodExistsProvider(): array + { + $job = new class implements ShouldQueue + { + public function displayName(): string + { + return 'testJob-123'; + } + }; + + return [ + [JobToTestWithSchedule::class, JobToTestWithSchedule::class], + [new JobToTestWithSchedule, JobToTestWithSchedule::class], + [$job, 'testJob-123'], + ]; + } +} From 6cc951a3f07c21d214a6510f560d5e1b1f21dc86 Mon Sep 17 00:00:00 2001 From: Toby Evans Date: Thu, 11 Apr 2024 01:54:04 +1200 Subject: [PATCH 111/123] Add Conditionable trait to Testing\PendingCommand.php (#50988) --- src/Illuminate/Testing/PendingCommand.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index bf6a3edd5ad2..bbd3d92d6e02 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -8,6 +8,7 @@ use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Arr; +use Illuminate\Support\Traits\Conditionable; use Mockery; use Mockery\Exception\NoMatchingExpectationException; use PHPUnit\Framework\TestCase as PHPUnitTestCase; @@ -18,6 +19,8 @@ class PendingCommand { + use Conditionable; + /** * The test being run. * From e1ccd318b1ddfa2d3a16e1c76563376bbe03da32 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 10 Apr 2024 13:54:25 +0000 Subject: [PATCH 112/123] Apply fixes from StyleCI --- src/Illuminate/Testing/PendingCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index bbd3d92d6e02..5aac2df770c9 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -20,7 +20,7 @@ class PendingCommand { use Conditionable; - + /** * The test being run. * From 8929ee954ef1e4308516c3e09820d3d22d49fb46 Mon Sep 17 00:00:00 2001 From: Fred Bradley Date: Wed, 10 Apr 2024 15:01:31 +0100 Subject: [PATCH 113/123] Allow sorting of route:list by multiple column/factors using a comma (#50998) * feat: allow route:list sorting bymultiple column factors using a comma * fix: code indentation * fix: code indentation again to appease styleci * styleci: add line break before return statement * refactor: use `collect` and `sortBy` methods regardless of using a comma or not * style: used pint to work out what the thing styleci was complaining about was --- src/Illuminate/Foundation/Console/RouteListCommand.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index 11a8c7247cbe..df3126fc0241 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -157,9 +157,13 @@ protected function getRouteInformation(Route $route) */ protected function sortRoutes($sort, array $routes) { - return Arr::sort($routes, function ($route) use ($sort) { - return $route[$sort]; - }); + if (Str::contains($sort, ',')) { + $sort = explode(',', $sort); + } + + return collect($routes) + ->sortBy($sort) + ->toArray(); } /** From b9055973009c1f5a4856e6d170fb28384a3285d2 Mon Sep 17 00:00:00 2001 From: Lonny Kapelushnik Date: Wed, 10 Apr 2024 08:11:27 -0600 Subject: [PATCH 114/123] [10.x] Added eachById and chunkByIdDesc to BelongsToMany (#50991) * Added failing test * Added eachById and chunkByIdDesc to BelongsToMany * Removed extra namespace --- .../Eloquent/Relations/BelongsToMany.php | 55 ++++++- ...baseEloquentBelongsToManyChunkByIdTest.php | 31 ++-- ...abaseEloquentBelongsToManyEachByIdTest.php | 134 ++++++++++++++++++ 3 files changed, 208 insertions(+), 12 deletions(-) create mode 100644 tests/Database/DatabaseEloquentBelongsToManyEachByIdTest.php diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index c0459b4d7267..73152d7e5879 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -997,19 +997,66 @@ public function chunk($count, callable $callback) */ public function chunkById($count, callable $callback, $column = null, $alias = null) { - $this->prepareQueryBuilder(); + return $this->orderedChunkById($count, $callback, $column, $alias); + } + + /** + * Chunk the results of a query by comparing IDs in descending order. + * + * @param int $count + * @param callable $callback + * @param string|null $column + * @param string|null $alias + * @return bool + */ + public function chunkByIdDesc($count, callable $callback, $column = null, $alias = null) + { + return $this->orderedChunkById($count, $callback, $column, $alias, descending: true); + } + /** + * Execute a callback over each item while chunking by ID. + * + * @param callable $callback + * @param int $count + * @param string|null $column + * @param string|null $alias + * @return bool + */ + public function eachById(callable $callback, $count = 1000, $column = null, $alias = null) + { + return $this->chunkById($count, function ($results, $page) use ($callback, $count) { + foreach ($results as $key => $value) { + if ($callback($value, (($page - 1) * $count) + $key) === false) { + return false; + } + } + }, $column, $alias); + } + + /** + * Chunk the results of a query by comparing IDs in a given order. + * + * @param int $count + * @param callable $callback + * @param string|null $column + * @param string|null $alias + * @param bool $descending + * @return bool + */ + public function orderedChunkById($count, callable $callback, $column = null, $alias = null, $descending = false) + { $column ??= $this->getRelated()->qualifyColumn( $this->getRelatedKeyName() ); $alias ??= $this->getRelatedKeyName(); - return $this->query->chunkById($count, function ($results) use ($callback) { + return $this->prepareQueryBuilder()->orderedChunkById($count, function ($results, $page) use ($callback) { $this->hydratePivotRelation($results->all()); - return $callback($results); - }, $column, $alias); + return $callback($results, $page); + }, $column, $alias, $descending); } /** diff --git a/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php b/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php index f35c2f9a3ce9..0b9d8d51d93c 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php @@ -37,13 +37,14 @@ public function createSchema() }); $this->schema()->create('articles', function ($table) { - $table->increments('aid'); + $table->increments('id'); $table->string('title'); }); $this->schema()->create('article_user', function ($table) { + $table->increments('id'); $table->integer('article_id')->unsigned(); - $table->foreign('article_id')->references('aid')->on('articles'); + $table->foreign('article_id')->references('id')->on('articles'); $table->integer('user_id')->unsigned(); $table->foreign('user_id')->references('id')->on('users'); }); @@ -58,7 +59,22 @@ public function testBelongsToChunkById() $user->articles()->chunkById(1, function (Collection $collection) use (&$i) { $i++; - $this->assertEquals($i, $collection->first()->aid); + $this->assertEquals($i, $collection->first()->id); + }); + + $this->assertSame(3, $i); + } + + public function testBelongsToChunkByIdDesc() + { + $this->seedData(); + + $user = BelongsToManyChunkByIdTestTestUser::query()->first(); + $i = 0; + + $user->articles()->chunkByIdDesc(1, function (Collection $collection) use (&$i) { + $this->assertEquals(3 - $i, $collection->first()->id); + $i++; }); $this->assertSame(3, $i); @@ -83,9 +99,9 @@ protected function seedData() { $user = BelongsToManyChunkByIdTestTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); BelongsToManyChunkByIdTestTestArticle::query()->insert([ - ['aid' => 1, 'title' => 'Another title'], - ['aid' => 2, 'title' => 'Another title'], - ['aid' => 3, 'title' => 'Another title'], + ['id' => 1, 'title' => 'Another title'], + ['id' => 2, 'title' => 'Another title'], + ['id' => 3, 'title' => 'Another title'], ]); $user->articles()->sync([3, 1, 2]); @@ -126,10 +142,9 @@ public function articles() class BelongsToManyChunkByIdTestTestArticle extends Eloquent { - protected $primaryKey = 'aid'; protected $table = 'articles'; protected $keyType = 'string'; public $incrementing = false; public $timestamps = false; - protected $fillable = ['aid', 'title']; + protected $fillable = ['id', 'title']; } diff --git a/tests/Database/DatabaseEloquentBelongsToManyEachByIdTest.php b/tests/Database/DatabaseEloquentBelongsToManyEachByIdTest.php new file mode 100644 index 000000000000..0a2fe1e97a06 --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManyEachByIdTest.php @@ -0,0 +1,134 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + /** + * Setup the database schema. + * + * @return void + */ + public function createSchema() + { + $this->schema()->create('users', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + }); + + $this->schema()->create('articles', function ($table) { + $table->increments('id'); + $table->string('title'); + }); + + $this->schema()->create('article_user', function ($table) { + $table->increments('id'); + $table->integer('article_id')->unsigned(); + $table->foreign('article_id')->references('id')->on('articles'); + $table->integer('user_id')->unsigned(); + $table->foreign('user_id')->references('id')->on('users'); + }); + } + + public function testBelongsToEachById() + { + $this->seedData(); + + $user = BelongsToManyEachByIdTestTestUser::query()->first(); + $i = 0; + + $user->articles()->eachById(function (BelongsToManyEachByIdTestTestArticle $model) use (&$i) { + $i++; + $this->assertEquals($i, $model->id); + }); + + $this->assertSame(3, $i); + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + $this->schema()->drop('users'); + $this->schema()->drop('articles'); + $this->schema()->drop('article_user'); + } + + /** + * Helpers... + */ + protected function seedData() + { + $user = BelongsToManyEachByIdTestTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + BelongsToManyEachByIdTestTestArticle::query()->insert([ + ['id' => 1, 'title' => 'Another title'], + ['id' => 2, 'title' => 'Another title'], + ['id' => 3, 'title' => 'Another title'], + ]); + + $user->articles()->sync([3, 1, 2]); + } + + /** + * Get a database connection instance. + * + * @return \Illuminate\Database\ConnectionInterface + */ + protected function connection() + { + return Eloquent::getConnectionResolver()->connection(); + } + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema() + { + return $this->connection()->getSchemaBuilder(); + } +} + +class BelongsToManyEachByIdTestTestUser extends Eloquent +{ + protected $table = 'users'; + protected $fillable = ['id', 'email']; + public $timestamps = false; + + public function articles() + { + return $this->belongsToMany(BelongsToManyEachByIdTestTestArticle::class, 'article_user', 'user_id', 'article_id'); + } +} + +class BelongsToManyEachByIdTestTestArticle extends Eloquent +{ + protected $table = 'articles'; + protected $keyType = 'string'; + public $incrementing = false; + public $timestamps = false; + protected $fillable = ['id', 'title']; +} From 0efb4cbe8d2b55998c826d4c0b1c923a93eb4e13 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Apr 2024 09:40:30 -0500 Subject: [PATCH 115/123] fix chunkByIdDesc on HasManyThrough --- .../Eloquent/Relations/HasManyThrough.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index cf94493c8142..a07bb54d1122 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -601,6 +601,24 @@ public function chunkById($count, callable $callback, $column = null, $alias = n return $this->prepareQueryBuilder()->chunkById($count, $callback, $column, $alias); } + /** + * Chunk the results of a query by comparing IDs in descending order. + * + * @param int $count + * @param callable $callback + * @param string|null $column + * @param string|null $alias + * @return bool + */ + public function chunkByIdDesc($count, callable $callback, $column = null, $alias = null) + { + $column ??= $this->getRelated()->getQualifiedKeyName(); + + $alias ??= $this->getRelated()->getKeyName(); + + return $this->prepareQueryBuilder()->chunkByIdDesc($count, $callback, $column, $alias); + } + /** * Execute a callback over each item while chunking by ID. * From db3fe1b9492d4266b1611c79848d6bfb88c3981e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Apr 2024 09:41:04 -0500 Subject: [PATCH 116/123] fix chunkByIdDesc --- .../Eloquent/Relations/HasManyThrough.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index b0b4b1fdebe1..78ac9018bdd0 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -600,6 +600,24 @@ public function chunkById($count, callable $callback, $column = null, $alias = n return $this->prepareQueryBuilder()->chunkById($count, $callback, $column, $alias); } + /** + * Chunk the results of a query by comparing IDs in descending order. + * + * @param int $count + * @param callable $callback + * @param string|null $column + * @param string|null $alias + * @return bool + */ + public function chunkByIdDesc($count, callable $callback, $column = null, $alias = null) + { + $column ??= $this->getRelated()->getQualifiedKeyName(); + + $alias ??= $this->getRelated()->getKeyName(); + + return $this->prepareQueryBuilder()->chunkByIdDesc($count, $callback, $column, $alias); + } + /** * Execute a callback over each item while chunking by ID. * From 4eadc6c93f879916d7614dd5a62831d32834c639 Mon Sep 17 00:00:00 2001 From: driesvints Date: Wed, 10 Apr 2024 14:47:03 +0000 Subject: [PATCH 117/123] Update version to v10.48.6 --- 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 9649f34af55b..1aa5d18bb8ac 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -40,7 +40,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '10.48.5'; + const VERSION = '10.48.6'; /** * The base path for the Laravel installation. From ae6dc85bf7697e0dba225704800b2140dc3971d0 Mon Sep 17 00:00:00 2001 From: driesvints Date: Wed, 10 Apr 2024 14:49:13 +0000 Subject: [PATCH 118/123] Update CHANGELOG --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c52d6040c23e..03bbdc08f3f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Release Notes for 10.x -## [Unreleased](https://github.com/laravel/framework/compare/v10.48.5...10.x) +## [Unreleased](https://github.com/laravel/framework/compare/v10.48.6...10.x) + +## [v10.48.6](https://github.com/laravel/framework/compare/v10.48.5...v10.48.6) - 2024-04-10 + +* [10.x] Added eachById and chunkByIdDesc to BelongsToMany by [@lonnylot](https://github.com/lonnylot) in https://github.com/laravel/framework/pull/50991 ## [v10.48.5](https://github.com/laravel/framework/compare/v10.48.4...v10.48.5) - 2024-04-09 From d56a3c286d82b6552d6ee389a025780c5cbb0366 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Apr 2024 09:52:18 -0500 Subject: [PATCH 119/123] fix lazyByIdDesc --- .../Eloquent/Relations/BelongsToMany.php | 23 +++++++++++++++++++ .../Eloquent/Relations/HasManyThrough.php | 17 ++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 91c12d8b9715..064edbdd2577 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -1116,6 +1116,29 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null) }); } + /** + * Query lazily, by chunking the results of a query by comparing IDs in descending order. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) + { + $column ??= $this->getRelated()->qualifyColumn( + $this->getRelatedKeyName() + ); + + $alias ??= $this->getRelatedKeyName(); + + return $this->prepareQueryBuilder()->lazyByIdDesc($chunkSize, $column, $alias)->map(function ($model) { + $this->hydratePivotRelation([$model]); + + return $model; + }); + } + /** * Get a lazy collection for the given query. * diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index a07bb54d1122..ab3d19fa4e9e 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -693,6 +693,23 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null) return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias); } + /** + * Query lazily, by chunking the results of a query by comparing IDs in descending order. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) + { + $column ??= $this->getRelated()->getQualifiedKeyName(); + + $alias ??= $this->getRelated()->getKeyName(); + + return $this->prepareQueryBuilder()->lazyByIdDesc($chunkSize, $column, $alias); + } + /** * Prepare the query builder for query execution. * From 95ef230339b15321493a08327f250c0760c95376 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Apr 2024 09:54:00 -0500 Subject: [PATCH 120/123] fix more query builder methods --- .../Eloquent/Relations/BelongsToMany.php | 23 +++++++++++++++++++ .../Eloquent/Relations/HasManyThrough.php | 17 ++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 73152d7e5879..0f93ee7e390c 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -1115,6 +1115,29 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null) }); } + /** + * Query lazily, by chunking the results of a query by comparing IDs in descending order. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) + { + $column ??= $this->getRelated()->qualifyColumn( + $this->getRelatedKeyName() + ); + + $alias ??= $this->getRelatedKeyName(); + + return $this->prepareQueryBuilder()->lazyByIdDesc($chunkSize, $column, $alias)->map(function ($model) { + $this->hydratePivotRelation([$model]); + + return $model; + }); + } + /** * Get a lazy collection for the given query. * diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 78ac9018bdd0..20c34749efba 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -692,6 +692,23 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null) return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias); } + /** + * Query lazily, by chunking the results of a query by comparing IDs in descending order. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + */ + public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) + { + $column ??= $this->getRelated()->getQualifiedKeyName(); + + $alias ??= $this->getRelated()->getKeyName(); + + return $this->prepareQueryBuilder()->lazyByIdDesc($chunkSize, $column, $alias); + } + /** * Prepare the query builder for query execution. * From 118c686992f4b90d4da6deaf0901315c337bbaf9 Mon Sep 17 00:00:00 2001 From: driesvints Date: Wed, 10 Apr 2024 14:57:20 +0000 Subject: [PATCH 121/123] Update version to v10.48.7 --- 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 1aa5d18bb8ac..f8db2b718375 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -40,7 +40,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '10.48.6'; + const VERSION = '10.48.7'; /** * The base path for the Laravel installation. From 3b87d0767e9cbddec46480d883010ba720e50dea Mon Sep 17 00:00:00 2001 From: driesvints Date: Wed, 10 Apr 2024 15:13:49 +0000 Subject: [PATCH 122/123] Update version to v11.3.1 --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 161dce41519f..1034923b40f2 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -45,7 +45,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '11.3.0'; + const VERSION = '11.3.1'; /** * The base path for the Laravel installation. From fd9fa8919052d8405b1a6f0c1ed6d21e64026277 Mon Sep 17 00:00:00 2001 From: driesvints Date: Wed, 10 Apr 2024 15:16:36 +0000 Subject: [PATCH 123/123] Update CHANGELOG --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 400989c4aa37..a978a09c7a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.3.0...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.3.1...11.x) + +## [v11.3.1](https://github.com/laravel/framework/compare/v11.3.0...v11.3.1) - 2024-04-10 + +* [11.x] Name of job set by displayName() must be honoured by Schedule by [@SCIF](https://github.com/SCIF) in https://github.com/laravel/framework/pull/50973 +* Add Conditionable trait to Testing\PendingCommand.php by [@tobz-nz](https://github.com/tobz-nz) in https://github.com/laravel/framework/pull/50988 +* Allow sorting of route:list by multiple column/factors using a comma by [@fredbradley](https://github.com/fredbradley) in https://github.com/laravel/framework/pull/50998 +* [10.x] Added eachById and chunkByIdDesc to BelongsToMany by [@lonnylot](https://github.com/lonnylot) in https://github.com/laravel/framework/pull/50991 ## [v11.3.0](https://github.com/laravel/framework/compare/v11.2.0...v11.3.0) - 2024-04-09