diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b6df29a5b70cc59fb37b4c302ec8736f03d4c3e..8a4c7a4c7be49be0af99bdd9451d48f5cfb01ce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ # Release Notes for 11.x -## [Unreleased](https://github.com/laravel/framework/compare/v11.43.2...11.x) +## [Unreleased](https://github.com/laravel/framework/compare/v11.44.1...11.x) + +## [v11.44.1](https://github.com/laravel/framework/compare/v11.44.0...v11.44.1) - 2025-03-05 + +* [11.x] Add valid values to ensure method by [@lancepioch](https://github.com/lancepioch) in https://github.com/laravel/framework/pull/54840 +* Fix attribute name used on `Validator` instance within certain rule classes by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54845 +* [11.x] Fix `Application::interBasePath()` fails to resolve application when project name is "vendor" by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54871 +* [11.x] Test improvements by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54879 + +## [v11.44.0](https://github.com/laravel/framework/compare/v11.43.2...v11.44.0) - 2025-02-24 + +* [11.x] Fix parsing `PHP_CLI_SERVER_WORKERS` as `string` instead of `int` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/54724 +* [11.x] Rename Redis parse connection for cluster test method to follow naming conventions by [@jackbayliss](https://github.com/jackbayliss) in https://github.com/laravel/framework/pull/54721 +* [11.x] Allow `readAt` method to use in database channel by [@utsavsomaiya](https://github.com/utsavsomaiya) in https://github.com/laravel/framework/pull/54729 +* [11.x] Fix: Custom Exceptions with Multiple Arguments does not properly rein… by [@pandiselvamm](https://github.com/pandiselvamm) in https://github.com/laravel/framework/pull/54705 +* [11.x] Update ConcurrencyTest exception reference to use namespace by [@jackbayliss](https://github.com/jackbayliss) in https://github.com/laravel/framework/pull/54732 +* [11.x] Deprecate `Factory::$modelNameResolver` by [@samlev](https://github.com/samlev) in https://github.com/laravel/framework/pull/54736 +* [11x.] Improved typehints for `InteractsWithDatabase` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54748 +* [11.x] Improved typehints for `InteractsWithExceptionHandling` && `ExceptionHandlerFake` by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/54747 ## [v11.43.2](https://github.com/laravel/framework/compare/v11.43.1...v11.43.2) - 2025-02-19 diff --git a/composer.json b/composer.json index cf2c2589ce8fb3266ff3b41c13539ce548a7687b..282d9ff0aa8da951ac3868cddfd5f361c64460aa 100644 --- a/composer.json +++ b/composer.json @@ -111,7 +111,7 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^9.9.4", + "orchestra/testbench-core": "^9.11.2", "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index ce3c302038b9f3ee3a2a5f97a1bc064e61c45fcc..55c7110942dad0237a11185fabb36ea05cb54740 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -342,7 +342,7 @@ trait EnumeratesValues * * @template TEnsureOfType * - * @param class-string<TEnsureOfType>|array<array-key, class-string<TEnsureOfType>> $type + * @param class-string<TEnsureOfType>|array<array-key, class-string<TEnsureOfType>>|'string'|'int'|'float'|'bool'|'array'|'null' $type * @return static<TKey, TEnsureOfType> * * @throws \UnexpectedValueException diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 1c27bb2ff7739e60443955095eaf393c9bb364f7..57baa3a6801f5c2127d9ee8be443a2c9f44fd94d 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1018,7 +1018,7 @@ class Builder implements BuilderContract * @param string $pageName * @param int|null $page * @param \Closure|int|null $total - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index c6162d7656a88a8660dccf6eee15b0c005eb8243..a9acf90fb68f6d46e4f0e12df7eca7936e5cd7c9 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -674,7 +674,7 @@ trait QueriesRelationships $models->groupBy(fn ($model) => $model->getMorphClass())->each(function ($models) use ($query, $relation) { $query->orWhere(function ($query) use ($relation, $models) { $query->where($relation->qualifyColumn($relation->getMorphType()), '<=>', $models->first()->getMorphClass()) - ->whereNotIn($relation->qualifyColumn($relation->getForeignKeyName()), $models->map->getKey()); + ->whereIn($relation->qualifyColumn($relation->getForeignKeyName()), $models->map->getKey()); }); }); }, null, null, $boolean); diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 7019cf49c06953fec293a4e06858396788c166f0..5618f0190f514e256a03c513fcb26ae9a7c66280 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -938,7 +938,7 @@ class BelongsToMany extends Relation * @param array $columns * @param string $pageName * @param int|null $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index 6e74acf74651f6116ba8d3acbda8a0d58eb2d549..72a65b0c1f5b02d0ff015c461b8ae48604b24a75 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -468,7 +468,7 @@ abstract class HasOneOrManyThrough extends Relation * @param array $columns * @param string $pageName * @param int $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 538994fe4b2536c93bea9f288b13d72063b9c7cf..d6d9fd07b445ece09998d32ea0854a5cc038363a 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3142,7 +3142,7 @@ class Builder implements BuilderContract * @param string $pageName * @param int|null $page * @param \Closure|int|null $total - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null, $total = null) { diff --git a/src/Illuminate/Database/Seeder.php b/src/Illuminate/Database/Seeder.php index bfb48aedf3b0cb87f19516d847f6810e6954b6ba..08e57b2d7834817b7795421e49c1336f0b858b6a 100755 --- a/src/Illuminate/Database/Seeder.php +++ b/src/Illuminate/Database/Seeder.php @@ -110,11 +110,15 @@ abstract class Seeder */ public function callOnce($class, $silent = false, array $parameters = []) { - if (in_array($class, static::$called)) { - return; - } + $classes = Arr::wrap($class); + + foreach ($classes as $class) { + if (in_array($class, static::$called)) { + continue; + } - $this->call($class, $silent, $parameters); + $this->call($class, $silent, $parameters); + } } /** diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index cc9783289be0c3771a51a4a42a33a9fbb0e8a643..be7345c8ef2894aa65eea14dd0f127aa64733470 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.44.0'; + const VERSION = '11.44.2'; /** * The base path for the Laravel installation. @@ -257,7 +257,7 @@ class Application extends Container implements ApplicationContract, CachesConfig isset($_ENV['APP_BASE_PATH']) => $_ENV['APP_BASE_PATH'], default => dirname(array_values(array_filter( array_keys(ClassLoader::getRegisteredLoaders()), - fn ($path) => ! str_contains($path, '/vendor/'), + fn ($path) => ! str_starts_with($path, 'phar://'), ))[0]), }; } diff --git a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php index 526a764ede89da0afa3beefb67da00fd02d7a67f..1a81720b0752c3f4b0e83d448114e77834f4c18f 100644 --- a/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php +++ b/src/Illuminate/Redis/Connections/PacksPhpRedisValues.php @@ -95,26 +95,26 @@ trait PacksPhpRedisValues $oldSerializer = null; if ($this->serialized()) { - $oldSerializer = $client->getOption($client::OPT_SERIALIZER); - $client->setOption($client::OPT_SERIALIZER, $client::SERIALIZER_NONE); + $oldSerializer = $client->getOption(Redis::OPT_SERIALIZER); + $client->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); } $oldCompressor = null; if ($this->compressed()) { - $oldCompressor = $client->getOption($client::OPT_COMPRESSION); - $client->setOption($client::OPT_COMPRESSION, $client::COMPRESSION_NONE); + $oldCompressor = $client->getOption(Redis::OPT_COMPRESSION); + $client->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE); } try { return $callback(); } finally { if ($oldSerializer !== null) { - $client->setOption($client::OPT_SERIALIZER, $oldSerializer); + $client->setOption(Redis::OPT_SERIALIZER, $oldSerializer); } if ($oldCompressor !== null) { - $client->setOption($client::OPT_COMPRESSION, $oldCompressor); + $client->setOption(Redis::OPT_COMPRESSION, $oldCompressor); } } } diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 557ab19f57a25ea78bd024a1024f5e4728960227..21cb2e7273819b3a352ee065adf082855dbe97ab 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -307,11 +307,11 @@ class Validator implements ValidatorContract protected $defaultNumericRules = ['Numeric', 'Integer', 'Decimal']; /** - * The current placeholder for dots in rule keys. + * The current random hash for the validator. * * @var string */ - protected $dotPlaceholder; + protected static $placeholderHash; /** * The exception to throw upon failure. @@ -344,7 +344,9 @@ class Validator implements ValidatorContract array $messages = [], array $attributes = [], ) { - $this->dotPlaceholder = Str::random(); + if (! isset(static::$placeholderHash)) { + static::$placeholderHash = Str::random(); + } $this->initialRules = $rules; $this->translator = $translator; @@ -372,7 +374,7 @@ class Validator implements ValidatorContract $key = str_replace( ['.', '*'], - [$this->dotPlaceholder, '__asterisk__'], + ['__dot__'.static::$placeholderHash, '__asterisk__'.static::$placeholderHash], $key ); @@ -410,7 +412,7 @@ class Validator implements ValidatorContract protected function replacePlaceholderInString(string $value) { return str_replace( - [$this->dotPlaceholder, '__asterisk__'], + ['__dot__'.static::$placeholderHash, '__asterisk__'.static::$placeholderHash], ['.', '*'], $value ); @@ -419,13 +421,13 @@ class Validator implements ValidatorContract /** * Replace each field parameter dot placeholder with dot. * - * @param string $value - * @return string + * @param array $parameters + * @return array */ protected function replaceDotPlaceholderInParameters(array $parameters) { return array_map(function ($field) { - return str_replace($this->dotPlaceholder, '.', $field); + return str_replace('__dot__'.static::$placeholderHash, '.', $field); }, $parameters); } @@ -746,7 +748,7 @@ class Validator implements ValidatorContract protected function replaceDotInParameters(array $parameters) { return array_map(function ($field) { - return str_replace('\.', $this->dotPlaceholder, $field); + return str_replace('\.', '__dot__'.static::$placeholderHash, $field); }, $parameters); } @@ -872,11 +874,24 @@ class Validator implements ValidatorContract */ protected function validateUsingCustomRule($attribute, $value, $rule) { - $attribute = $this->replacePlaceholderInString($attribute); + $originalAttribute = $this->replacePlaceholderInString($attribute); + + $attribute = match (true) { + $rule instanceof Rules\Email => $attribute, + $rule instanceof Rules\File => $attribute, + $rule instanceof Rules\Password => $attribute, + default => $originalAttribute, + }; $value = is_array($value) ? $this->replacePlaceholders($value) : $value; if ($rule instanceof ValidatorAwareRule) { + if ($attribute !== $originalAttribute) { + $this->addCustomAttributes([ + $attribute => $this->customAttributes[$originalAttribute] ?? $originalAttribute, + ]); + } + $rule->setValidator($this); } @@ -889,14 +904,14 @@ class Validator implements ValidatorContract get_class($rule->invokable()) : get_class($rule); - $this->failedRules[$attribute][$ruleClass] = []; + $this->failedRules[$originalAttribute][$ruleClass] = []; - $messages = $this->getFromLocalArray($attribute, $ruleClass) ?? $rule->message(); + $messages = $this->getFromLocalArray($originalAttribute, $ruleClass) ?? $rule->message(); $messages = $messages ? (array) $messages : [$ruleClass]; foreach ($messages as $key => $message) { - $key = is_string($key) ? $key : $attribute; + $key = is_string($key) ? $key : $originalAttribute; $this->messages->add($key, $this->makeReplacements( $message, $key, $ruleClass, [] @@ -1189,7 +1204,7 @@ class Validator implements ValidatorContract { return (new Collection($this->rules)) ->mapWithKeys(fn ($value, $key) => [ - str_replace($this->dotPlaceholder, '\\.', $key) => $value, + str_replace('__dot__'.static::$placeholderHash, '\\.', $key) => $value, ]) ->all(); } @@ -1203,7 +1218,7 @@ class Validator implements ValidatorContract public function setRules(array $rules) { $rules = (new Collection($rules))->mapWithKeys(function ($value, $key) { - return [str_replace('\.', $this->dotPlaceholder, $key) => $value]; + return [str_replace('\.', '__dot__'.static::$placeholderHash, $key) => $value]; })->toArray(); $this->initialRules = $rules; diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 60daa61f0bcc945506ccf8793d6111540236b7b3..ad0c86122a9f27b9da0e8b95524b02dc4a441be4 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -1837,7 +1837,7 @@ class DatabaseEloquentBuilderTest extends TestCase $builder = $model->whereNotMorphedTo('morph', $relatedModel); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals([$relatedModel->getMorphClass(), $relatedModel->getKey()], $builder->getBindings()); } @@ -1854,7 +1854,7 @@ class DatabaseEloquentBuilderTest extends TestCase $builder = $model->whereNotMorphedTo('morph', new Collection([$firstRelatedModel, $secondRelatedModel])); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)))', $builder->toSql()); $this->assertEquals([$firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $secondRelatedModel->getKey()], $builder->getBindings()); } @@ -1874,7 +1874,7 @@ class DatabaseEloquentBuilderTest extends TestCase $builder = $model->whereNotMorphedTo('morph', [$firstRelatedModel, $secondRelatedModel, $thirdRelatedModel]); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals([$firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $thirdRelatedModel->getKey(), $secondRelatedModel->getMorphClass(), $secondRelatedModel->id], $builder->getBindings()); } @@ -1950,7 +1950,7 @@ class DatabaseEloquentBuilderTest extends TestCase $builder = $model->where('bar', 'baz')->orWhereNotMorphedTo('morph', $relatedModel); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals(['baz', $relatedModel->getMorphClass(), $relatedModel->getKey()], $builder->getBindings()); } @@ -1967,7 +1967,7 @@ class DatabaseEloquentBuilderTest extends TestCase $builder = $model->where('bar', 'baz')->orWhereNotMorphedTo('morph', new Collection([$firstRelatedModel, $secondRelatedModel])); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)))', $builder->toSql()); $this->assertEquals(['baz', $firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $secondRelatedModel->getKey()], $builder->getBindings()); } @@ -1987,7 +1987,7 @@ class DatabaseEloquentBuilderTest extends TestCase $builder = $model->where('bar', 'baz')->orWhereNotMorphedTo('morph', [$firstRelatedModel, $secondRelatedModel, $thirdRelatedModel]); - $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" not in (?)))', $builder->toSql()); + $this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or not (("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?, ?)) or ("eloquent_builder_test_model_parent_stubs"."morph_type" <=> ? and "eloquent_builder_test_model_parent_stubs"."morph_id" in (?)))', $builder->toSql()); $this->assertEquals(['baz', $firstRelatedModel->getMorphClass(), $firstRelatedModel->getKey(), $thirdRelatedModel->getKey(), $secondRelatedModel->getMorphClass(), $secondRelatedModel->id], $builder->getBindings()); } diff --git a/tests/Integration/Cache/DynamoDbStoreTest.php b/tests/Integration/Cache/DynamoDbStoreTest.php index b465cc61ea0e937b894bf675c838d0a1a51f346c..7abe70d2786459df3081643b0458d3e48927e777 100644 --- a/tests/Integration/Cache/DynamoDbStoreTest.php +++ b/tests/Integration/Cache/DynamoDbStoreTest.php @@ -65,7 +65,7 @@ class DynamoDbStoreTest extends TestCase * @param \Illuminate\Foundation\Application $app * @return void */ - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { if (! env('DYNAMODB_CACHE_TABLE')) { $this->markTestSkipped('DynamoDB not configured.'); diff --git a/tests/Integration/Cookie/CookieTest.php b/tests/Integration/Cookie/CookieTest.php index bc52526303761f974c520132af29eec86a672667..ed5223022a91ff960bad3d9d1ca42025c9a94292 100644 --- a/tests/Integration/Cookie/CookieTest.php +++ b/tests/Integration/Cookie/CookieTest.php @@ -42,7 +42,7 @@ class CookieTest extends TestCase $this->assertEquals(Carbon::now()->getTimestamp() + 60, $response->headers->getCookies()[1]->getExpiresTime()); } - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app->instance( ExceptionHandler::class, diff --git a/tests/Integration/Database/EloquentTransactionWithAfterCommitUsingDatabaseTransactionsTest.php b/tests/Integration/Database/EloquentTransactionWithAfterCommitUsingDatabaseTransactionsTest.php index 25a8b27a72cc0a25d6d67db3a86f392dd2853dd2..620df3d0b9c77cc55630156f7097316573328e8e 100644 --- a/tests/Integration/Database/EloquentTransactionWithAfterCommitUsingDatabaseTransactionsTest.php +++ b/tests/Integration/Database/EloquentTransactionWithAfterCommitUsingDatabaseTransactionsTest.php @@ -32,7 +32,7 @@ class EloquentTransactionWithAfterCommitUsingDatabaseTransactionsTest extends Te } } - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $connection = $app->make('config')->get('database.default'); diff --git a/tests/Integration/Database/MariaDb/DatabaseEmulatePreparesMariaDbConnectionTest.php b/tests/Integration/Database/MariaDb/DatabaseEmulatePreparesMariaDbConnectionTest.php index 8c155518dcb565011945ee1fecc1b3a6316ed752..451fd3a1bd6994a82db0dad502d4ec55f6cc2ea9 100755 --- a/tests/Integration/Database/MariaDb/DatabaseEmulatePreparesMariaDbConnectionTest.php +++ b/tests/Integration/Database/MariaDb/DatabaseEmulatePreparesMariaDbConnectionTest.php @@ -10,9 +10,9 @@ use PHPUnit\Framework\Attributes\RequiresPhpExtension; #[RequiresPhpExtension('pdo_mysql')] class DatabaseEmulatePreparesMariaDbConnectionTest extends DatabaseMariaDbConnectionTest { - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { - parent::getEnvironmentSetUp($app); + parent::defineEnvironment($app); $app['config']->set('database.connections.mariadb.options', [ PDO::ATTR_EMULATE_PREPARES => true, diff --git a/tests/Integration/Database/MySql/DatabaseEmulatePreparesMySqlConnectionTest.php b/tests/Integration/Database/MySql/DatabaseEmulatePreparesMySqlConnectionTest.php index 62592a40486f388a0cf3760c3f6672b95c8bce4c..a67d747945e7c9390bd71ac5d47d87cf44d9e122 100755 --- a/tests/Integration/Database/MySql/DatabaseEmulatePreparesMySqlConnectionTest.php +++ b/tests/Integration/Database/MySql/DatabaseEmulatePreparesMySqlConnectionTest.php @@ -10,9 +10,9 @@ use PHPUnit\Framework\Attributes\RequiresPhpExtension; #[RequiresPhpExtension('pdo_mysql')] class DatabaseEmulatePreparesMySqlConnectionTest extends DatabaseMySqlConnectionTest { - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { - parent::getEnvironmentSetUp($app); + parent::defineEnvironment($app); $app['config']->set('database.connections.mysql.options', [ PDO::ATTR_EMULATE_PREPARES => true, diff --git a/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php b/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php index 4f64c21fbc800e5ed9766b565c79e7729cc4fee5..bfcf439d74acdecf62141915de2b9d3e781b6993 100644 --- a/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php +++ b/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php @@ -13,9 +13,9 @@ use PHPUnit\Framework\Attributes\RequiresPhpExtension; #[RequiresPhpExtension('pdo_pgsql')] class PostgresSchemaBuilderTest extends PostgresTestCase { - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { - parent::getEnvironmentSetUp($app); + parent::defineEnvironment($app); $app['config']->set('database.connections.pgsql.search_path', 'public,private'); } diff --git a/tests/Integration/Mail/SendingMarkdownMailTest.php b/tests/Integration/Mail/SendingMarkdownMailTest.php index 591b7264f60a9b51fb7c5d8e31920fe64d68231c..43ecd156646d71d55f55439bf9baa3b87c54b16f 100644 --- a/tests/Integration/Mail/SendingMarkdownMailTest.php +++ b/tests/Integration/Mail/SendingMarkdownMailTest.php @@ -12,7 +12,7 @@ use Orchestra\Testbench\TestCase; class SendingMarkdownMailTest extends TestCase { - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app['config']->set('mail.driver', 'array'); diff --git a/tests/Integration/Mail/SendingQueuedMailTest.php b/tests/Integration/Mail/SendingQueuedMailTest.php index 6f982043ce65f4b88109fef3074eb03d083d6190..e20a44659cbbdf1457aaf1b6e8470adfabf0c7cd 100644 --- a/tests/Integration/Mail/SendingQueuedMailTest.php +++ b/tests/Integration/Mail/SendingQueuedMailTest.php @@ -11,7 +11,7 @@ use Orchestra\Testbench\TestCase; class SendingQueuedMailTest extends TestCase { - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app['config']->set('mail.driver', 'array'); diff --git a/tests/Integration/Queue/JobEncryptionTest.php b/tests/Integration/Queue/JobEncryptionTest.php index 704c080010745b888e52af92927858d272eb76ec..85701d51871fb505fa1f38dc14b559bac93f2c41 100644 --- a/tests/Integration/Queue/JobEncryptionTest.php +++ b/tests/Integration/Queue/JobEncryptionTest.php @@ -21,9 +21,9 @@ class JobEncryptionTest extends DatabaseTestCase { use DatabaseMigrations; - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { - parent::getEnvironmentSetUp($app); + parent::defineEnvironment($app); $app['config']->set('app.key', Str::random(32)); $app['config']->set('queue.default', 'database'); diff --git a/tests/Integration/Queue/ModelSerializationTest.php b/tests/Integration/Queue/ModelSerializationTest.php index 359bbff8fa84ec8a3551caf1e56106f5bb42fe9e..bd3b401c6576521813ef9ef92ca7540b61cbbe52 100644 --- a/tests/Integration/Queue/ModelSerializationTest.php +++ b/tests/Integration/Queue/ModelSerializationTest.php @@ -18,7 +18,7 @@ class ModelSerializationTest extends TestCase { use RefreshDatabase; - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app['config']->set('database.connections.custom', [ 'driver' => 'sqlite', diff --git a/tests/Integration/Queue/QueueConnectionTest.php b/tests/Integration/Queue/QueueConnectionTest.php index 1ae5f1ef9083e0c21a98cf855cac54c09b2d02d5..7ad7722499a4b3000ec5f2e13070e6f3077987dd 100644 --- a/tests/Integration/Queue/QueueConnectionTest.php +++ b/tests/Integration/Queue/QueueConnectionTest.php @@ -8,17 +8,14 @@ use Illuminate\Database\DatabaseTransactionsManager; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Support\Facades\Bus; use Mockery as m; +use Orchestra\Testbench\Attributes\WithConfig; use Orchestra\Testbench\TestCase; use Throwable; +#[WithConfig('queue.default', 'sqs')] +#[WithConfig('queue.connections.sqs.after_commit', true)] class QueueConnectionTest extends TestCase { - protected function getEnvironmentSetUp($app) - { - $app['config']->set('queue.default', 'sqs'); - $app['config']->set('queue.connections.sqs.after_commit', true); - } - protected function tearDown(): void { QueueConnectionTestJob::$ran = false; diff --git a/tests/Integration/Validation/Rules/EmailValidationTest.php b/tests/Integration/Validation/Rules/EmailValidationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..558bef77a9729f6d73a25734a977dcb6912d3c07 --- /dev/null +++ b/tests/Integration/Validation/Rules/EmailValidationTest.php @@ -0,0 +1,49 @@ +<?php + +namespace Illuminate\Tests\Integration\Validation\Rules; + +use Illuminate\Support\Facades\Validator; +use Illuminate\Validation\Rules\Email; +use Orchestra\Testbench\TestCase; +use PHPUnit\Framework\Attributes\TestWith; + +class EmailValidationTest extends TestCase +{ + #[TestWith(['0'])] + #[TestWith(['.'])] + #[TestWith(['*'])] + #[TestWith(['__asterisk__'])] + public function test_it_can_validate_attribute_as_array(string $attribute) + { + $validator = Validator::make([ + 'emails' => [ + $attribute => 'taylor@laravel.com', + ], + ], [ + 'emails.*' => ['required', Email::default()->rfcCompliant()], + ]); + + $this->assertTrue($validator->passes()); + } + + #[TestWith(['0'])] + #[TestWith(['.'])] + #[TestWith(['*'])] + #[TestWith(['__asterisk__'])] + public function test_it_can_validate_attribute_as_array_when_validation_should_fails(string $attribute) + { + $validator = Validator::make([ + 'emails' => [ + $attribute => 'taylor[at]laravel.com', + ], + ], [ + 'emails.*' => ['required', Email::default()->rfcCompliant()], + ]); + + $this->assertFalse($validator->passes()); + + $this->assertSame([ + 0 => __('validation.email', ['attribute' => sprintf('emails.%s', str_replace('_', ' ', $attribute))]), + ], $validator->messages()->all()); + } +} diff --git a/tests/Integration/Validation/Rules/FileValidationTest.php b/tests/Integration/Validation/Rules/FileValidationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ba0d54920e46b3ea153ca201cb1d5c771f15141e --- /dev/null +++ b/tests/Integration/Validation/Rules/FileValidationTest.php @@ -0,0 +1,54 @@ +<?php + +namespace Illuminate\Tests\Integration\Validation\Rules; + +use Illuminate\Http\UploadedFile; +use Illuminate\Support\Facades\Validator; +use Illuminate\Validation\Rules\File; +use Orchestra\Testbench\TestCase; +use PHPUnit\Framework\Attributes\TestWith; + +class FileValidationTest extends TestCase +{ + #[TestWith(['0'])] + #[TestWith(['.'])] + #[TestWith(['*'])] + #[TestWith(['__asterisk__'])] + public function test_it_can_validate_attribute_as_array(string $attribute) + { + $file = UploadedFile::fake()->create('laravel.png', 1, 'image/png'); + + $validator = Validator::make([ + 'files' => [ + $attribute => $file, + ], + ], [ + 'files.*' => ['required', File::types(['image/png', 'image/jpeg'])], + ]); + + $this->assertTrue($validator->passes()); + } + + #[TestWith(['0'])] + #[TestWith(['.'])] + #[TestWith(['*'])] + #[TestWith(['__asterisk__'])] + public function test_it_can_validate_attribute_as_array_when_validation_should_fails(string $attribute) + { + $file = UploadedFile::fake()->create('laravel.php', 1, 'image/php'); + + $validator = Validator::make([ + 'files' => [ + $attribute => $file, + ], + ], [ + 'files.*' => ['required', File::types($mimes = ['image/png', 'image/jpeg'])], + ]); + + $this->assertFalse($validator->passes()); + + $this->assertSame([ + 0 => __('validation.mimetypes', ['attribute' => sprintf('files.%s', str_replace('_', ' ', $attribute)), 'values' => implode(', ', $mimes)]), + ], $validator->messages()->all()); + } +} diff --git a/tests/Integration/Validation/Rules/PasswordValidationTest.php b/tests/Integration/Validation/Rules/PasswordValidationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e1f7672ac89b33cfa3ee3796e30eb4a83c2ad294 --- /dev/null +++ b/tests/Integration/Validation/Rules/PasswordValidationTest.php @@ -0,0 +1,49 @@ +<?php + +namespace Illuminate\Tests\Integration\Validation\Rules; + +use Illuminate\Support\Facades\Validator; +use Illuminate\Validation\Rules\Password; +use Orchestra\Testbench\TestCase; +use PHPUnit\Framework\Attributes\TestWith; + +class PasswordValidationTest extends TestCase +{ + #[TestWith(['0'])] + #[TestWith(['.'])] + #[TestWith(['*'])] + #[TestWith(['__asterisk__'])] + public function test_it_can_validate_attribute_as_array(string $attribute) + { + $validator = Validator::make([ + 'passwords' => [ + $attribute => 'secret', + ], + ], [ + 'passwords.*' => ['required', Password::default()->min(6)], + ]); + + $this->assertTrue($validator->passes()); + } + + #[TestWith(['0'])] + #[TestWith(['.'])] + #[TestWith(['*'])] + #[TestWith(['__asterisk__'])] + public function test_it_can_validate_attribute_as_array_when_validation_should_fails(string $attribute) + { + $validator = Validator::make([ + 'passwords' => [ + $attribute => 'secret', + ], + ], [ + 'passwords.*' => ['required', Password::default()->min(8)], + ]); + + $this->assertFalse($validator->passes()); + + $this->assertSame([ + 0 => sprintf('The passwords.%s field must be at least 8 characters.', str_replace('_', ' ', $attribute)), + ], $validator->messages()->all()); + } +} diff --git a/tests/Integration/View/BladeAnonymousComponentTest.php b/tests/Integration/View/BladeAnonymousComponentTest.php index eb29765dae031fb6ac1c7bdc52b44190bf5e173c..0281de48d80f64e9aa0194aedc1049be6f7b17eb 100644 --- a/tests/Integration/View/BladeAnonymousComponentTest.php +++ b/tests/Integration/View/BladeAnonymousComponentTest.php @@ -41,7 +41,7 @@ class BladeAnonymousComponentTest extends TestCase $view = View::make('panel')->render(); } - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app['config']->set('view.paths', [__DIR__.'/anonymous-components-templates']); } diff --git a/tests/Integration/View/BladeTest.php b/tests/Integration/View/BladeTest.php index 7a08d43fd0b35ab642d87db1fdbf56b53b1ba515..6495175337c450f30664db0b26200d897253039d 100644 --- a/tests/Integration/View/BladeTest.php +++ b/tests/Integration/View/BladeTest.php @@ -210,7 +210,7 @@ class BladeTest extends TestCase $this->artisan('view:clear'); } - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app['config']->set('view.paths', [__DIR__.'/templates']); } diff --git a/tests/Integration/View/RenderableViewExceptionTest.php b/tests/Integration/View/RenderableViewExceptionTest.php index 93c91cb31387e403ffcc1419885afc11888145a4..f5ed176e26f4a656f6170bd34cec0f7333b99c5c 100644 --- a/tests/Integration/View/RenderableViewExceptionTest.php +++ b/tests/Integration/View/RenderableViewExceptionTest.php @@ -21,7 +21,7 @@ class RenderableViewExceptionTest extends TestCase $response->assertSee('This is a renderable exception.'); } - protected function getEnvironmentSetUp($app) + protected function defineEnvironment($app) { $app['config']->set('view.paths', [__DIR__.'/templates']); } diff --git a/tests/Validation/ValidationEmailRuleTest.php b/tests/Validation/ValidationEmailRuleTest.php index b6382f508bc4a117c6e9ca80c0ee64f76239725d..c48451db9bef515b1eebf35d9c011ebddd28a6d7 100644 --- a/tests/Validation/ValidationEmailRuleTest.php +++ b/tests/Validation/ValidationEmailRuleTest.php @@ -11,6 +11,7 @@ use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\Email; use Illuminate\Validation\ValidationServiceProvider; use Illuminate\Validation\Validator; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; @@ -143,6 +144,7 @@ class ValidationEmailRuleTest extends TestCase ); } + #[RequiresPhpExtension('intl')] public function testValidateMxRecord() { $this->fails( @@ -674,6 +676,7 @@ class ValidationEmailRuleTest extends TestCase ); } + #[RequiresPhpExtension('intl')] public function testCombiningRules() { $this->passes(