From bfb57aad65b08b304164a81dfe701ed8fcf1b6d7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 26 Aug 2023 15:52:45 +0200 Subject: [PATCH 01/23] Bump Symfony version to 5.4.29 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 8f448da150ce0..42e6ed4b1e80f 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.28'; - public const VERSION_ID = 50428; + public const VERSION = '5.4.29-DEV'; + public const VERSION_ID = 50429; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 28; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 29; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From aaf507a766cfb2b63152f3cc5c89e0d11c2ed00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Despont?= Date: Tue, 29 Aug 2023 08:36:24 +0200 Subject: [PATCH 02/23] Update Pbkdf2PasswordHasher.php Because https://www.php.net/manual/en/function.hash-pbkdf2.php is expecting string and not ?string. Pertmits avoiding deprecation warning. --- .../Component/PasswordHasher/Hasher/Pbkdf2PasswordHasher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/PasswordHasher/Hasher/Pbkdf2PasswordHasher.php b/src/Symfony/Component/PasswordHasher/Hasher/Pbkdf2PasswordHasher.php index 57fbe0728fe93..2fc762cb4e870 100644 --- a/src/Symfony/Component/PasswordHasher/Hasher/Pbkdf2PasswordHasher.php +++ b/src/Symfony/Component/PasswordHasher/Hasher/Pbkdf2PasswordHasher.php @@ -69,7 +69,7 @@ public function hash(string $plainPassword, string $salt = null): string throw new LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm)); } - $digest = hash_pbkdf2($this->algorithm, $plainPassword, $salt, $this->iterations, $this->length, true); + $digest = hash_pbkdf2($this->algorithm, $plainPassword, $salt ?? '', $this->iterations, $this->length, true); return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest); } From bfc4bddc7b9358dfb77dfa76446380b40a219290 Mon Sep 17 00:00:00 2001 From: Caligone Date: Sat, 2 Sep 2023 09:45:59 +0200 Subject: [PATCH 03/23] [Serializer] Looking for DiscriminatorMap on interfaces when the current object also extends from a class --- .../ClassDiscriminatorFromClassMetadata.php | 4 +++- .../Tests/Fixtures/DummyMessageInterface.php | 3 ++- .../Fixtures/DummyMessageNumberThree.php | 19 +++++++++++++++++++ .../Serializer/Tests/SerializerTest.php | 13 +++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberThree.php diff --git a/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php b/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php index 23554ffda98ab..6f69c890b91d9 100644 --- a/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php +++ b/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php @@ -78,7 +78,9 @@ private function resolveMappingForMappedObject($object) { $reflectionClass = new \ReflectionClass($object); if ($parentClass = $reflectionClass->getParentClass()) { - return $this->getMappingForMappedObject($parentClass->getName()); + if (null !== ($parentMapping = $this->getMappingForMappedObject($parentClass->getName()))) { + return $parentMapping; + } } foreach ($reflectionClass->getInterfaceNames() as $interfaceName) { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php index 55bb00bc8e253..78beb8374aaff 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php @@ -16,7 +16,8 @@ /** * @DiscriminatorMap(typeProperty="type", mapping={ * "one"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne", - * "two"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo" + * "two"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo", + * "three"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberThree" * }) * * @author Samuel Roze diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberThree.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberThree.php new file mode 100644 index 0000000000000..e15fc62c7bae0 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberThree.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Samuel Roze + */ +class DummyMessageNumberThree extends \stdClass implements DummyMessageInterface +{ +} diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index b4e84132a0858..2141c0cf6d334 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -58,6 +58,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\DummyFirstChildQuux; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne; +use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberThree; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo; use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor; use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumProperty; @@ -488,6 +489,18 @@ public function testDeserializeAndSerializeNestedInterfacedObjectsWithTheClassMe $this->assertEquals($example, $deserialized); } + public function testDeserializeAndSerializeNestedAbstractAndInterfacedObjectsWithTheClassMetadataDiscriminator() + { + $example = new DummyMessageNumberThree(); + + $serializer = $this->serializerWithClassDiscriminator(); + + $serialized = $serializer->serialize($example, 'json'); + $deserialized = $serializer->deserialize($serialized, DummyMessageInterface::class, 'json'); + + $this->assertEquals($example, $deserialized); + } + public function testExceptionWhenTypeIsNotKnownInDiscriminator() { try { From 809cf7403771d123134139819e6508466a8258d2 Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" Date: Wed, 6 Sep 2023 22:45:09 +0100 Subject: [PATCH 04/23] PHP 8.3 highlight_file function output changes --- .../Bridge/Twig/Extension/CodeExtension.php | 26 ++++++++++++++----- .../ErrorRenderer/HtmlErrorRenderer.php | 26 ++++++++++++++----- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php index 3bf8ccd294b41..59845396cfe40 100644 --- a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php @@ -123,13 +123,25 @@ public function fileExcerpt(string $file, int $line, int $srcContext = 3): ?stri // highlight_file could throw warnings // see https://bugs.php.net/25725 $code = @highlight_file($file, true); - // remove main code/span tags - $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); - // split multiline spans - $code = preg_replace_callback('#]++)>((?:[^<]*+
)++[^<]*+)
#', function ($m) { - return "".str_replace('
', "

