diff --git a/src/Symfony/Bridge/Doctrine/SchemaListener/AbstractSchemaListener.php b/src/Symfony/Bridge/Doctrine/SchemaListener/AbstractSchemaListener.php index 04907ee9a78b..7d286d782cc6 100644 --- a/src/Symfony/Bridge/Doctrine/SchemaListener/AbstractSchemaListener.php +++ b/src/Symfony/Bridge/Doctrine/SchemaListener/AbstractSchemaListener.php @@ -13,6 +13,8 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs; abstract class AbstractSchemaListener @@ -22,8 +24,16 @@ abstract public function postGenerateSchema(GenerateSchemaEventArgs $event): voi protected function getIsSameDatabaseChecker(Connection $connection): \Closure { return static function (\Closure $exec) use ($connection): bool { + $schemaManager = $connection->createSchemaManager(); + $checkTable = 'schema_subscriber_check_'.bin2hex(random_bytes(7)); - $connection->executeStatement(sprintf('CREATE TABLE %s (id INTEGER NOT NULL)', $checkTable)); + $table = new Table($checkTable); + $table->addColumn('id', Types::INTEGER) + ->setAutoincrement(true) + ->setNotnull(true); + $table->setPrimaryKey(['id']); + + $schemaManager->createTable($table); try { $exec(sprintf('DROP TABLE %s', $checkTable)); @@ -32,7 +42,7 @@ protected function getIsSameDatabaseChecker(Connection $connection): \Closure } try { - $connection->executeStatement(sprintf('DROP TABLE %s', $checkTable)); + $schemaManager->dropTable($checkTable); return false; } catch (TableNotFoundException) { diff --git a/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageStorage.php b/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageStorage.php index f651033b6505..b1c0cd5966b3 100644 --- a/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageStorage.php +++ b/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageStorage.php @@ -11,6 +11,8 @@ namespace Symfony\Component\AssetMapper\ImportMap; +use Symfony\Component\AssetMapper\Exception\RuntimeException; + /** * Manages the local storage of remote/vendor importmap packages. */ @@ -52,7 +54,9 @@ public function save(ImportMapEntry $entry, string $contents): void $vendorPath = $this->getDownloadPath($entry->packageModuleSpecifier, $entry->type); @mkdir(\dirname($vendorPath), 0777, true); - file_put_contents($vendorPath, $contents); + if (false === @file_put_contents($vendorPath, $contents)) { + throw new RuntimeException(error_get_last()['message'] ?? sprintf('Failed to write file "%s".', $vendorPath)); + } } public function saveExtraFile(ImportMapEntry $entry, string $extraFilename, string $contents): void @@ -64,7 +68,9 @@ public function saveExtraFile(ImportMapEntry $entry, string $extraFilename, stri $vendorPath = $this->getExtraFileDownloadPath($entry, $extraFilename); @mkdir(\dirname($vendorPath), 0777, true); - file_put_contents($vendorPath, $contents); + if (false === @file_put_contents($vendorPath, $contents)) { + throw new RuntimeException(error_get_last()['message'] ?? sprintf('Failed to write file "%s".', $vendorPath)); + } } /** diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php index 3198b11ee76a..551a60492460 100644 --- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php @@ -201,15 +201,15 @@ public static function getRequirePackageTests(): iterable ]; yield 'single_package_with_a_path' => [ - 'packages' => [new PackageRequireOptions('some/module', path: self::$writableRoot.'/assets/some_file.js')], - 'expectedProviderPackageArgumentCount' => 0, - 'resolvedPackages' => [], - 'expectedImportMap' => [ - 'some/module' => [ - // converted to relative path - 'path' => './assets/some_file.js', + 'packages' => [new PackageRequireOptions('some/module', path: self::$writableRoot.'/assets/some_file.js')], + 'expectedProviderPackageArgumentCount' => 0, + 'resolvedPackages' => [], + 'expectedImportMap' => [ + 'some/module' => [ + // converted to relative path + 'path' => './assets/some_file.js', + ], ], - ], ]; } diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/RemotePackageStorageTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/RemotePackageStorageTest.php index 3d390475486d..8ceb90999410 100644 --- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/RemotePackageStorageTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/RemotePackageStorageTest.php @@ -25,7 +25,7 @@ class RemotePackageStorageTest extends TestCase protected function setUp(): void { $this->filesystem = new Filesystem(); - if (!file_exists(self::$writableRoot)) { + if (!$this->filesystem->exists(self::$writableRoot)) { $this->filesystem->mkdir(self::$writableRoot); } } @@ -41,14 +41,30 @@ public function testGetStorageDir() $this->assertSame(realpath(self::$writableRoot.'/assets/vendor'), realpath($storage->getStorageDir())); } + public function testSaveThrowsWhenVendorDirectoryIsNotWritable() + { + $this->filesystem->mkdir($vendorDir = self::$writableRoot.'/assets/acme/vendor'); + $this->filesystem->chmod($vendorDir, 0555); + + $storage = new RemotePackageStorage($vendorDir); + $entry = ImportMapEntry::createRemote('foo', ImportMapType::JS, '/does/not/matter', '1.0.0', 'module_specifier', false); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('file_put_contents('.$vendorDir.'/module_specifier/module_specifier.index.js): Failed to open stream: No such file or directory'); + $storage->save($entry, 'any content'); + + $this->filesystem->remove($vendorDir); + } + public function testIsDownloaded() { $storage = new RemotePackageStorage(self::$writableRoot.'/assets/vendor'); $entry = ImportMapEntry::createRemote('foo', ImportMapType::JS, '/does/not/matter', '1.0.0', 'module_specifier', false); $this->assertFalse($storage->isDownloaded($entry)); + $targetPath = self::$writableRoot.'/assets/vendor/module_specifier/module_specifier.index.js'; - @mkdir(\dirname($targetPath), 0777, true); - file_put_contents($targetPath, 'any content'); + $this->filesystem->mkdir(\dirname($targetPath)); + $this->filesystem->dumpFile($targetPath, 'any content'); $this->assertTrue($storage->isDownloaded($entry)); } @@ -57,9 +73,10 @@ public function testIsExtraFileDownloaded() $storage = new RemotePackageStorage(self::$writableRoot.'/assets/vendor'); $entry = ImportMapEntry::createRemote('foo', ImportMapType::JS, '/does/not/matter', '1.0.0', 'module_specifier', false); $this->assertFalse($storage->isExtraFileDownloaded($entry, '/path/to/extra.woff')); + $targetPath = self::$writableRoot.'/assets/vendor/module_specifier/path/to/extra.woff'; - @mkdir(\dirname($targetPath), 0777, true); - file_put_contents($targetPath, 'any content'); + $this->filesystem->mkdir(\dirname($targetPath)); + $this->filesystem->dumpFile($targetPath, 'any content'); $this->assertTrue($storage->isExtraFileDownloaded($entry, '/path/to/extra.woff')); } @@ -92,7 +109,7 @@ public function testGetDownloadedPath(string $packageModuleSpecifier, ImportMapT $this->assertSame($expectedPath, $storage->getDownloadPath($packageModuleSpecifier, $importMapType)); } - public static function getDownloadPathTests() + public static function getDownloadPathTests(): iterable { yield 'javascript bare package' => [ 'packageModuleSpecifier' => 'foo', diff --git a/src/Symfony/Component/Finder/Iterator/VcsIgnoredFilterIterator.php b/src/Symfony/Component/Finder/Iterator/VcsIgnoredFilterIterator.php index ddd7007728a7..b278706e9f34 100644 --- a/src/Symfony/Component/Finder/Iterator/VcsIgnoredFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/VcsIgnoredFilterIterator.php @@ -37,9 +37,9 @@ public function __construct(\Iterator $iterator, string $baseDir) { $this->baseDir = $this->normalizePath($baseDir); - foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) { - if (@is_dir("{$parentDirectory}/.git")) { - $this->baseDir = $parentDirectory; + foreach ([$this->baseDir, ...$this->parentDirectoriesUpwards($this->baseDir)] as $directory) { + if (@is_dir("{$directory}/.git")) { + $this->baseDir = $directory; break; } } diff --git a/src/Symfony/Component/Finder/Tests/Iterator/VcsIgnoredFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/VcsIgnoredFilterIteratorTest.php index 3ebe481f559c..f725374d815e 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/VcsIgnoredFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/VcsIgnoredFilterIteratorTest.php @@ -34,7 +34,7 @@ protected function tearDown(): void * * @dataProvider getAcceptData */ - public function testAccept(array $gitIgnoreFiles, array $otherFileNames, array $expectedResult) + public function testAccept(array $gitIgnoreFiles, array $otherFileNames, array $expectedResult, string $baseDir = '') { $otherFileNames = $this->toAbsolute($otherFileNames); foreach ($otherFileNames as $path) { @@ -51,7 +51,8 @@ public function testAccept(array $gitIgnoreFiles, array $otherFileNames, array $ $inner = new InnerNameIterator($otherFileNames); - $iterator = new VcsIgnoredFilterIterator($inner, $this->tmpDir); + $baseDir = $this->tmpDir.('' !== $baseDir ? '/'.$baseDir : ''); + $iterator = new VcsIgnoredFilterIterator($inner, $baseDir); $this->assertIterator($this->toAbsolute($expectedResult), $iterator); } @@ -74,6 +75,55 @@ public static function getAcceptData(): iterable ], ]; + yield 'simple file - .gitignore and in() from repository root' => [ + [ + '.gitignore' => 'a.txt', + ], + [ + '.git', + 'a.txt', + 'b.txt', + 'dir/', + 'dir/a.txt', + ], + [ + '.git', + 'b.txt', + 'dir', + ], + ]; + + yield 'nested git repositories only consider .gitignore files of the most inner repository' => [ + [ + '.gitignore' => "nested/*\na.txt", + 'nested/.gitignore' => 'c.txt', + 'nested/dir/.gitignore' => 'f.txt', + ], + [ + '.git', + 'a.txt', + 'b.txt', + 'nested/', + 'nested/.git', + 'nested/c.txt', + 'nested/d.txt', + 'nested/dir/', + 'nested/dir/e.txt', + 'nested/dir/f.txt', + ], + [ + '.git', + 'a.txt', + 'b.txt', + 'nested', + 'nested/.git', + 'nested/d.txt', + 'nested/dir', + 'nested/dir/e.txt', + ], + 'nested', + ]; + yield 'simple file at root' => [ [ '.gitignore' => '/a.txt', diff --git a/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php b/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php index dab1ece3d56c..33d01fd4f54d 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php +++ b/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php @@ -12,7 +12,9 @@ namespace Symfony\Component\Form\Extension\Core\DataAccessor; use Symfony\Component\Form\DataAccessorInterface; +use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\AccessException; +use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\FormInterface; use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; @@ -52,15 +54,25 @@ public function setValue(object|array &$data, mixed $value, FormInterface $form) throw new AccessException('Unable to write the given value as no property path is defined.'); } + $getValue = function () use ($data, $form, $propertyPath) { + $dataMapper = $this->getDataMapper($form); + + if ($dataMapper instanceof DataMapper && null !== $dataAccessor = $dataMapper->getDataAccessor()) { + return $dataAccessor->getValue($data, $form); + } + + return $this->getPropertyValue($data, $propertyPath); + }; + // If the field is of type DateTimeInterface and the data is the same skip the update to // keep the original object hash - if ($value instanceof \DateTimeInterface && $value == $this->getPropertyValue($data, $propertyPath)) { + if ($value instanceof \DateTimeInterface && $value == $getValue()) { return; } // If the data is identical to the value in $data, we are // dealing with a reference - if (!\is_object($data) || !$form->getConfig()->getByReference() || $value !== $this->getPropertyValue($data, $propertyPath)) { + if (!\is_object($data) || !$form->getConfig()->getByReference() || $value !== $getValue()) { try { $this->propertyAccessor->setValue($data, $propertyPath, $value); } catch (NoSuchPropertyException $e) { @@ -98,4 +110,13 @@ private function getPropertyValue(object|array $data, PropertyPathInterface $pro return null; } } + + private function getDataMapper(FormInterface $form): ?DataMapperInterface + { + do { + $dataMapper = $form->getConfig()->getDataMapper(); + } while (null === $dataMapper && null !== $form = $form->getParent()); + + return $dataMapper; + } } diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php index f27f9d14bff9..a7bf98032202 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php +++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php @@ -74,4 +74,12 @@ public function mapFormsToData(\Traversable $forms, mixed &$data): void } } } + + /** + * @internal + */ + public function getDataAccessor(): DataAccessorInterface + { + return $this->dataAccessor; + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/DataMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/DataMapperTest.php index fafd0e9d032f..1a8f2678dd74 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/DataMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/DataMapperTest.php @@ -16,6 +16,8 @@ use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormFactoryBuilder; @@ -403,6 +405,25 @@ public function testMapFormsToDataMapsDateTimeInstanceToArrayIfNotSetBefore() $this->assertEquals(['date' => new \DateTime('2022-08-04', new \DateTimeZone('UTC'))], $form->getData()); } + + public function testMapFormToDataWithOnlyGetterConfigured() + { + $person = new DummyPerson('foo'); + $form = (new FormFactoryBuilder()) + ->getFormFactory() + ->createBuilder(FormType::class, $person) + ->add('name', TextType::class, [ + 'getter' => function (DummyPerson $person) { + return $person->myName(); + }, + ]) + ->getForm(); + $form->submit([ + 'name' => 'bar', + ]); + + $this->assertSame('bar', $person->myName()); + } } class SubmittedForm extends Form @@ -439,4 +460,9 @@ public function rename($name): void { $this->name = $name; } + + public function setName($name): void + { + $this->name = $name; + } } diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php index f4e5d4333a06..7f52bdaf0f67 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php @@ -94,6 +94,22 @@ public function __construct(array $options, \Redis|Relay|\RedisCluster|null $red throw new InvalidArgumentException('Cannot configure Redis Sentinel and Redis Cluster instance at the same time.'); } + $booleanStreamOptions = [ + 'allow_self_signed', + 'capture_peer_cert', + 'capture_peer_cert_chain', + 'disable_compression', + 'SNI_enabled', + 'verify_peer', + 'verify_peer_name', + ]; + + foreach ($options['ssl'] ?? [] as $streamOption => $value) { + if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) { + $options['ssl'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL); + } + } + if ((\is_array($host) && null === $sentinelMaster) || $redis instanceof \RedisCluster) { $hosts = \is_string($host) ? [$host.':'.$port] : $host; // Always ensure we have an array $this->redis = static fn () => self::initializeRedisCluster($redis, $hosts, $auth, $options); diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php index 39d997c78cc4..0441c4cff145 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php @@ -314,6 +314,15 @@ private function getDocBlockFromProperty(string $class, string $property): ?arra return null; } + $reflector = $reflectionProperty->getDeclaringClass(); + + foreach ($reflector->getTraits() as $trait) { + if ($trait->hasProperty($property)) { + return $this->getDocBlockFromProperty($trait->getName(), $property); + } + + } + // Type can be inside property docblock as `@var` $rawDocNode = $reflectionProperty->getDocComment(); $phpDocNode = $rawDocNode ? $this->getPhpDocNode($rawDocNode) : null; diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php index 1e76a5272b2d..0dcb0150057b 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php @@ -29,6 +29,7 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80PromotedDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\PhpStanPseudoTypesDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\RootDummy\RootDummyItem; +use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\AnotherNamespace\DummyInAnotherNamespace; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait; use Symfony\Component\PropertyInfo\Type as LegacyType; @@ -333,6 +334,7 @@ public static function provideLegacyPropertiesDefinedByTraits(): array ['propertyInTraitPrimitiveType', new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], ['propertyInTraitObjectSameNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], ['propertyInTraitObjectDifferentNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], + ['dummyInAnotherNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyInAnotherNamespace::class)], ]; } @@ -758,6 +760,7 @@ public static function propertiesDefinedByTraitsProvider(): iterable yield ['propertyInTraitPrimitiveType', Type::string()]; yield ['propertyInTraitObjectSameNamespace', Type::object(DummyUsedInTrait::class)]; yield ['propertyInTraitObjectDifferentNamespace', Type::object(Dummy::class)]; + yield ['dummyInAnotherNamespace', Type::object(DummyInAnotherNamespace::class)]; } /** diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/AnotherNamespace/DummyInAnotherNamespace.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/AnotherNamespace/DummyInAnotherNamespace.php new file mode 100644 index 000000000000..5ae6b60b5973 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/AnotherNamespace/DummyInAnotherNamespace.php @@ -0,0 +1,7 @@ +message = $message ?? $this->message; diff --git a/src/Symfony/Component/Validator/Constraints/Range.php b/src/Symfony/Component/Validator/Constraints/Range.php index e91aaf98f106..a8c7271c4717 100644 --- a/src/Symfony/Component/Validator/Constraints/Range.php +++ b/src/Symfony/Component/Validator/Constraints/Range.php @@ -99,7 +99,7 @@ public function __construct( throw new LogicException(sprintf('The "%s" constraint requires the Symfony PropertyAccess component to use the "minPropertyPath" or "maxPropertyPath" option. Try running "composer require symfony/property-access".', static::class)); } - if (null !== $this->min && null !== $this->max && ($minMessage || $maxMessage)) { + if (null !== $this->min && null !== $this->max && ($minMessage || $maxMessage || isset($options['minMessage']) || isset($options['maxMessage']))) { throw new ConstraintDefinitionException(sprintf('The "%s" constraint can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.', static::class)); } } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index a96cce98048e..08012ac233bd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -440,7 +440,7 @@ This URL is missing a top-level domain. - هذا الرابط يفتقر إلى نطاق أعلى مستوى. + هذا الرابط يفتقر إلى نطاق المستوى الأعلى. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index de24ec5eb0c4..d2405339f0c3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -68,7 +68,7 @@ The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Mime типа на файла е невалиден ({{ type }}). Разрешени mime типове са {{ types }}. + Mime типът на файла е невалиден ({{ type }}). Разрешени mime типове са {{ types }}. This value should be {{ limit }} or less. @@ -136,7 +136,7 @@ This value is not a valid IP address. - Тази стойност не е валиден IP адрес. + Стойността не е валиден IP адрес. This value is not a valid language. @@ -156,7 +156,7 @@ The size of the image could not be detected. - Размера на изображението не може да бъде определен. + Размерът на изображението не може да бъде определен. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - В php.ini не е конфигурирана временна директория, или конфигурираната директория не съществува. + В php.ini не е конфигурирана временна директория или конфигурираната директория не съществува. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Тази стойност не е валиден международен банков сметка номер (IBAN). + Стойността не е валиден Международен номер на банкова сметка (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Тази стойност не е валиден код за идентификация на бизнеса (BIC). + Стойността не е валиден Бизнес идентификационен код (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Тази стойност не е валиден UUID. + Стойността не е валиден UUID. This value should be a multiple of {{ compared_value }}. @@ -328,7 +328,7 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. - Бизнес идентификационния код (BIC) не е свързан с IBAN {{ iban }}. + Бизнес идентификационният код (BIC) не е свързан с IBAN {{ iban }}. This value should be valid JSON. @@ -360,7 +360,7 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - Тази парола е компрометирана, не трябва да бъде използвана. Моля използвайте друга парола. + Тази парола е компрометирана, не може да бъде използвана. Моля използвайте друга парола. This value should be between {{ min }} and {{ max }}. @@ -436,11 +436,11 @@ This value is not a valid MAC address. - Тази стойност не е валиден MAC адрес. + Стойността не е валиден MAC адрес. This URL is missing a top-level domain. - На този URL липсва домейн от най-високо ниво. + На този URL липсва домейн от най-високо ниво. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index c9da5988af14..652c0a48d693 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -108,7 +108,7 @@ This value is not a valid URL. - Aquest valor no és una URL vàlida. + Aquest valor no és un URL vàlid. The two values should be equal. @@ -116,7 +116,7 @@ The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - L'arxiu és massa gran. El tamany màxim permés és {{ limit }} {{ suffix }}. + L'arxiu és massa gran. La mida màxima permesa és {{ limit }} {{ suffix }}. The file is too large. @@ -136,7 +136,7 @@ This value is not a valid IP address. - Aquest valor no és una adreça IP vàlida. + Aquest valor no és una adreça IP vàlida. This value is not a valid language. @@ -160,19 +160,19 @@ The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - L'amplària de la imatge és massa gran ({{ width }}px). L'amplària màxima permesa són {{ max_width }}px. + L'amplària de la imatge és massa gran ({{ width }}px). L'amplària màxima permesa és {{ max_width }}px. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - L'amplària de la imatge és massa petita ({{ width }}px). L'amplària mínima requerida són {{ min_width }}px. + L'amplària de la imatge és massa petita ({{ width }}px). L'amplària mínima requerida és {{ min_width }}px. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - L'altura de la imatge és massa gran ({{ height }}px). L'altura màxima permesa són {{ max_height }}px. + L'altura de la imatge és massa gran ({{ height }}px). L'altura màxima permesa és {{ max_height }}px. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - L'altura de la imatge és massa petita ({{ height }}px). L'altura mínima requerida són {{ min_height }}px. + L'altura de la imatge és massa petita ({{ height }}px). L'altura mínima requerida és {{ min_height }}px. This value should be the user's current password. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - No s'ha configurat cap carpeta temporal en php.ini, o la carpeta configurada no existeix. + No s'ha configurat cap carpeta temporal en php.ini, o la carpeta configurada no existeix. Cannot write temporary file to disk. @@ -200,7 +200,7 @@ A PHP extension caused the upload to fail. - Una extensió de PHP va fer que la pujada fallara. + Una extensió de PHP va fer que la pujada fallarà. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Aquest valor no és un Número de Compte Bancari Internacional (IBAN) vàlid. + Aquest valor no és un Número de Compte Bancari Internacional (IBAN) vàlid. This value is not a valid ISBN-10. @@ -276,31 +276,31 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - Aquest valor no hauria de idèntic a {{ compared_value_type }} {{ compared_value }}. + Aquest valor no hauria de ser idèntic a {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - La proporció de l'imatge és massa gran ({{ ratio }}). La màxima proporció permesa és {{ max_ratio }}. + La proporció de la imatge és massa gran ({{ ratio }}). La màxima proporció permesa és {{ max_ratio }}. The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - La proporció de l'imatge és massa petita ({{ ratio }}). La mínima proporció permesa és {{ max_ratio }}. + La proporció de la imatge és massa petita ({{ ratio }}). La mínima proporció permesa és {{ min_ratio }}. The image is square ({{ width }}x{{ height }}px). Square images are not allowed. - L'imatge és quadrada({{ width }}x{{ height }}px). Les imatges quadrades no estan permeses. + La imatge és quadrada({{ width }}x{{ height }}px). Les imatges quadrades no estan permeses. The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. - L'imatge està orientada horitzontalment ({{ width }}x{{ height }}px). Les imatges orientades horitzontalment no estan permeses. + La imatge està orientada horitzontalment ({{ width }}x{{ height }}px). Les imatges orientades horitzontalment no estan permeses. The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. - L'imatge està orientada verticalment ({{ width }}x{{ height }}px). Les imatges orientades verticalment no estan permeses. + La imatge està orientada verticalment ({{ width }}x{{ height }}px). Les imatges orientades verticalment no estan permeses. An empty file is not allowed. - No està permès un fixter buit. + No està permès un fitxer buit. The host could not be resolved. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Aquest valor no és un Codi d'Identificador de Negocis (BIC) vàlid. + Aquest valor no és un Codi d'identificació bancari (BIC) vàlid. Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Aquest valor no és un UUID vàlid. + Aquest valor no és un UUID vàlid. This value should be a multiple of {{ compared_value }}. @@ -428,19 +428,19 @@ The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. - L'extensió del fitxer no és vàlida ({{ extension }}). Les extensions permeses són {{ extensions }}. + L'extensió del fitxer no és vàlida ({{ extension }}). Les extensions permeses són {{ extensions }}. The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. - S'ha detectat que la codificació de caràcters no és vàlida ({{ detected }}). Les codificacions permeses són {{ encodings }}. + S'ha detectat que la codificació de caràcters no és vàlida ({{ detected }}). Les codificacions permeses són {{ encodings }}. This value is not a valid MAC address. - Aquest valor no és una adreça MAC vàlida. + Aquest valor no és una adreça MAC vàlida. This URL is missing a top-level domain. - Aquesta URL no conté un domini de nivell superior. + Aquesta URL no conté un domini de primer nivell. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 141ec515f789..d58045471c70 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -404,7 +404,7 @@ The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. - El nombre del archivo es demasido largo. Debe tener {{ filename_max_length }} carácter o menos.|El nombre del archivo es demasido largo. Debe tener {{ filename_max_length }} caracteres o menos. + El nombre del archivo es demasiado largo. Debe tener {{ filename_max_length }} carácter o menos.|El nombre del archivo es demasiado largo. Debe tener {{ filename_max_length }} caracteres o menos. The password strength is too low. Please use a stronger password. @@ -440,7 +440,7 @@ This URL is missing a top-level domain. - Esta URL no contiene una extensión de dominio (TLD). + Esta URL no contiene una extensión de dominio (TLD). diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index 27a57d0331fe..4e949d838cae 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -440,7 +440,7 @@ This URL is missing a top-level domain. - Cette URL est dépourvue de domaine de premier niveau. + Cette URL doit contenir un domaine de premier niveau. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 980b1a676704..b894c69d855d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Tidak ada folder sementara yang dikonfigurasi di php.ini, atau folder yang dikonfigurasi tidak ada. + Tidak ada folder sementara yang dikonfigurasi di php.ini, atau folder yang dikonfigurasi tidak ada. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index df67a2c082b5..74f3a75b0c97 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -440,7 +440,7 @@ This URL is missing a top-level domain. - Questo URL è privo di un dominio di primo livello. + Questo URL è privo di un dominio di primo livello. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index 26b3a4e77e37..e16daea93b80 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Ši vertė nėra galiojantis IP adresas. + Ši reikšmė nėra tinkamas IP adresas. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - php.ini nesukonfigūruotas laikinas aplankas, arba sukonfigūruotas aplankas neegzistuoja. + php.ini nesukonfigūruotas laikinas aplankas arba sukonfigūruotas aplankas neegzistuoja. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Ši vertė nėra galiojantis Tarptautinis Banko Sąskaitos Numeris (IBAN). + Ši reikšmė nėra tinkamas Tarptautinis Banko Sąskaitos Numeris (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Ši vertė nėra galiojantis Verslo Identifikavimo Kodas (BIC). + Ši reikšmė nėra tinkamas Verslo Identifikavimo Kodas (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Ši vertė nėra galiojantis UUID. + Ši reikšmė nėra tinkamas UUID. This value should be a multiple of {{ compared_value }}. @@ -432,15 +432,15 @@ The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. - Nustatyta simbolių koduotė yra netinkama ({{ detected }}). Leidžiamos koduotės yra {{ encodings }}. + Aptikta simbolių koduotė yra netinkama ({{ detected }}). Leidžiamos koduotės yra {{ encodings }}. This value is not a valid MAC address. - Ši vertė nėra galiojantis MAC adresas. + Ši reikšmė nėra tinkamas MAC adresas. This URL is missing a top-level domain. - Šiam URL trūksta aukščiausio lygio domeno. + Šiam URL trūksta aukščiausio lygio domeno. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf index 9bbaafd0ce33..66e370fea944 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf @@ -440,7 +440,7 @@ This URL is missing a top-level domain. - Šim URL trūkst augšējā līmeņa domēna. + Šim URL trūkst augšējā līmeņa domēna. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 241cba52e3d6..dbee06a984b2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -440,7 +440,7 @@ This URL is missing a top-level domain. - Этому URL не хватает домена верхнего уровня. + В этом URL отсутствует домен верхнего уровня. diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php index b6f710ffc7ad..8489f9cfecb6 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php @@ -40,6 +40,13 @@ public function testUnknownModesTriggerException() new Email(['mode' => 'Unknown Mode']); } + public function testUnknownModeArgumentsTriggerException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "mode" parameter value is not valid.'); + new Email(null, null, 'Unknown Mode'); + } + public function testNormalizerCanBeSet() { $email = new Email(['normalizer' => 'trim']); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php index f51898299d7a..a306b104a576 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php @@ -65,10 +65,58 @@ public function testThrowsNoDefaultOptionConfiguredException() new Range('value'); } - public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMinMessageOrMaxMessage() + public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMinMessageAndMaxMessage() { $this->expectException(ConstraintDefinitionException::class); $this->expectExceptionMessage('can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.'); new Range(min: 'min', max: 'max', minMessage: 'minMessage', maxMessage: 'maxMessage'); } + + public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMinMessage() + { + $this->expectException(ConstraintDefinitionException::class); + $this->expectExceptionMessage('can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.'); + new Range(min: 'min', max: 'max', minMessage: 'minMessage'); + } + + public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMaxMessage() + { + $this->expectException(ConstraintDefinitionException::class); + $this->expectExceptionMessage('can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.'); + new Range(min: 'min', max: 'max', maxMessage: 'maxMessage'); + } + + public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMinMessageAndMaxMessageOptions() + { + $this->expectException(ConstraintDefinitionException::class); + $this->expectExceptionMessage('can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.'); + new Range([ + 'min' => 'min', + 'minMessage' => 'minMessage', + 'max' => 'max', + 'maxMessage' => 'maxMessage', + ]); + } + + public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMinMessageOptions() + { + $this->expectException(ConstraintDefinitionException::class); + $this->expectExceptionMessage('can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.'); + new Range([ + 'min' => 'min', + 'minMessage' => 'minMessage', + 'max' => 'max', + ]); + } + + public function testThrowsConstraintDefinitionExceptionIfBothMinAndMaxAndMaxMessageOptions() + { + $this->expectException(ConstraintDefinitionException::class); + $this->expectExceptionMessage('can not use "minMessage" and "maxMessage" when the "min" and "max" options are both set. Use "notInRangeMessage" instead.'); + new Range([ + 'min' => 'min', + 'max' => 'max', + 'maxMessage' => 'maxMessage', + ]); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php index 876595c37fc9..c0eb5e61703a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php @@ -1037,30 +1037,6 @@ public static function provideMessageIfMinAndMaxSet(): array 'not_in_range_message', Range::NOT_IN_RANGE_ERROR, ], - [ - ['minMessage' => 'min_message'], - 0, - $notInRangeMessage, - Range::NOT_IN_RANGE_ERROR, - ], - [ - ['maxMessage' => 'max_message'], - 0, - $notInRangeMessage, - Range::NOT_IN_RANGE_ERROR, - ], - [ - ['minMessage' => 'min_message'], - 15, - $notInRangeMessage, - Range::NOT_IN_RANGE_ERROR, - ], - [ - ['maxMessage' => 'max_message'], - 15, - $notInRangeMessage, - Range::NOT_IN_RANGE_ERROR, - ], ]; } diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 06c7c750a083..7a4150999aef 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -633,12 +633,12 @@ private function getNextEmbedBlock(?int $indentation = null, bool $inSequence = } if ($this->isCurrentLineBlank()) { - $data[] = substr($this->currentLine, $newIndent); + $data[] = substr($this->currentLine, $newIndent ?? 0); continue; } if ($indent >= $newIndent) { - $data[] = substr($this->currentLine, $newIndent); + $data[] = substr($this->currentLine, $newIndent ?? 0); } elseif ($this->isCurrentLineComment()) { $data[] = $this->currentLine; } elseif (0 == $indent) { diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 9abdf5b02533..5e06819e81ca 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -1476,13 +1476,13 @@ public static function getBinaryData() data: !!binary | SGVsbG8gd29ybGQ= EOT - ], + ], 'containing spaces in block scalar' => [ <<<'EOT' data: !!binary | SGVs bG8gd 29ybGQ= EOT - ], + ], ]; } @@ -2967,6 +2967,11 @@ public function testParseIdeographicSpaces() ], $this->parser->parse($expected)); } + public function testSkipBlankLines() + { + $this->assertSame(['foo' => [null]], (new Parser())->parse("foo:\n-\n\n")); + } + private function assertSameData($expected, $actual) { $this->assertEquals($expected, $actual);