", $m[2]).''; - }, $code); - $content = explode('
', $code); + if (\PHP_VERSION_ID >= 80300) { + // remove main pre/code tags + $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); + // split multiline code tags + $code = preg_replace_callback('#]++)>((?:[^<]*+\\n)++[^<]*+)#', function ($m) { + return "".str_replace("\n", "\n", $m[2]).''; + }, $code); + // Convert spaces to html entities to preserve indentation when rendered + $code = str_replace(' ', ' ', $code); + $content = explode("\n", $code); + } else { + // remove main code/span tags + $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); + // split multiline spans + $code = preg_replace_callback('#]++)>((?:[^<]*+
)++[^<]*+)
#', function ($m) { + return "".str_replace('
', "

", $m[2]).''; + }, $code); + $content = explode('
', $code); + } $lines = []; if (0 > $srcContext) { diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php index b8a9aeda61fda..92434b8e94506 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php @@ -269,13 +269,25 @@ private function fileExcerpt(string $file, int $line, int $srcContext = 3): stri // highlight_file could throw warnings // see https://bugs.php.net/25725 $code = @highlight_file($file, true); - // remove main code/span tags - $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); - // split multiline spans - $code = preg_replace_callback('#]++)>((?:[^<]*+
)++[^<]*+)
#', function ($m) { - return "".str_replace('
', "

", $m[2]).''; - }, $code); - $content = explode('
', $code); + if (\PHP_VERSION_ID >= 80300) { + // remove main pre/code tags + $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); + // split multiline code tags + $code = preg_replace_callback('#]++)>((?:[^<]*+\\n)++[^<]*+)#', function ($m) { + return "".str_replace("\n", "\n", $m[2]).''; + }, $code); + // Convert spaces to html entities to preserve indentation when rendered + $code = str_replace(' ', ' ', $code); + $content = explode("\n", $code); + } else { + // remove main code/span tags + $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); + // split multiline spans + $code = preg_replace_callback('#]++)>((?:[^<]*+
)++[^<]*+)
#', function ($m) { + return "".str_replace('
', "

", $m[2]).''; + }, $code); + $content = explode('
', $code); + } $lines = []; if (0 > $srcContext) { From e1a14b754b0333b719a078c58c88103ac46789b0 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Thu, 7 Sep 2023 00:39:36 +0200 Subject: [PATCH 05/23] [FrameworkBundle] Always use buildDir as `ConfigBuilderGenerator` outputDir --- .../CacheWarmer/ConfigBuilderCacheWarmer.php | 2 +- .../ConfigBuilderCacheWarmerTest.php | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php index ed20bbcb648d7..50843f5263c18 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php @@ -44,7 +44,7 @@ public function __construct(KernelInterface $kernel, LoggerInterface $logger = n */ public function warmUp(string $cacheDir) { - $generator = new ConfigBuilderGenerator($cacheDir); + $generator = new ConfigBuilderGenerator($this->kernel->getBuildDir()); foreach ($this->kernel->getBundles() as $bundle) { $extension = $bundle->getContainerExtension(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php new file mode 100644 index 0000000000000..c64e5d3b4cdd3 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer; + +use Symfony\Bundle\FrameworkBundle\CacheWarmer\ConfigBuilderCacheWarmer; +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\HttpKernel\Kernel; + +class ConfigBuilderCacheWarmerTest extends TestCase +{ + private $varDir; + + protected function setUp(): void + { + $this->varDir = sys_get_temp_dir().'/'.uniqid(); + $fs = new Filesystem(); + $fs->mkdir($this->varDir); + } + + protected function tearDown(): void + { + $fs = new Filesystem(); + $fs->remove($this->varDir); + unset($this->varDir); + } + + public function testBuildDirIsUsedAsConfigBuilderOutputDir() + { + $kernel = new class($this->varDir) extends Kernel { + private $varDir; + + public function __construct(string $varDir) + { + parent::__construct('test', false); + + $this->varDir = $varDir; + } + + public function registerBundles(): iterable + { + yield new FrameworkBundle(); + } + + public function getBuildDir(): string + { + return $this->varDir.'/build'; + } + + public function getCacheDir(): string + { + return $this->varDir.'/cache'; + } + + public function registerContainerConfiguration(LoaderInterface $loader) + { + } + }; + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir()); + + self::assertDirectoryExists($kernel->getBuildDir().'/Symfony'); + self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + } +} From 0182fc7d306cd4253dc1550946686d2cbee0c14e Mon Sep 17 00:00:00 2001 From: Makrevski Zoran Date: Sat, 9 Sep 2023 10:37:18 +0300 Subject: [PATCH 06/23] [Form][Security][Validator] Add mk translations --- .../Resources/translations/validators.mk.xlf | 139 ++++++ .../Resources/translations/security.mk.xlf | 83 ++++ .../Resources/translations/validators.mk.xlf | 431 ++++++++++++++++++ 3 files changed, 653 insertions(+) create mode 100644 src/Symfony/Component/Form/Resources/translations/validators.mk.xlf create mode 100644 src/Symfony/Component/Security/Core/Resources/translations/security.mk.xlf create mode 100644 src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf diff --git a/src/Symfony/Component/Form/Resources/translations/validators.mk.xlf b/src/Symfony/Component/Form/Resources/translations/validators.mk.xlf new file mode 100644 index 0000000000000..ea86b304cee25 --- /dev/null +++ b/src/Symfony/Component/Form/Resources/translations/validators.mk.xlf @@ -0,0 +1,139 @@ + + + + + + This form should not contain extra fields. + Оваа форма не треба да содржи дополнителни полиња. + + + The uploaded file was too large. Please try to upload a smaller file. + Датотеката што се обидовте да ја подигнете е преголема. Ве молиме обидете се со помала датотека. + + + The CSRF token is invalid. Please try to resubmit the form. + Вашиот CSRF токен е невалиден. Ве молиме испратете ја формата одново. + + + This value is not a valid HTML5 color. + Оваа вредност не е валидна HTML5 боја. + + + Please enter a valid birthdate. + Ве молиме внесете валидна дата на раѓање. + + + The selected choice is invalid. + Избраната опција е невалидна. + + + The collection is invalid. + Колекцијата е невалидна. + + + Please select a valid color. + Ве молиме одберете валидна боја. + + + Please select a valid country. + Ве молиме одберете валидна земја. + + + Please select a valid currency. + Ве молиме одберете валидна валута. + + + Please choose a valid date interval. + Ве молиме одберете валиден интервал помеѓу два датума. + + + Please enter a valid date and time. + Ве молиме внесете валиден датум и време. + + + Please enter a valid date. + Ве молиме внесете валиден датум. + + + Please select a valid file. + Ве молиме одберете валидна датотека. + + + The hidden field is invalid. + Скриеното поле е невалидно. + + + Please enter an integer. + Ве молиме внесете цел број. + + + Please select a valid language. + Ве молиме одберете валиден јазик. + + + Please select a valid locale. + Ве молиме одберете валидна локализација. + + + Please enter a valid money amount. + Ве молиме внесете валидна сума на пари. + + + Please enter a number. + Ве молиме внесете број. + + + The password is invalid. + Лозинката е погрешна. + + + Please enter a percentage value. + Ве молиме внесете процентуална вредност. + + + The values do not match. + Вредностите не се совпаѓаат. + + + Please enter a valid time. + Ве молиме внесете валидно време. + + + Please select a valid timezone. + Ве молиме одберете валидна временска зона. + + + Please enter a valid URL. + Ве молиме внесете валиден униформен локатор на ресурси (URL). + + + Please enter a valid search term. + Ве молиме внесете валиден термин за пребарување. + + + Please provide a valid phone number. + Ве молиме внесете валиден телефонски број. + + + The checkbox has an invalid value. + Полето за штиклирање има неважечка вредност. + + + Please enter a valid email address. + Ве молиме внесете валидна адреса за е-пошта. + + + Please select a valid option. + Ве молиме одберете валидна опција. + + + Please select a valid range. + Ве молиме одберете важечки опсег. + + + Please enter a valid week. + Ве молиме внесете валидна недела. + + + + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.mk.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.mk.xlf new file mode 100644 index 0000000000000..051affcf8b241 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.mk.xlf @@ -0,0 +1,83 @@ + + + + + + An authentication exception occurred. + Настана грешка во автентикацијата. + + + Authentication credentials could not be found. + Акредитивите за автентикација не се пронајдени. + + + Authentication request could not be processed due to a system problem. + Барањето за автентикација не можеше да биде процесуирано заради системски проблем. + + + Invalid credentials. + Невалидни акредитиви. + + + Cookie has already been used by someone else. + Колачето е веќе користено од некој друг. + + + Not privileged to request the resource. + Немате привилегии за да го побарате ресурсот. + + + Invalid CSRF token. + Невалиден CSRF токен. + + + No authentication provider found to support the authentication token. + Не е пронајден провајдер за автентикација кој го поддржува токенот за автентикација. + + + No session available, it either timed out or cookies are not enabled. + Сесијата е недостапна, или е истечена, или колачињата не се овозможени. + + + No token could be found. + Токенот не е најден. + + + Username could not be found. + Корисничкото име не е најдено. + + + Account has expired. + Корисничката сметка е истечена. + + + Credentials have expired. + Акредитивите се истечени. + + + Account is disabled. + Корисничката сметка е деактивирана. + + + Account is locked. + Корисничката сметка е заклучена. + + + Too many failed login attempts, please try again later. + Премногу неуспешни обиди за најавување, ве молиме обидете се повторно подоцна. + + + Invalid or expired login link. + Неважечка или истечена врска за најавување. + + + Too many failed login attempts, please try again in %minutes% minute. + Премногу неуспешни обиди за најавување, обидете се повторно за %minutes% минута. + + + Too many failed login attempts, please try again in %minutes% minutes. + Премногу неуспешни обиди за најавување, обидете се повторно за %minutes% минути. + + + + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf new file mode 100644 index 0000000000000..eb15989839b8a --- /dev/null +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf @@ -0,0 +1,431 @@ + + + + + + This value should be false. + Оваа вредност треба да биде лажна. + + + This value should be true. + Оваа вредност треба да биде вистинита. + + + This value should be of type {{ type }}. + Оваа вредност треба да биде од типот {{ type }}. + + + This value should be blank. + Оваа вредност треба да биде празна. + + + The value you selected is not a valid choice. + Вредноста што ја одбравте не е валиден избор. + + + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. + Мора да одберете најмалку {{ limit }} избор.|Мора да одберете најмалку {{ limit }} изброи. + + + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. + Може да одберете најмногу {{ limit }} избор.|Мора да одберете најмногу {{ limit }} избори. + + + One or more of the given values is invalid. + Една или повеќе од дадените вредности не се валидни. + + + This field was not expected. + Ова поле не беше очекувано. + + + This field is missing. + Ова поле недостига. + + + This value is not a valid date. + Оваа вредност не е валиден датум. + + + This value is not a valid datetime. + Оваа вредност не е валиден датум и време. + + + This value is not a valid email address. + Оваа вредност не е валидна адреса за е-пошта. + + + The file could not be found. + Датотеката не е најдена. + + + The file is not readable. + Датотеката не може да биде прочитана. + + + The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. + Датотеката е премногу голема ({{ size }} {{ suffix }}). Максималната дозволена големина е {{ limit }} {{ suffix }}. + + + The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. + Миме типот на датотеката не е валиден ({{ type }}). Дозволените миме типови се {{ types }}. + + + This value should be {{ limit }} or less. + Оваа вредност треба да биде {{ limit }} или помалку. + + + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. + Оваа вредност е предолга. Треба да содржи {{ limit }} карактер или помалку.|Оваа вредност е предолга. Треба да содржи {{ limit }} карактери или помалку. + + + This value should be {{ limit }} or more. + Оваа вредност треба да е {{ limit }} или повеќе. + + + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. + Оваа вредност е прекратка. Треба да содржи {{ limit }} карактер или повеќе.|Оваа вредност е прекратка. Треба да содржи {{ limit }} карактери или повеќе. + + + This value should not be blank. + Ова поле не може да биде празно. + + + This value should not be null. + Оваа вредност не може да биде ништо (null). + + + This value should be null. + Оваа вредност треба да е ништо (null). + + + This value is not valid. + Оваа вредност не е валидна. + + + This value is not a valid time. + Оваа вредност не е валидно време. + + + This value is not a valid URL. + Оваа вредност не е валиден URL. + + + The two values should be equal. + Двете вредности треба да се еднакви. + + + The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. + Датотеката е премногу голема. Максималната дозволена големина е {{ limit }} {{ suffix }}. + + + The file is too large. + Датотеката е премногу голема. + + + The file could not be uploaded. + Датотеката не може да биде подигната. + + + This value should be a valid number. + Оваа вредност треба да е валиден број. + + + This file is not a valid image. + Оваа датотека не е валидна слика. + + + This is not a valid IP address. + Ова не е валидна IP адреса. + + + This value is not a valid language. + Оваа вредност не е валиден јазик. + + + This value is not a valid locale. + Оваа вредност не е валидна локализација. + + + This value is not a valid country. + Оваа вредност не е валидна земја. + + + This value is already used. + Оваа вредност веќе се користи. + + + The size of the image could not be detected. + Големината на сликата не може да се детектира. + + + The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. + Ширината на сликата е преголема ({{ width }}px). Максималната дозволена ширина е {{ max_width }}px. + + + The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. + Ширината на сликата е премала ({{ width }}px). Минималната дозволена ширина е {{ min_width }}px. + + + The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. + Висината на сликата е преголема ({{ height }}px). Максималната дозволена висина е {{ max_height }}px. + + + The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. + Висината на сликата е премала ({{ height }}px). Минималната дозволена висина е {{ min_height }}px. + + + This value should be the user's current password. + Оваа вредност треба да биде сегашната лозинка на корисникот. + + + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. + Оваа вредност треба да има точно {{ limit }} карактер.|Оваа вредност треба да има точно {{ limit }} карактери. + + + The file was only partially uploaded. + Датотеката е само делумно подигната. + + + No file was uploaded. + Датотеката не е подигната. + + + No temporary folder was configured in php.ini. + Ниту една привремена папка не е конфигурирана во php.ini. + + + Cannot write temporary file to disk. + Не може да се напише привремена датотека на дискот. + + + A PHP extension caused the upload to fail. + PHP екстензијата предизвика подигнувањето да биде неуспешно. + + + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. + Оваа колекција треба да содржи {{ limit }} елемент или повеќе.|Оваа колекција треба да содржи {{ limit }} елементи или повеќе. + + + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. + Оваа колекција треба да содржи {{ limit }} елемент или помалку.|Оваа колекција треба да содржи {{ limit }} елементи или помалку. + + + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. + Оваа колекција треба да содржи точно {{ limit }} елемент.|Оваа колекција треба да содржи точно {{ limit }} елементи. + + + Invalid card number. + Бројот на картичката не е валиден. + + + Unsupported card type or invalid card number. + Неподдржан тип на картичка или бројот на картичката не е валиден. + + + This is not a valid International Bank Account Number (IBAN). + Ова не е валиден број на меѓународна банкарска сметка (IBAN). + + + This value is not a valid ISBN-10. + Оваа вредност не е валиден ISBN-10. + + + This value is not a valid ISBN-13. + Оваа вредност не е валиден ISBN-13. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Оваа вредност не е ниту валиден ISBN-10 ниту валиден ISBN-13. + + + This value is not a valid ISSN. + Оваа вредност не е валиден ISSN. + + + This value is not a valid currency. + Оваа вредност не е валидна валута. + + + This value should be equal to {{ compared_value }}. + Оваа вредност треба да биде еднаква на {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Оваа вредност треба да е поголема од {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Оваа вредност треба да е поголема или еднаква на {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Оваа вредност треба да е идентична на {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Оваа вредност треба да е помала од {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Оваа вредност треба да е помала или еднаква на {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Оваа вредност треба да не биде еднаква на {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Оваа вредност треба да не биде идентична со {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Соодносот на сликата е преголем ({{ ratio }}).Максималниот дозволен сооднос е {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Соодносот на сликата е премал ({{ ratio }}). Минималниот дозволен сооднос е {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Сликата е квадратна ({{ width }}x{{ height }}px). Квадратни слики не се дозволени. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Сликата е ориентирана кон пејзаж ({{ width }}x{{ height }}px). Сликите ориентирани кон пејзаж не се дозволени. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Сликата е ориентирана кон портрет ({{ width }}x{{ height }}px). Сликите ориентирани кон портрет не се дозволени. + + + An empty file is not allowed. + Празна датотека не е дозволена. + + + The host could not be resolved. + Хостот е недостапен. + + + This value does not match the expected {{ charset }} charset. + Оваа вредност не се совпаѓа со очекуваниот {{ charset }} сет на карактери (charset). + + + This is not a valid Business Identifier Code (BIC). + Ова не е валиден бизнис идентификациски код (BIC). + + + Error + Грешка + + + This is not a valid UUID. + Ова не е валиден универзален уникатен идентификатор (UUID). + + + This value should be a multiple of {{ compared_value }}. + Оваа вредност треба да биде повеќекратна од {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Овој бизнис идентификациски код (BIC) не е поврзан со IBAN {{ iban }}. + + + This value should be valid JSON. + Оваа вредност треба да биде валиден JSON. + + + This collection should contain only unique elements. + Оваа колекција треба да содржи само уникатни елементи. + + + This value should be positive. + Оваа вредност треба да биде позитивна. + + + This value should be either positive or zero. + Оваа вредност треба да биде или позитивна или нула. + + + This value should be negative. + Оваа вредност треба да биде негативна. + + + This value should be either negative or zero. + Оваа вредност треба да биде или негативна или нула. + + + This value is not a valid timezone. + Оваа вредност не е валидна временска зона. + + + 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 }}. + Оваа вредност треба да е помеѓу {{ min }} и {{ max }}. + + + This value is not a valid hostname. + Оваа вредност не е валидно име за мрежниот сметач (hostname). + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Бројот на елементи во оваа колекција треба да биде повеќекратен од {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Оваа вредност треба да задоволува најмалку едно од следните ограничувања: + + + Each element of this collection should satisfy its own set of constraints. + Секој елемент од оваа колекција треба да задоволува сопствен сет на ограничувања. + + + This value is not a valid International Securities Identification Number (ISIN). + Оваа вредност не е важечки меѓународен идентификациски број за хартии од вредност (ISIN). + + + This value should be a valid expression. + Оваа вредност треба да биде валиден израз. + + + This value is not a valid CSS color. + Оваа вредност не е валидна CSS боја. + + + This value is not a valid CIDR notation. + Оваа вредност не е валидна CIDR ознака. + + + The value of the netmask should be between {{ min }} and {{ max }}. + Вредноста на мрежната маска (netmask) треба да биде помеѓу {{ min }} и {{ max }}. + + + 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. + Името на датотеката е предолго. Треба да има {{ filename_max_length }} карактер има помалку.|Името на датотеката е предолго. Треба да има {{ filename_max_length }} карактери или помалку. + + + The password strength is too low. Please use a stronger password. + Оваа лозинка е премногу едноставна. Ве молиме користете посилна лозинка. + + + This value contains characters that are not allowed by the current restriction-level. + Оваа вредност содржи карактери кои не се дозволени од тековното ниво на ограничување. + + + Using invisible characters is not allowed. + Користењето на невидливи знаци не е дозволено. + + + Mixing numbers from different scripts is not allowed. + Не е дозволено мешање на броеви од различни скрипти. + + + Using hidden overlay characters is not allowed. + Не е дозволено користење на скриени знаци за преклопување. + + + + From 578a15200b33c21d161b40261b0a8ef74119008c Mon Sep 17 00:00:00 2001 From: Markus Fasselt Date: Thu, 7 Sep 2023 21:58:43 +0200 Subject: [PATCH 07/23] [Cache] fix using multiple Redis Sentinel hosts when the first one is not resolvable --- src/Symfony/Component/Cache/Traits/RedisTrait.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 220e65e744d43..0e7740e628369 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -217,8 +217,11 @@ public static function createConnection(string $dsn, array $options = []) } $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra); - if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) { - [$host, $port] = $address; + try { + if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) { + [$host, $port] = $address; + } + } catch (\RedisException $e) { } } while (++$hostIndex < \count($hosts) && !$address); From c557647ede0bae07098067bb25c2eaaf49277a5b Mon Sep 17 00:00:00 2001 From: Uladzimir Tsykun Date: Mon, 11 Sep 2023 18:39:34 +0200 Subject: [PATCH 08/23] Make tests green again --- .../Component/VarDumper/Tests/Dumper/CliDumperTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index 7809fcdb9f523..1c7dcc07ff4e9 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -553,6 +553,10 @@ public function testDumpArrayWithColor($value, $flags, $expectedOut) public function testCollapse() { + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->markTestSkipped('This test cannot be run on Windows.'); + } + $stub = new Stub(); $stub->type = Stub::TYPE_OBJECT; $stub->class = 'stdClass'; From 338e2da2d2e57cbbafac2d68713e529bce918572 Mon Sep 17 00:00:00 2001 From: Christopher Georg Date: Tue, 12 Sep 2023 09:44:46 +0200 Subject: [PATCH 09/23] chore: fix ci deprecations --- .github/workflows/integration-tests.yml | 4 ++-- .github/workflows/intl-data-tests.yml | 2 +- .github/workflows/package-tests.yml | 2 +- .github/workflows/phpunit-bridge.yml | 2 +- .github/workflows/psalm.yml | 4 ++-- .github/workflows/unit-tests.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index dc80c6fb28ce6..6e785c383a0f1 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -107,7 +107,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install system dependencies run: | @@ -191,7 +191,7 @@ jobs: # sudo rm -rf .phpunit # [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit - - uses: marceloprado/has-changed-path@v1 + - uses: marceloprado/has-changed-path@v1.0.1 id: changed-translation-files with: paths: src/**/Resources/translations/*.xlf diff --git a/.github/workflows/intl-data-tests.yml b/.github/workflows/intl-data-tests.yml index 8db09e52912af..ac2b8d41237ad 100644 --- a/.github/workflows/intl-data-tests.yml +++ b/.github/workflows/intl-data-tests.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install system dependencies run: | diff --git a/.github/workflows/package-tests.yml b/.github/workflows/package-tests.yml index a6955dbead472..1840d30f091a6 100644 --- a/.github/workflows/package-tests.yml +++ b/.github/workflows/package-tests.yml @@ -14,7 +14,7 @@ jobs: runs-on: Ubuntu-20.04 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Fetch branch from where the PR started run: git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* diff --git a/.github/workflows/phpunit-bridge.yml b/.github/workflows/phpunit-bridge.yml index 2229bbc866655..f63c02bc31925 100644 --- a/.github/workflows/phpunit-bridge.yml +++ b/.github/workflows/phpunit-bridge.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 219b8677325d0..27b51d5af7428 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -30,12 +30,12 @@ jobs: coverage: none - name: Checkout target branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.base_ref }} - name: Checkout PR - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install dependencies run: | diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 199887754e036..94b69e6c9891c 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 From 4312e96c28eec5ba8825d71f8b751aa4e37f7df5 Mon Sep 17 00:00:00 2001 From: soyuka Date: Sun, 27 Aug 2023 12:21:37 +0200 Subject: [PATCH 10/23] [FrameworkBundle] no serializer mapping cache in debug mode without enable_annotations There's no reason we should disable the cache only without `enable_annotations`, when working only with attributes, in debug mode the cache is enabled which is why we often need to clear cache when changing a serialized object to get the changes. --- .../DependencyInjection/FrameworkExtension.php | 7 ++++--- .../DependencyInjection/FrameworkExtensionTestCase.php | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 206bda1039a44..da60eeabb41c9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1790,14 +1790,15 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $container->removeDefinition('serializer.normalizer.mime_message'); } + if ($container->getParameter('kernel.debug')) { + $container->removeDefinition('serializer.mapping.cache_class_metadata_factory'); + } + $serializerLoaders = []; if (isset($config['enable_annotations']) && $config['enable_annotations']) { if (\PHP_VERSION_ID < 80000 && !$this->annotationsConfigEnabled) { throw new \LogicException('"enable_annotations" on the serializer cannot be set as the PHP version is lower than 8 and Annotations support is disabled. Consider upgrading PHP.'); } - if ($container->getParameter('kernel.debug')) { - $container->removeDefinition('serializer.mapping.cache_class_metadata_factory'); - } $annotationLoader = new Definition( 'Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index d1a0f52eac4fb..f5429d617b1a7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -1530,6 +1530,12 @@ public function testSerializerCacheActivated() public function testSerializerCacheUsedWithoutAnnotationsAndMappingFiles() { $container = $this->createContainerFromFile('serializer_mapping_without_annotations', ['kernel.debug' => true, 'kernel.container_class' => __CLASS__]); + $this->assertFalse($container->hasDefinition('serializer.mapping.cache_class_metadata_factory')); + } + + public function testSerializerCacheUsedWithoutAnnotationsAndMappingFilesNoDebug() + { + $container = $this->createContainerFromFile('serializer_mapping_without_annotations', ['kernel.debug' => false, 'kernel.container_class' => __CLASS__]); $this->assertTrue($container->hasDefinition('serializer.mapping.cache_class_metadata_factory')); } From 4264558fea9705c22c14fce0374db49efe665a09 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 13 Sep 2023 13:47:37 +0200 Subject: [PATCH 11/23] [String] Update wcswidth data with Unicode 15.1 --- .../String/Resources/WcswidthDataGenerator.php | 2 +- .../Resources/data/wcswidth_table_wide.php | 18 +++++++++++++++--- .../Resources/data/wcswidth_table_zero.php | 4 ++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/String/Resources/WcswidthDataGenerator.php b/src/Symfony/Component/String/Resources/WcswidthDataGenerator.php index 69d32e292a990..7443d051ee14d 100644 --- a/src/Symfony/Component/String/Resources/WcswidthDataGenerator.php +++ b/src/Symfony/Component/String/Resources/WcswidthDataGenerator.php @@ -46,7 +46,7 @@ private function writeWideWidthData(): void $version = $matches[1]; - if (!preg_match_all('/^([A-H\d]{4,})(?:\.\.([A-H\d]{4,}))?;[W|F]/m', $content, $matches, \PREG_SET_ORDER)) { + if (!preg_match_all('/^([A-H\d]{4,})(?:\.\.([A-H\d]{4,}))? +; [W|F]/m', $content, $matches, \PREG_SET_ORDER)) { throw new RuntimeException('The wide width pattern did not match anything.'); } diff --git a/src/Symfony/Component/String/Resources/data/wcswidth_table_wide.php b/src/Symfony/Component/String/Resources/data/wcswidth_table_wide.php index 5a647e67bf30f..8314c8fd504c2 100644 --- a/src/Symfony/Component/String/Resources/data/wcswidth_table_wide.php +++ b/src/Symfony/Component/String/Resources/data/wcswidth_table_wide.php @@ -3,8 +3,8 @@ /* * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.0.0 - * Date: 2022-10-05T17:16:36+02:00 + * Unicode version: 15.1.0 + * Date: 2023-09-13T11:47:12+00:00 */ return [ @@ -166,7 +166,7 @@ ], [ 12272, - 12283, + 12287, ], [ 12288, @@ -396,6 +396,10 @@ 12736, 12771, ], + [ + 12783, + 12783, + ], [ 12784, 12799, @@ -1110,6 +1114,14 @@ ], [ 191457, + 191471, + ], + [ + 191472, + 192093, + ], + [ + 192094, 194559, ], [ diff --git a/src/Symfony/Component/String/Resources/data/wcswidth_table_zero.php b/src/Symfony/Component/String/Resources/data/wcswidth_table_zero.php index 9ae7330325291..e5b26a21515ea 100644 --- a/src/Symfony/Component/String/Resources/data/wcswidth_table_zero.php +++ b/src/Symfony/Component/String/Resources/data/wcswidth_table_zero.php @@ -3,8 +3,8 @@ /* * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.0.0 - * Date: 2022-10-05T17:16:37+02:00 + * Unicode version: 15.1.0 + * Date: 2023-09-13T11:47:13+00:00 */ return [ From fdef0abb6e098430320cad11e86ee6f9d569a5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20H=C3=A9lias?= Date: Thu, 14 Sep 2023 22:49:15 +0200 Subject: [PATCH 12/23] [HttpClient] Fix TraceableResponse if response has no destruct method --- .../Component/HttpClient/Response/TraceableResponse.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php index d656c0a5f94d7..3bf1571fda1fb 100644 --- a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php +++ b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php @@ -57,7 +57,9 @@ public function __wakeup() public function __destruct() { try { - $this->response->__destruct(); + if (method_exists($this->response, '__destruct')) { + $this->response->__destruct(); + } } finally { if ($this->event && $this->event->isStarted()) { $this->event->stop(); From 35341187ba3ba6078552ff4e308b6a470b644491 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 16 Sep 2023 13:22:53 +0200 Subject: [PATCH 13/23] [Translator] Fix support for `default_path` in XML --- .../FrameworkBundle/Resources/config/schema/symfony-1.0.xsd | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 29f64dad9bed9..faee50e2528a8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -191,6 +191,7 @@ + From 4d65f302bf0928fe2140f565091949ce986c4dc3 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Mon, 18 Sep 2023 17:40:31 +0200 Subject: [PATCH 14/23] [SecurityBundle][PasswordHasher] Fix password migration with custom hasher service with security bundle config --- .../DependencyInjection/SecurityExtension.php | 5 +- .../SecurityExtensionTest.php | 27 ++++++++++ .../Hasher/PasswordHasherFactory.php | 50 ++++++++++++------- .../Hasher/PasswordHasherFactoryTest.php | 33 ++++++++++++ 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index d64b2c38ac7e7..c165024b68d0d 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -848,7 +848,10 @@ private function createHasher(array $config) { // a custom hasher service if (isset($config['id'])) { - return new Reference($config['id']); + return $config['migrate_from'] ?? false ? [ + 'instance' => new Reference($config['id']), + 'migrate_from' => $config['migrate_from'], + ] : new Reference($config['id']); } if ($config['migrate_from'] ?? false) { diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 71ca327ca40c6..eef68e4c3de46 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -881,6 +881,33 @@ public function testLegacyAuthorizationManagerSignature() $this->assertEquals('%security.access.always_authenticate_before_granting%', (string) $args[3]); } + public function testCustomHasherWithMigrateFrom() + { + $container = $this->getRawContainer(); + + $container->loadFromExtension('security', [ + 'enable_authenticator_manager' => true, + 'password_hashers' => [ + 'legacy' => 'md5', + 'App\User' => [ + 'id' => 'App\Security\CustomHasher', + 'migrate_from' => 'legacy', + ], + ], + 'firewalls' => ['main' => ['http_basic' => true]], + ]); + + $container->compile(); + + $hashersMap = $container->getDefinition('security.password_hasher_factory')->getArgument(0); + + $this->assertArrayHasKey('App\User', $hashersMap); + $this->assertEquals($hashersMap['App\User'], [ + 'instance' => new Reference('App\Security\CustomHasher'), + 'migrate_from' => ['legacy'], + ]); + } + protected function getRawContainer() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php b/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php index dd7e015c1ecd2..116301c04a441 100644 --- a/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php +++ b/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php @@ -71,6 +71,14 @@ public function getPasswordHasher($user): PasswordHasherInterface */ private function createHasher(array $config, bool $isExtra = false): PasswordHasherInterface { + if (isset($config['instance'])) { + if (!isset($config['migrate_from'])) { + return $config['instance']; + } + + $config = $this->getMigratingPasswordConfig($config); + } + if (isset($config['algorithm'])) { $rawConfig = $config; $config = $this->getHasherConfigFromAlgorithm($config); @@ -142,24 +150,8 @@ private function getHasherConfigFromAlgorithm(array $config): array ]; } - if ($frompasswordHashers = ($config['migrate_from'] ?? false)) { - unset($config['migrate_from']); - $hasherChain = [$this->createHasher($config, true)]; - - foreach ($frompasswordHashers as $name) { - if (isset($this->passwordHashers[$name])) { - $hasher = $this->createHasherUsingAdapter($name); - } else { - $hasher = $this->createHasher(['algorithm' => $name], true); - } - - $hasherChain[] = $hasher; - } - - return [ - 'class' => MigratingPasswordHasher::class, - 'arguments' => $hasherChain, - ]; + if ($config['migrate_from'] ?? false) { + return $this->getMigratingPasswordConfig($config); } switch ($config['algorithm']) { @@ -239,4 +231,26 @@ private function getHasherConfigFromAlgorithm(array $config): array ], ]; } + + private function getMigratingPasswordConfig(array $config): array + { + $frompasswordHashers = $config['migrate_from']; + unset($config['migrate_from']); + $hasherChain = [$this->createHasher($config, true)]; + + foreach ($frompasswordHashers as $name) { + if ($this->passwordHashers[$name] ?? false) { + $hasher = $this->createHasherUsingAdapter($name); + } else { + $hasher = $this->createHasher(['algorithm' => $name], true); + } + + $hasherChain[] = $hasher; + } + + return [ + 'class' => MigratingPasswordHasher::class, + 'arguments' => $hasherChain, + ]; + } } diff --git a/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php b/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php index 1f24a0d3cace2..1b97eedcdac48 100644 --- a/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php +++ b/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php @@ -49,6 +49,17 @@ public function testGetHasherWithService() $this->assertEquals($expectedHasher->hash('foo', ''), $hasher->hash('foo', '')); } + public function testGetHasherWithInstance() + { + $factory = new PasswordHasherFactory([ + PasswordAuthenticatedUserInterface::class => ['instance' => new MessageDigestPasswordHasher('sha1')], + ]); + + $hasher = $factory->getPasswordHasher($this->createMock(PasswordAuthenticatedUserInterface::class)); + $expectedHasher = new MessageDigestPasswordHasher('sha1'); + $this->assertEquals($expectedHasher->hash('foo', ''), $hasher->hash('foo', '')); + } + public function testGetHasherWithClassName() { $factory = new PasswordHasherFactory([ @@ -163,6 +174,28 @@ public function testMigrateFrom() $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null)); } + public function testMigrateFromWithCustomInstance() + { + if (!SodiumPasswordHasher::isSupported()) { + $this->markTestSkipped('Sodium is not available'); + } + + $sodium = new SodiumPasswordHasher(); + + $factory = new PasswordHasherFactory([ + 'digest_hasher' => $digest = new MessageDigestPasswordHasher('sha256'), + SomeUser::class => ['instance' => $sodium, 'migrate_from' => ['bcrypt', 'digest_hasher']], + ]); + + $hasher = $factory->getPasswordHasher(SomeUser::class); + $this->assertInstanceOf(MigratingPasswordHasher::class, $hasher); + + $this->assertTrue($hasher->verify((new SodiumPasswordHasher())->hash('foo', null), 'foo', null)); + $this->assertTrue($hasher->verify((new NativePasswordHasher(null, null, null, \PASSWORD_BCRYPT))->hash('foo', null), 'foo', null)); + $this->assertTrue($hasher->verify($digest->hash('foo', null), 'foo', null)); + $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null)); + } + /** * @group legacy */ From 5ad2b5a6022d3aa51f52a2dae7d687ae57ce43b1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 18 Sep 2023 17:58:13 +0200 Subject: [PATCH 15/23] Update the PR template --- .github/PULL_REQUEST_TEMPLATE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0dfc06eb7c16b..f56136de940d3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,14 +1,14 @@ | Q | A | ------------- | --- -| Branch? | 6.4 for features / 5.4, or 6.3 for bug fixes +| Branch? | 6.4 for features / 5.4 or 6.3 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no | Tickets | Fix #... | License | MIT -| Doc PR | symfony/symfony-docs#... +