diff --git a/.appveyor.yml b/.appveyor.yml index 35847e4fc3727..1a14319db7c73 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,7 +12,6 @@ init: - SET SYMFONY_DEPRECATIONS_HELPER=strict - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 - - SET SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f install: @@ -20,8 +19,8 @@ install: - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.2.5-Win32-VC15-x86.zip - 7z x php-7.2.5-Win32-VC15-x86.zip -y >nul - cd ext - - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.17-7.2-ts-vc15-x86.zip - - 7z x php_apcu-5.1.17-7.2-ts-vc15-x86.zip -y >nul + - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.19-7.2-ts-vc15-x86.zip + - 7z x php_apcu-5.1.19-7.2-ts-vc15-x86.zip -y >nul - cd .. - copy /Y php.ini-development php.ini-min - echo memory_limit=-1 >> php.ini-min diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index c4559a084a466..0820ae8d918b3 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -157,7 +157,6 @@ jobs: - name: Run tests run: ./phpunit --group integration -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=1 # to be removed once DbalLogger is compatible with dbal 3.2+ REDIS_HOST: localhost REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' REDIS_SENTINEL_HOSTS: 'localhost:26379' diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 685d08e1b1d9d..c60d92ba61cce 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -63,7 +63,6 @@ jobs: echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV - echo SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 >> $GITHUB_ENV # to be removed once DbalLogger is compatible with dbal 3.2+ SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+') diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md index f73800bc11f80..ceeefa8cad098 100644 --- a/CHANGELOG-5.3.md +++ b/CHANGELOG-5.3.md @@ -7,6 +7,15 @@ in 5.3 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.3.0...v5.3.1 +* 5.3.12 (2021-11-24) + + * security #cve-2021-41268 [SecurityBundle] Default signature_properties to the previous behavior (wouterj) + * security #cve-2021-41267 [HttpKernel] Fix missing extra trusted header in sub-request (jderusse) + * security #cve-2021-41270 [Serializer] Use single quote to escape formulas (jderusse) + * bug #44232 [Cache] fix connecting to local Redis sockets (nicolas-grekas) + * bug #44204 [HttpClient] fix closing curl multi handle when destructing client (nicolas-grekas) + * bug #44208 [Process] exclude argv/argc from possible default env vars (nicolas-grekas) + * 5.3.11 (2021-11-22) * bug #44188 [VarExporter] fix exporting declared but unset properties when __sleep() is implemented (nicolas-grekas) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 98ea5ab9c9e74..5ba6dab3b6129 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,20 @@ in 5.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.4.0...v5.4.1 +* 5.4.0 (2021-11-29) + + * bug #44309 [Messenger] Leverage DBAL's getNativeConnection() method (derrabus) + * bug #44300 [FrameworkBundle] Fix property-info phpstan extractor discovery (1ed) + * feature #44271 [Notifier] add Vonage bridge to replace the Nexmo one (nicolas-grekas) + * bug #44187 [Translation] [Loco] Fix idempotency of LocoProvider write method (welcoMattic) + * bug #43992 [Security] Do not overwrite already stored tokens for REMOTE_USER authentication (stlrnz) + * bug #43876 [Validator] Fix validation for single level domains (HypeMC) + * bug #44327 [Debug][ErrorHandler] Increased the reserved memory from 10k to 32k (sakalys) + * bug #44261 [Process] intersect with getenv() in case-insensitive manner to get default envs (stable-staple) + * bug #44295 [Serializer] fix support for lazy/unset properties (nicolas-grekas) + * bug #44277 [Notifier] Fix AllMySms bridge body content (afiocre) + * bug #44269 [DoctrineBridge] Revert " add support for the JSON type" (dunglas) + * 5.4.0-RC1 (2021-11-24) * security #cve-2021-41268 [SecurityBundle] Default signature_properties to the previous behavior (wouterj) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 92b9b528b9c50..b5e87ad1280f4 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -12,8 +12,8 @@ The Symfony Connect username in parenthesis allows to get more information - Tobias Schultze (tobion) - Robin Chalas (chalas_r) - Christophe Coevoet (stof) - - Wouter De Jong (wouterj) - Jérémy DERUSSÉ (jderusse) + - Wouter De Jong (wouterj) - Grégoire Pineau (lyrixx) - Maxime Steinhausser (ogizanagi) - Kévin Dunglas (dunglas) @@ -58,9 +58,9 @@ The Symfony Connect username in parenthesis allows to get more information - Diego Saint Esteben (dosten) - Grégoire Paris (greg0ire) - Alexandre Salomé (alexandresalome) + - Jérôme Tamarelle (gromnan) - William Durand (couac) - ornicar - - Jérôme Tamarelle (gromnan) - Konstantin Myakshin (koc) - Dany Maillard (maidmaid) - Francis Besset (francisbesset) @@ -116,11 +116,11 @@ The Symfony Connect username in parenthesis allows to get more information - John Wards (johnwards) - Tomas Norkūnas (norkunas) - Baptiste Clavié (talus) + - HypeMC (hypemc) - Antoine Hérault (herzult) - Paráda József (paradajozsef) - Alexandre Daubois (alexandre-daubois) - Vincent Langlet (deviling) - - HypeMC (hypemc) - Massimiliano Arione (garak) - Arnaud Le Blanc (arnaud-lb) - Przemysław Bogusz (przemyslaw-bogusz) @@ -825,6 +825,7 @@ The Symfony Connect username in parenthesis allows to get more information - Rodrigo Borrego Bernabé (rodrigobb) - Emanuele Iannone - Jörn Lang (j.lang) + - Petr Duda (petrduda) - Marcos Rezende (rezehnde) - Denis Gorbachev (starfall) - Peter van Dommelen @@ -1350,7 +1351,6 @@ The Symfony Connect username in parenthesis allows to get more information - Simon Leblanc (leblanc_simon) - Matthieu Mota (matthieumota) - Mikhail Prosalov (mprosalov) - - Petr Duda (petrduda) - Ronny López (ronnylt) - abdul malik ikhsan (samsonasik) - Henry Snoek (snoek09) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index d37a90fa4a20f..6474440f9acb9 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -75,7 +75,7 @@ public static function createChoiceLabel(object $choice): string */ public static function createChoiceName(object $choice, $key, string $value): string { - return str_replace('-', '_', (string) $value); + return str_replace('-', '_', $value); } /** diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index c1eeb5e3ded96..8148ce0d3882d 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -168,7 +168,6 @@ public function getTypes(string $class, string $property, array $context = []) switch ($typeOfField) { case Types::ARRAY: case 'json_array': - case 'json': return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)]; case Types::SIMPLE_ARRAY: @@ -283,7 +282,6 @@ private function getPhpType(string $doctrineType): ?string case Types::ARRAY: case Types::SIMPLE_ARRAY: case 'json_array': - case 'json': return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php index d79b7d4998134..710e87a15e0b8 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php @@ -15,6 +15,9 @@ use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Logger\DbalLogger; +/** + * @group legacy + */ class DbalLoggerTest extends TestCase { /** @@ -46,8 +49,8 @@ public function getLogFixtures() ['SQL', null, []], ['SQL', [], []], ['SQL', ['foo' => 'bar'], ['foo' => 'bar']], - ['SQL', ['foo' => "\x7F\xFF"], ['foo' => DbalLogger::BINARY_DATA_VALUE]], - ['SQL', ['foo' => "bar\x7F\xFF"], ['foo' => DbalLogger::BINARY_DATA_VALUE]], + ['SQL', ['foo' => "\x7F\xFF"], ['foo' => '(binary value)']], + ['SQL', ['foo' => "bar\x7F\xFF"], ['foo' => '(binary value)']], ['SQL', ['foo' => ''], ['foo' => '']], ]; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index 3f0fb80ab04ce..3b9419d174a60 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -207,7 +207,7 @@ public function typesProvider() new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class) )]], - ['json', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]], + ['json', null], ]; return $provider; diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php index 99248c508ccab..4420ef3d0e46c 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php @@ -107,7 +107,7 @@ private function __construct(array $thresholds = [], $regex = '', $verboseOutput if (!isset($this->verboseOutput[$group])) { throw new \InvalidArgumentException(sprintf('Unsupported verbosity group "%s", expected one of "%s".', $group, implode('", "', array_keys($this->verboseOutput)))); } - $this->verboseOutput[$group] = (bool) $status; + $this->verboseOutput[$group] = $status; } if ($generateBaseline && !$baselineFile) { diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php index 2eb1bbce038c6..a0953a2d9f346 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php @@ -57,7 +57,7 @@ protected function setUp(): void protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -66,42 +66,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php index 6c84b32038b6e..b02d859f74856 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php @@ -107,7 +107,7 @@ public function testMoneyWidgetInIso() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -116,42 +116,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php index 5dbb7e5b6c8b8..33e1862afd74a 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php @@ -59,7 +59,7 @@ protected function setUp(): void protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -68,42 +68,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php index 285aa066e691d..41985a8ce2d85 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php @@ -111,7 +111,7 @@ public function testMoneyWidgetInIso() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -120,42 +120,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php index 042cbf0e40a7e..ef924884a4751 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5HorizontalLayoutTest.php @@ -59,7 +59,7 @@ protected function setUp(): void protected function renderForm(FormView $view, array $vars = []): string { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []): string @@ -68,42 +68,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []): $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []): string { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []): string { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true): void diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php index 1bf4a315fab0b..8c0e54744f964 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap5LayoutTest.php @@ -111,7 +111,7 @@ public function testMoneyWidgetInIso() protected function renderForm(FormView $view, array $vars = []): string { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []): string @@ -120,42 +120,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []): $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []): string { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []): string { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []): string { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true): void diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 3190b4cb74bed..69f0c8f680933 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -331,7 +331,7 @@ public function testLabelHtmlIsTrue() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -340,42 +340,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php index 48811750a82e0..b70a250e19639 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -217,7 +217,7 @@ public function testLabelHtmlIsTrue() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -226,42 +226,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php index 523c481a4ba06..cfc9ae2fbee4c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php @@ -14,12 +14,15 @@ use Psr\Container\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Service\ServiceProviderInterface; /** * A console command for retrieving information about event dispatcher. @@ -120,6 +123,31 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestArgumentValuesFor('event')) { + $dispatcherServiceName = $input->getOption('dispatcher'); + if ($this->dispatchers->has($dispatcherServiceName)) { + $dispatcher = $this->dispatchers->get($dispatcherServiceName); + $suggestions->suggestValues(array_keys($dispatcher->getListeners())); + } + + return; + } + + if ($input->mustSuggestOptionValuesFor('dispatcher')) { + if ($this->dispatchers instanceof ServiceProviderInterface) { + $suggestions->suggestValues(array_keys($this->dispatchers->getProvidedServices())); + } + + return; + } + + if ($input->mustSuggestOptionValuesFor('format')) { + $suggestions->suggestValues((new DescriptorHelper())->getFormats()); + } + } + private function searchForEvent(EventDispatcherInterface $dispatcher, string $needle): array { $output = []; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 22517ad5c7d3f..9b761dbdd3934 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -16,6 +16,7 @@ use Doctrine\Common\Annotations\Reader; use Http\Client\HttpClient; use phpDocumentor\Reflection\DocBlockFactoryInterface; +use phpDocumentor\Reflection\Types\ContextFactory; use PHPStan\PhpDocParser\Parser\PhpDocParser; use Psr\Cache\CacheItemPoolInterface; use Psr\Container\ContainerInterface as PsrContainerInterface; @@ -157,6 +158,7 @@ use Symfony\Component\Notifier\Bridge\Telnyx\TelnyxTransportFactory; use Symfony\Component\Notifier\Bridge\TurboSms\TurboSmsTransport; use Symfony\Component\Notifier\Bridge\Twilio\TwilioTransportFactory; +use Symfony\Component\Notifier\Bridge\Vonage\VonageTransportFactory; use Symfony\Component\Notifier\Bridge\Yunpian\YunpianTransportFactory; use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory; use Symfony\Component\Notifier\Notifier; @@ -1849,7 +1851,7 @@ private function registerPropertyInfoConfiguration(ContainerBuilder $container, if ( ContainerBuilder::willBeAvailable('phpstan/phpdoc-parser', PhpDocParser::class, ['symfony/framework-bundle', 'symfony/property-info'], true) - && ContainerBuilder::willBeAvailable('phpdocumentor/type-resolver', PhpDocParser::class, ['symfony/framework-bundle', 'symfony/property-info'], true) + && ContainerBuilder::willBeAvailable('phpdocumentor/type-resolver', ContextFactory::class, ['symfony/framework-bundle', 'symfony/property-info'], true) ) { $definition = $container->register('property_info.phpstan_extractor', PhpStanExtractor::class); $definition->addTag('property_info.type_extractor', ['priority' => -1000]); @@ -2540,6 +2542,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ TelnyxTransportFactory::class => 'notifier.transport_factory.telnyx', TurboSmsTransport::class => 'notifier.transport_factory.turbo-sms', TwilioTransportFactory::class => 'notifier.transport_factory.twilio', + VonageTransportFactory::class => 'notifier.transport_factory.vonage', YunpianTransportFactory::class => 'notifier.transport_factory.yunpian', ZulipTransportFactory::class => 'notifier.transport_factory.zulip', ]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php index 18620b30832cb..8e3bb4ce2abed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php @@ -52,6 +52,7 @@ use Symfony\Component\Notifier\Bridge\Telnyx\TelnyxTransportFactory; use Symfony\Component\Notifier\Bridge\TurboSms\TurboSmsTransportFactory; use Symfony\Component\Notifier\Bridge\Twilio\TwilioTransportFactory; +use Symfony\Component\Notifier\Bridge\Vonage\VonageTransportFactory; use Symfony\Component\Notifier\Bridge\Yunpian\YunpianTransportFactory; use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory; @@ -109,6 +110,11 @@ ->set('notifier.transport_factory.nexmo', NexmoTransportFactory::class) ->parent('notifier.transport_factory.abstract') ->tag('texter.transport_factory') + ->deprecate('symfony/framework-bundle', '5.4', 'The "%service_id% service is deprecated, use "notifier.transport_factory.vonage" instead.') + + ->set('notifier.transport_factory.vonage', VonageTransportFactory::class) + ->parent('notifier.transport_factory.abstract') + ->tag('texter.transport_factory') ->set('notifier.transport_factory.rocket-chat', RocketChatTransportFactory::class) ->parent('notifier.transport_factory.abstract') diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php new file mode 100644 index 0000000000000..ce653c6bfaaaa --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Command; + +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\Command\EventDispatcherDebugCommand; +use Symfony\Component\Console\Tester\CommandCompletionTester; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\EventDispatcher\EventDispatcher; + +class EventDispatcherDebugCommandTest extends TestCase +{ + /** + * @dataProvider provideCompletionSuggestions + */ + public function testComplete(array $input, array $expectedSuggestions) + { + $tester = $this->createCommandCompletionTester(); + + $suggestions = $tester->complete($input); + + $this->assertSame($expectedSuggestions, $suggestions); + } + + public function provideCompletionSuggestions() + { + yield 'event' => [[''], ['Symfony\Component\Mailer\Event\MessageEvent', 'console.command']]; + yield 'event for other dispatcher' => [['--dispatcher', 'other_event_dispatcher', ''], ['other_event', 'App\OtherEvent']]; + yield 'dispatcher' => [['--dispatcher='], ['event_dispatcher', 'other_event_dispatcher']]; + yield 'format' => [['--format='], ['txt', 'xml', 'json', 'md']]; + } + + private function createCommandCompletionTester(): CommandCompletionTester + { + $dispatcher = new EventDispatcher(); + $otherDispatcher = new EventDispatcher(); + + $dispatcher->addListener('event', ['Listener']); + $otherDispatcher->addListener('other_event', ['OtherListener']); + + $dispatchers = new ServiceLocator([ + 'event_dispatcher' => function () { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('Symfony\Component\Mailer\Event\MessageEvent', 'var_dump'); + $dispatcher->addListener('console.command', 'var_dump'); + + return $dispatcher; + }, + 'other_event_dispatcher' => function () { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('other_event', 'var_dump'); + $dispatcher->addListener('App\OtherEvent', 'var_dump'); + + return $dispatcher; + }, + ]); + $command = new EventDispatcherDebugCommand($dispatchers); + + return new CommandCompletionTester($command); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 9774c219f1cb3..6fe970f366f3f 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -1059,7 +1059,7 @@ private function createExpression(ContainerBuilder $container, string $expressio private function createRequestMatcher(ContainerBuilder $container, string $path = null, string $host = null, int $port = null, array $methods = [], array $ips = null, array $attributes = []): Reference { if ($methods) { - $methods = array_map('strtoupper', (array) $methods); + $methods = array_map('strtoupper', $methods); } if (null !== $ips) { diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index 06f434457771b..6aff151cc8bb8 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -38,7 +38,7 @@ public function __construct(string $resource, bool $exists = null) { $this->resource = $resource; if (null !== $exists) { - $this->exists = [(bool) $exists, null]; + $this->exists = [$exists, null]; } } diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php index 196d44f07edce..9f32b5a62a33f 100644 --- a/src/Symfony/Component/Config/Util/XmlUtils.php +++ b/src/Symfony/Component/Config/Util/XmlUtils.php @@ -239,12 +239,12 @@ public static function phpize($value) $raw = $value; $cast = (int) $value; - return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw); + return '0' == $value[0] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw); case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)): $raw = $value; $cast = (int) $value; - return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw); + return '0' == $value[1] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw); case 'true' === $lowercaseValue: return true; case 'false' === $lowercaseValue: diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php index 0e5202775b187..3a73f04b2383d 100644 --- a/src/Symfony/Component/Console/Question/Question.php +++ b/src/Symfony/Component/Console/Question/Question.php @@ -127,7 +127,7 @@ public function isHiddenFallback() */ public function setHiddenFallback(bool $fallback) { - $this->hiddenFallback = (bool) $fallback; + $this->hiddenFallback = $fallback; return $this; } diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index b30137cc9859d..7fc6752554f70 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -146,7 +146,7 @@ public function setDecoratedService(?string $id, string $renamedId = null, int $ if (null === $id) { $this->decoratedService = null; } else { - $this->decoratedService = [$id, $renamedId, (int) $priority]; + $this->decoratedService = [$id, $renamedId, $priority]; if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { $this->decoratedService[] = $invalidBehavior; diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 0d5c36e14e916..d0a016f06a866 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -214,7 +214,7 @@ private function parseDefinition(\DOMElement $service, string $file, Definition if ($alias = $service->getAttribute('alias')) { $this->validateAlias($service, $file); - $this->container->setAlias((string) $service->getAttribute('id'), $alias = new Alias($alias)); + $this->container->setAlias($service->getAttribute('id'), $alias = new Alias($alias)); if ($publicAttr = $service->getAttribute('public')) { $alias->setPublic(XmlUtils::phpize($publicAttr)); } elseif ($defaults->getChanges()['public'] ?? false) { @@ -352,7 +352,7 @@ private function parseDefinition(\DOMElement $service, string $file, Definition } if ('' === $tagName && '' === $tagName = $tag->getAttribute('name')) { - throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', (string) $service->getAttribute('id'), $file)); + throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', $service->getAttribute('id'), $file)); } $definition->addTag($tagName, $parameters); @@ -382,7 +382,7 @@ private function parseDefinition(\DOMElement $service, string $file, Definition } elseif ('null' === $decorationOnInvalid) { $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; } else { - throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, (string) $service->getAttribute('id'), $file)); + throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, $service->getAttribute('id'), $file)); } $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null; diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php index 2c885e3393b92..b1bf77568d4ac 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php @@ -109,7 +109,7 @@ public function set(string $name, $value) */ public function has(string $name) { - return \array_key_exists((string) $name, $this->parameters); + return \array_key_exists($name, $this->parameters); } /** diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index 1abafc15289f9..87e508405b734 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -111,7 +111,7 @@ class ErrorHandler public static function register(self $handler = null, bool $replace = true): self { if (null === self::$reservedMemory) { - self::$reservedMemory = str_repeat('x', 10240); + self::$reservedMemory = str_repeat('x', 32768); register_shutdown_function(__CLASS__.'::handleFatalError'); } @@ -348,7 +348,7 @@ public function scopeAt(int $levels, bool $replace = false): int public function traceAt(int $levels, bool $replace = false): int { $prev = $this->tracedErrors; - $this->tracedErrors = (int) $levels; + $this->tracedErrors = $levels; if (!$replace) { $this->tracedErrors |= $prev; } diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php index 7e389273f9f42..27589cdd5f57a 100644 --- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php +++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php @@ -64,7 +64,7 @@ public function current() // the logic here avoids redoing the same work in all iterations if (null === $subPathname = $this->subPath) { - $subPathname = $this->subPath = (string) $this->getSubPath(); + $subPathname = $this->subPath = $this->getSubPath(); } if ('' !== $subPathname) { $subPathname .= $this->directorySeparator; diff --git a/src/Symfony/Component/Form/AbstractRendererEngine.php b/src/Symfony/Component/Form/AbstractRendererEngine.php index 55917de1338c4..5641c420e28c4 100644 --- a/src/Symfony/Component/Form/AbstractRendererEngine.php +++ b/src/Symfony/Component/Form/AbstractRendererEngine.php @@ -68,7 +68,7 @@ public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true) // Do not cast, as casting turns objects into arrays of properties $this->themes[$cacheKey] = \is_array($themes) ? $themes : [$themes]; - $this->useDefaultThemes[$cacheKey] = (bool) $useDefaultThemes; + $this->useDefaultThemes[$cacheKey] = $useDefaultThemes; // Unset instead of resetting to an empty array, in order to allow // implementations (like TwigRendererEngine) to check whether $cacheKey diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index 959f6bcf782a8..b3185d1a376c6 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -66,7 +66,7 @@ public function createNamedBuilder(string $name, string $type = FormType::class, $type = $this->registry->getType($type); - $builder = $type->createBuilder($this, (string) $name, $options); + $builder = $type->createBuilder($this, $name, $options); // Explicitly call buildForm() in order to be able to override either // createBuilder() or buildForm() in the resolved form type diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index a5ad4df6d5b38..10e91ca1be30d 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1969,7 +1969,7 @@ protected function preparePathInfo() return '/'; } - return (string) $pathInfo; + return $pathInfo; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php index 2707d64ec7138..8aab3a1228edd 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php @@ -78,7 +78,7 @@ public function peek(string $type, array $default = []) */ public function peekAll() { - return \array_key_exists('display', $this->flashes) ? (array) $this->flashes['display'] : []; + return \array_key_exists('display', $this->flashes) ? $this->flashes['display'] : []; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php index 5535bc96441db..9b0cdeb7fe1d0 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -21,7 +21,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf public function __construct(\SessionHandlerInterface $handler) { $this->handler = $handler; - $this->wrapper = ($handler instanceof \SessionHandler); + $this->wrapper = $handler instanceof \SessionHandler; $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user'; } @@ -41,7 +41,7 @@ public function getHandler() #[\ReturnTypeWillChange] public function open($savePath, $sessionName) { - return (bool) $this->handler->open($savePath, $sessionName); + return $this->handler->open($savePath, $sessionName); } /** @@ -50,16 +50,16 @@ public function open($savePath, $sessionName) #[\ReturnTypeWillChange] public function close() { - return (bool) $this->handler->close(); + return $this->handler->close(); } /** - * @return string + * @return string|false */ #[\ReturnTypeWillChange] public function read($sessionId) { - return (string) $this->handler->read($sessionId); + return $this->handler->read($sessionId); } /** @@ -68,7 +68,7 @@ public function read($sessionId) #[\ReturnTypeWillChange] public function write($sessionId, $data) { - return (bool) $this->handler->write($sessionId, $data); + return $this->handler->write($sessionId, $data); } /** @@ -77,7 +77,7 @@ public function write($sessionId, $data) #[\ReturnTypeWillChange] public function destroy($sessionId) { - return (bool) $this->handler->destroy($sessionId); + return $this->handler->destroy($sessionId); } /** diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php index 6bb0b1808d80f..523f5c957f188 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php @@ -163,7 +163,7 @@ public function collect(Request $request, Response $response, \Throwable $except 'method' => $request->getMethod(), 'controller' => $this->parseController($request->attributes->get('_controller')), 'status_code' => $statusCode, - 'status_text' => Response::$statusTexts[(int) $statusCode], + 'status_text' => Response::$statusTexts[$statusCode], ]), 0, '/', null, $request->isSecure(), true, false, 'lax' )); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f55f5f693dcec..656324a4df7e8 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.0-RC1'; + public const VERSION = '5.4.0'; public const VERSION_ID = 50400; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'RC1'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; diff --git a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php index 30479fd3878b1..96b36f97e2a80 100644 --- a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php @@ -666,12 +666,12 @@ public function parseProvider() return [ ['prefix1', false, '->parse() does not parse a number with a string prefix.', 0], ['prefix1', false, '->parse() does not parse a number with a string prefix.', 0, false], - ['1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3], - ['1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3, false], + ['1.4suffix', 1.4, '->parse() parses a number with a string suffix.', 3], + ['1.4suffix', 1.4, '->parse() parses a number with a string suffix.', 3, false], ['1,234.4suffix', 1234.4, '->parse() parses a number with a string suffix.', 7], ['1,234.4suffix', 1.0, '->parse() parses a number with a string suffix.', 1, false], - ['-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3], - ['-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3, false], + ['-.4suffix', -0.4, '->parse() parses a negative dot float with suffix.', 3], + ['-.4suffix', -0.4, '->parse() parses a negative dot float with suffix.', 3, false], [',4', false, '->parse() does not parse when invalid grouping used.', 0], [',4', false, '->parse() does not parse when invalid grouping used.', 0, false], ['123,4', false, '->parse() does not parse when invalid grouping used.', 0], diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Adapter.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Adapter.php index 3106ba3ce4aa0..ff6d4d9f6a023 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Adapter.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Adapter.php @@ -72,7 +72,7 @@ public function escape(string $subject, string $ignore = '', int $flags = 0) $value = ldap_escape($subject, $ignore, $flags); // Per RFC 4514, leading/trailing spaces should be encoded in DNs, as well as carriage returns. - if ((int) $flags & \LDAP_ESCAPE_DN) { + if ($flags & \LDAP_ESCAPE_DN) { if (!empty($value) && ' ' === $value[0]) { $value = '\\20'.substr($value, 1); } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php index 4c221b7e4d4db..130ca0f9b4195 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php @@ -70,9 +70,13 @@ public function get(): ?array $this->listening = true; } - $wrappedConnection = $this->driverConnection->getWrappedConnection(); - if (!$wrappedConnection instanceof \PDO && $wrappedConnection instanceof DoctrinePdoConnection) { - $wrappedConnection = $wrappedConnection->getWrappedConnection(); + if (method_exists($this->driverConnection, 'getNativeConnection')) { + $wrappedConnection = $this->driverConnection->getNativeConnection(); + } else { + $wrappedConnection = $this->driverConnection->getWrappedConnection(); + if (!$wrappedConnection instanceof \PDO && $wrappedConnection instanceof DoctrinePdoConnection) { + $wrappedConnection = $wrappedConnection->getWrappedConnection(); + } } $notification = $wrappedConnection->pgsqlGetNotify(\PDO::FETCH_ASSOC, $this->configuration['get_notify_timeout']); diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php index 9a2d12eea25a8..c810f2620b4c1 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php @@ -474,7 +474,7 @@ public function add(string $body, array $headers, int $delayInMs = 0): void throw new TransportException(json_last_error_msg()); } - $score = (int) ($this->getCurrentTimeInMilliseconds() + $delayInMs); + $score = $this->getCurrentTimeInMilliseconds() + $delayInMs; $added = $this->connection->zadd($this->queue, ['NX'], $score, $message); } else { $message = json_encode([ diff --git a/src/Symfony/Component/Notifier/Bridge/AllMySms/AllMySmsTransport.php b/src/Symfony/Component/Notifier/Bridge/AllMySms/AllMySmsTransport.php index fab94304bf015..28508bdde3506 100644 --- a/src/Symfony/Component/Notifier/Bridge/AllMySms/AllMySmsTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/AllMySms/AllMySmsTransport.php @@ -64,7 +64,7 @@ protected function doSend(MessageInterface $message): SentMessage $endpoint = sprintf('https://%s/sms/send/', $this->getEndpoint()); $response = $this->client->request('POST', $endpoint, [ 'auth_basic' => $this->login.':'.$this->apiKey, - 'body' => [ + 'json' => [ 'from' => $this->from, 'to' => $message->getPhone(), 'text' => $message->getSubject(), diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php index 70313fb9f50f9..c69aeb6b4c0f7 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Notifier\Bridge\Nexmo; +trigger_deprecation('symfony/nexmo-notifier', '5.4', 'The "symfony/nexmo-notifier" package is deprecated, use "symfony/vonage-notifier" instead.'); + use Symfony\Component\Notifier\Exception\TransportException; use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException; use Symfony\Component\Notifier\Message\MessageInterface; @@ -23,6 +25,8 @@ /** * @author Fabien Potencier + * + * @deprecated since Symfony 5.4, use the Vonage bridge instead. */ final class NexmoTransport extends AbstractTransport { diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php index 6c7287b398658..f00b9232860bf 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php @@ -18,6 +18,8 @@ /** * @author Fabien Potencier + * + * @deprecated since Symfony 5.4, use the Vonage bridge instead. */ final class NexmoTransportFactory extends AbstractTransportFactory { diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/README.md b/src/Symfony/Component/Notifier/Bridge/Nexmo/README.md index 71b63069f5c0d..24006aabb35c2 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/README.md @@ -1,19 +1,7 @@ Nexmo Notifier ============== -Provides [Nexmo](https://nexmo.com) integration for Symfony Notifier. - -DSN example ------------ - -``` -NEXMO_DSN=nexmo://KEY:SECRET@default?from=FROM -``` - -where: - - `KEY` is your Nexmo key - - `SECRET` is your Nexmo secret - - `FROM` is your sender +The Nexmo bridge is deprecated, use the Vonage bridge instead. Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportFactoryTest.php index a44545b069e5b..907b98e1ccf70 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportFactoryTest.php @@ -15,6 +15,9 @@ use Symfony\Component\Notifier\Test\TransportFactoryTestCase; use Symfony\Component\Notifier\Transport\TransportFactoryInterface; +/** + * @group legacy + */ final class NexmoTransportFactoryTest extends TransportFactoryTestCase { /** diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php index 8473b3a8888a1..d52014957b1c6 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php @@ -19,6 +19,9 @@ use Symfony\Component\Notifier\Transport\TransportInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; +/** + * @group legacy + */ final class NexmoTransportTest extends TransportTestCase { /** diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json b/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json index 8f2051c4c5ac4..8550289e8542d 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/http-client": "^4.3|^5.0|^6.0", "symfony/notifier": "^5.3|^6.0" }, diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/.gitattributes b/src/Symfony/Component/Notifier/Bridge/Vonage/.gitattributes new file mode 100644 index 0000000000000..84c7add058fb5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/.gitignore b/src/Symfony/Component/Notifier/Bridge/Vonage/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Vonage/CHANGELOG.md new file mode 100644 index 0000000000000..3a08c7ededfcd --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +5.4 +--- + + * Add the bridge diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/LICENSE b/src/Symfony/Component/Notifier/Bridge/Vonage/LICENSE new file mode 100644 index 0000000000000..efb17f98e7dd3 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/README.md b/src/Symfony/Component/Notifier/Bridge/Vonage/README.md new file mode 100644 index 0000000000000..5f43d5e0ec6c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/README.md @@ -0,0 +1,24 @@ +Vonage Notifier +=============== + +Provides [Vonage](https://vonage.com) integration for Symfony Notifier. + +DSN example +----------- + +``` +VONAGE_DSN=vonage://KEY:SECRET@default?from=FROM +``` + +where: + - `KEY` is your Vonage key + - `SECRET` is your Vonage secret + - `FROM` is your sender + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/Tests/VonageTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Vonage/Tests/VonageTransportFactoryTest.php new file mode 100644 index 0000000000000..b25b549828847 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/Tests/VonageTransportFactoryTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Vonage\Tests; + +use Symfony\Component\Notifier\Bridge\Vonage\VonageTransportFactory; +use Symfony\Component\Notifier\Test\TransportFactoryTestCase; +use Symfony\Component\Notifier\Transport\TransportFactoryInterface; + +final class VonageTransportFactoryTest extends TransportFactoryTestCase +{ + /** + * @return VonageTransportFactory + */ + public function createFactory(): TransportFactoryInterface + { + return new VonageTransportFactory(); + } + + public function createProvider(): iterable + { + yield [ + 'vonage://host.test?from=0611223344', + 'vonage://apiKey:apiSecret@host.test?from=0611223344', + ]; + } + + public function supportsProvider(): iterable + { + yield [true, 'vonage://apiKey:apiSecret@default?from=0611223344']; + yield [false, 'somethingElse://apiKey:apiSecret@default?from=0611223344']; + } + + public function missingRequiredOptionProvider(): iterable + { + yield 'missing option: from' => ['vonage://apiKey:apiSecret@default']; + } + + public function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://apiKey:apiSecret@default?from=0611223344']; + yield ['somethingElse://apiKey:apiSecret@default']; // missing "from" option + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/Tests/VonageTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Vonage/Tests/VonageTransportTest.php new file mode 100644 index 0000000000000..dc545a02a9d78 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/Tests/VonageTransportTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Vonage\Tests; + +use Symfony\Component\Notifier\Bridge\Vonage\VonageTransport; +use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Test\TransportTestCase; +use Symfony\Component\Notifier\Transport\TransportInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +final class VonageTransportTest extends TransportTestCase +{ + /** + * @return VonageTransport + */ + public function createTransport(HttpClientInterface $client = null): TransportInterface + { + return new VonageTransport('apiKey', 'apiSecret', 'sender', $client ?? $this->createMock(HttpClientInterface::class)); + } + + public function toStringProvider(): iterable + { + yield ['vonage://rest.nexmo.com?from=sender', $this->createTransport()]; + } + + public function supportedMessagesProvider(): iterable + { + yield [new SmsMessage('0611223344', 'Hello!')]; + } + + public function unsupportedMessagesProvider(): iterable + { + yield [new ChatMessage('Hello!')]; + yield [$this->createMock(MessageInterface::class)]; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/VonageTransport.php b/src/Symfony/Component/Notifier/Bridge/Vonage/VonageTransport.php new file mode 100644 index 0000000000000..f47f41a70fefc --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/VonageTransport.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Vonage; + +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SentMessage; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Transport\AbstractTransport; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + */ +final class VonageTransport extends AbstractTransport +{ + // see https://developer.vonage.com/messaging/sms/overview + protected const HOST = 'rest.nexmo.com'; + + private $apiKey; + private $apiSecret; + private $from; + + public function __construct(string $apiKey, string $apiSecret, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null) + { + $this->apiKey = $apiKey; + $this->apiSecret = $apiSecret; + $this->from = $from; + + parent::__construct($client, $dispatcher); + } + + public function __toString(): string + { + return sprintf('vonage://%s?from=%s', $this->getEndpoint(), $this->from); + } + + public function supports(MessageInterface $message): bool + { + return $message instanceof SmsMessage; + } + + protected function doSend(MessageInterface $message): SentMessage + { + if (!$message instanceof SmsMessage) { + throw new UnsupportedMessageTypeException(__CLASS__, SmsMessage::class, $message); + } + + $response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/sms/json', [ + 'body' => [ + 'from' => $this->from, + 'to' => $message->getPhone(), + 'text' => $message->getSubject(), + 'api_key' => $this->apiKey, + 'api_secret' => $this->apiSecret, + ], + ]); + + try { + $result = $response->toArray(false); + } catch (TransportExceptionInterface $e) { + throw new TransportException('Could not reach the remote Vonage server.', $response, 0, $e); + } + + foreach ($result['messages'] as $msg) { + if ($msg['status'] ?? false) { + throw new TransportException('Unable to send the SMS: '.$msg['error-text'].sprintf(' (code %s).', $msg['status']), $response); + } + } + + $success = $response->toArray(false); + + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['messages'][0]['message-id']); + + return $sentMessage; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/VonageTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Vonage/VonageTransportFactory.php new file mode 100644 index 0000000000000..c0f23b2425481 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/VonageTransportFactory.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Vonage; + +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; +use Symfony\Component\Notifier\Transport\TransportInterface; + +/** + * @author Fabien Potencier + */ +final class VonageTransportFactory extends AbstractTransportFactory +{ + /** + * @return VonageTransport + */ + public function create(Dsn $dsn): TransportInterface + { + $scheme = $dsn->getScheme(); + + if ('vonage' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'vonage', $this->getSupportedSchemes()); + } + + $apiKey = $this->getUser($dsn); + $apiSecret = $this->getPassword($dsn); + $from = $dsn->getRequiredOption('from'); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new VonageTransport($apiKey, $apiSecret, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + } + + protected function getSupportedSchemes(): array + { + return ['vonage']; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/composer.json b/src/Symfony/Component/Notifier/Bridge/Vonage/composer.json new file mode 100644 index 0000000000000..c80b016feaaa5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/composer.json @@ -0,0 +1,30 @@ +{ + "name": "symfony/vonage-notifier", + "type": "symfony-notifier-bridge", + "description": "Symfony Vonage Notifier Bridge", + "keywords": ["sms", "vonage", "notifier"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/http-client": "^4.3|^5.0|^6.0", + "symfony/notifier": "^5.3|^6.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\Vonage\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/src/Symfony/Component/Notifier/Bridge/Vonage/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/Vonage/phpunit.xml.dist new file mode 100644 index 0000000000000..84bc254ccab03 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Vonage/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php index 0e7628f2f1552..ebe0cef610dfd 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -184,6 +184,10 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Twilio\TwilioTransportFactory::class, 'package' => 'symfony/twilio-notifier', ], + 'vonage' => [ + 'class' => Bridge\Vonage\VonageTransportFactory::class, + 'package' => 'symfony/vonage-notifier', + ], 'yunpian' => [ 'class' => Bridge\Yunpian\YunpianTransportFactory::class, 'package' => 'symfony/yunpian-notifier', diff --git a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php index 05ef2ed964171..1cd8d4033eb4d 100644 --- a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php +++ b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php @@ -53,6 +53,7 @@ use Symfony\Component\Notifier\Bridge\Telnyx\TelnyxTransportFactory; use Symfony\Component\Notifier\Bridge\TurboSms\TurboSmsTransportFactory; use Symfony\Component\Notifier\Bridge\Twilio\TwilioTransportFactory; +use Symfony\Component\Notifier\Bridge\Vonage\VonageTransportFactory; use Symfony\Component\Notifier\Bridge\Yunpian\YunpianTransportFactory; use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; @@ -107,6 +108,7 @@ public static function setUpBeforeClass(): void TelnyxTransportFactory::class => false, TurboSmsTransportFactory::class => false, TwilioTransportFactory::class => false, + VonageTransportFactory::class => false, YunpianTransportFactory::class => false, ZulipTransportFactory::class => false, ]); diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index a8ca4c91e6fa2..9944573630e68 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -45,6 +45,7 @@ use Symfony\Component\Notifier\Bridge\Telnyx\TelnyxTransportFactory; use Symfony\Component\Notifier\Bridge\TurboSms\TurboSmsTransportFactory; use Symfony\Component\Notifier\Bridge\Twilio\TwilioTransportFactory; +use Symfony\Component\Notifier\Bridge\Vonage\VonageTransportFactory; use Symfony\Component\Notifier\Bridge\Yunpian\YunpianTransportFactory; use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; @@ -100,6 +101,7 @@ class Transport TelnyxTransportFactory::class, TurboSmsTransportFactory::class, TwilioTransportFactory::class, + VonageTransportFactory::class, YunpianTransportFactory::class, ZulipTransportFactory::class, ]; diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index f31e57358503c..4d811a69c1ea1 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -307,10 +307,10 @@ public function start(callable $callback = null, array $env = []) $descriptors = $this->getDescriptors(); if ($this->env) { - $env += $this->env; + $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env; } - $env += $this->getDefaultEnv(); + $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->getDefaultEnv(), $env, 'strcasecmp') : $this->getDefaultEnv(); if (\is_array($commandline = $this->commandline)) { $commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline)); @@ -1649,8 +1649,8 @@ private function replacePlaceholders(string $commandline, array $env) private function getDefaultEnv(): array { $env = getenv(); - $env = array_intersect_key($env, $_SERVER) ?: $env; + $env = ('\\' === \DIRECTORY_SEPARATOR ? array_intersect_ukey($env, $_SERVER, 'strcasecmp') : array_intersect_key($env, $_SERVER)) ?: $env; - return $_ENV + $env; + return $_ENV + ('\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($env, $_ENV, 'strcasecmp') : $env); } } diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 411cb8159be71..4a20fe1219b0b 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1522,6 +1522,18 @@ public function testWaitStoppedDeadProcess() $this->assertFalse($process->isRunning()); } + public function testEnvCaseInsensitiveOnWindows() + { + $p = $this->getProcessForCode('print_r([$_SERVER[\'PATH\'] ?? 1, $_SERVER[\'Path\'] ?? 2]);', null, ['PATH' => 'bar/baz']); + $p->run(null, ['Path' => 'foo/bar']); + + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->assertSame('Array ( [0] => 1 [1] => foo/bar )', preg_replace('/\s++/', ' ', trim($p->getOutput()))); + } else { + $this->assertSame('Array ( [0] => bar/baz [1] => foo/bar )', preg_replace('/\s++/', ' ', trim($p->getOutput()))); + } + } + /** * @param string|array $commandline * @param mixed $input diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index ee38448b842d2..223a8e9c4bff8 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -470,7 +470,7 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid throw $e; } } elseif (PropertyReadInfo::TYPE_PROPERTY === $type) { - if (!method_exists($object, '__get') && !\array_key_exists($name, (array) $object) && (\PHP_VERSION_ID < 70400 || !(new \ReflectionProperty($class, $name))->hasType())) { + if (!method_exists($object, '__get') && !isset($object->$name) && !\array_key_exists($name, (array) $object) && (\PHP_VERSION_ID < 70400 || !(new \ReflectionProperty($class, $name))->hasType())) { throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not initialized.', $class, $name)); } diff --git a/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php index 8e0e32d99f778..e28d669530d71 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php @@ -80,6 +80,17 @@ public function supports(Request $request): ?bool return false; } + // do not overwrite already stored tokens from the same user (i.e. from the session) + $token = $this->tokenStorage->getToken(); + + if ($token instanceof PreAuthenticatedToken && $this->firewallName === $token->getFirewallName() && $token->getUserIdentifier() === $username) { + if (null !== $this->logger) { + $this->logger->debug('Skipping pre-authenticated authenticator as the user already has an existing session.', ['authenticator' => static::class]); + } + + return false; + } + $request->attributes->set('_pre_authenticated_username', $username); return true; diff --git a/src/Symfony/Component/Security/Http/Tests/Authenticator/RemoteUserAuthenticatorTest.php b/src/Symfony/Component/Security/Http/Tests/Authenticator/RemoteUserAuthenticatorTest.php index 46454e6aaf86a..89a5776decd29 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authenticator/RemoteUserAuthenticatorTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authenticator/RemoteUserAuthenticatorTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Core\User\InMemoryUserProvider; @@ -37,6 +38,17 @@ public function testSupportNoUser() $this->assertFalse($authenticator->supports($this->createRequest([]))); } + public function testSupportTokenStorageWithToken() + { + $tokenStorage = new TokenStorage(); + $tokenStorage->setToken(new PreAuthenticatedToken(new InMemoryUser('username', null), 'main')); + + $authenticator = new RemoteUserAuthenticator(new InMemoryUserProvider(), $tokenStorage, 'main'); + + $this->assertFalse($authenticator->supports($this->createRequest(['REMOTE_USER' => 'username']))); + $this->assertTrue($authenticator->supports($this->createRequest(['REMOTE_USER' => 'another_username']))); + } + /** * @dataProvider provideAuthenticators */ diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index b81862b570940..38d81d9c9615e 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -137,14 +137,14 @@ protected function getAttributeValue(object $object, string $attribute, string $ return $reflectionProperty->getValue($object); } - if (!method_exists($object, '__get')) { + if (!method_exists($object, '__get') && !isset($object->$attribute)) { $propertyValues = (array) $object; if (($reflectionProperty->isPublic() && !\array_key_exists($reflectionProperty->name, $propertyValues)) || ($reflectionProperty->isProtected() && !\array_key_exists("\0*\0{$reflectionProperty->name}", $propertyValues)) || ($reflectionProperty->isPrivate() && !\array_key_exists("\0{$reflectionProperty->class}\0{$reflectionProperty->name}", $propertyValues)) ) { - throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not initialized.', $reflectionProperty->class, $reflectionProperty->name)); + throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not initialized.', \get_class($object), $reflectionProperty->name)); } } diff --git a/src/Symfony/Component/String/composer.json b/src/Symfony/Component/String/composer.json index 6dc1c46fe31b5..2b88fd529e8b7 100644 --- a/src/Symfony/Component/String/composer.json +++ b/src/Symfony/Component/String/composer.json @@ -29,6 +29,9 @@ "symfony/translation-contracts": "^1.1|^2", "symfony/var-exporter": "^4.4|^5.0|^6.0" }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, "autoload": { "psr-4": { "Symfony\\Component\\String\\": "" }, "files": [ "Resources/functions.php" ], diff --git a/src/Symfony/Component/Templating/Storage/Storage.php b/src/Symfony/Component/Templating/Storage/Storage.php index 97844ab6cab7e..c5e0d474a6c3d 100644 --- a/src/Symfony/Component/Templating/Storage/Storage.php +++ b/src/Symfony/Component/Templating/Storage/Storage.php @@ -35,7 +35,7 @@ public function __construct(string $template) */ public function __toString() { - return (string) $this->template; + return $this->template; } /** diff --git a/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php b/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php index 160d7decb459f..f40e2119f644d 100644 --- a/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php +++ b/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php @@ -73,8 +73,15 @@ public function write(TranslatorBagInterface $translatorBag): void } foreach ($catalogue->all() as $domain => $messages) { - $ids = $this->getAssetsIds($domain); - $this->translateAssets(array_combine($ids, array_values($messages)), $locale); + $keysIdsMap = []; + + foreach ($this->getAssetsIds($domain) as $id) { + $keysIdsMap[$this->retrieveKeyFromId($id, $domain)] = $id; + } + + $ids = array_intersect_key($keysIdsMap, $messages); + + $this->translateAssets(array_combine(array_values($ids), array_values($messages)), $locale); } } } @@ -120,11 +127,7 @@ public function read(array $domains, array $locales): TranslatorBag $catalogue = new MessageCatalogue($locale); foreach ($locoCatalogue->all($domain) as $key => $message) { - if (str_starts_with($key, $domain.'__')) { - $key = substr($key, \strlen($domain) + 2); - } - - $catalogue->set($key, $message, $domain); + $catalogue->set($this->retrieveKeyFromId($key, $domain), $message, $domain); } $translatorBag->addCatalogue($catalogue); @@ -287,4 +290,13 @@ private function getLocales(): array return $carry; }, []); } + + private function retrieveKeyFromId(string $id, string $domain): string + { + if (str_starts_with($id, $domain.'__')) { + return substr($id, \strlen($domain) + 2); + } + + return $id; + } } diff --git a/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php b/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php index 09c779324310b..2a2183abf110f 100644 --- a/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php +++ b/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php @@ -148,7 +148,7 @@ public function testCompleteWriteProcess() $this->assertSame(['filter' => 'messages'], $options['query']); $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - return new MockResponse('[{"id":"messages__a"}]'); + return new MockResponse('[{"id":"messages__foo.existing_key"},{"id":"messages__a"}]'); }, 'translateAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { $this->assertSame('POST', $method); @@ -164,7 +164,7 @@ public function testCompleteWriteProcess() $this->assertSame(['filter' => 'validators'], $options['query']); $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - return new MockResponse('[{"id":"validators__post.num_comments"}]'); + return new MockResponse('[{"id":"validators__foo.existing_key"},{"id":"validators__post.num_comments"}]'); }, 'translateAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { $this->assertSame('POST', $method); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 4cc4367de898d..dc0626093f278 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -457,7 +457,7 @@ protected function computeFallbackLocales(string $locale) */ protected function assertValidLocale(string $locale) { - if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', (string) $locale)) { + if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) { throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale)); } } diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 82e07feb6b792..a72eac6aae2b2 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -25,7 +25,13 @@ class UrlValidator extends ConstraintValidator (%s):// # protocol (((?:[\_\.\pL\pN-]|%%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%%[0-9A-Fa-f]{2})+)@)? # basic auth ( - ([\pL\pN\pS\-\_]+\.)*(([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name + (?: + (?:xn--[a-z0-9-]++\.)*+xn--[a-z0-9-]++ # a domain name using punycode + | + (?:[\pL\pN\pS\pM\-\_]++\.)+[\pL\pN\pM]++ # a multi-level domain name + | + [a-z0-9\-\_]++ # a single-level domain name + )\.? | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or diff --git a/src/Symfony/Component/Validator/Mapping/Loader/AbstractLoader.php b/src/Symfony/Component/Validator/Mapping/Loader/AbstractLoader.php index 74f445085e47d..9f6667f836f9d 100644 --- a/src/Symfony/Component/Validator/Mapping/Loader/AbstractLoader.php +++ b/src/Symfony/Component/Validator/Mapping/Loader/AbstractLoader.php @@ -67,7 +67,7 @@ protected function addNamespaceAlias(string $alias, string $namespace) protected function newConstraint(string $name, $options = null) { if (str_contains($name, '\\') && class_exists($name)) { - $className = (string) $name; + $className = $name; } elseif (str_contains($name, ':')) { [$prefix, $className] = explode(':', $name, 2); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index d88fbff6cd899..8227cd73f1b21 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -123,6 +123,10 @@ public function getValidUrls() ['http://very.long.domain.name.com/'], ['http://localhost/'], ['http://myhost123/'], + ['http://internal-api'], + ['http://internal-api.'], + ['http://internal-api/'], + ['http://internal-api/path'], ['http://127.0.0.1/'], ['http://127.0.0.1:80/'], ['http://[::1]/'], @@ -169,6 +173,7 @@ public function getValidUrls() ['http://symfony.com/#fragment'], ['http://symfony.com/#one_more%20test'], ['http://example.com/exploit.html?hello[0]=test'], + ['http://বিডিআইএ.বাংলা'], ]; } @@ -254,7 +259,14 @@ public function getInvalidUrls() ['http://127.0.0.1:aa/'], ['ftp://[::1]/'], ['http://[::1'], + ['http://☎'], + ['http://☎.'], + ['http://☎/'], + ['http://☎/path'], + ['http://hello.☎'], + ['http://hello.☎.'], ['http://hello.☎/'], + ['http://hello.☎/path'], ['http://:password@symfony.com'], ['http://:password@@symfony.com'], ['http://username:passwordsymfony.com'], @@ -271,6 +283,9 @@ public function getInvalidUrls() ['http://.m.example.com'], ['http://wwww.example..com'], ['http://.www.example.com'], + ['http://example.co-'], + ['http://example.co-/path'], + ['http:///path'], ]; } diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 8d3c518964e46..ea8f0f33abbe1 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -209,7 +209,7 @@ public function __toString() public function withMaxDepth(int $maxDepth) { $data = clone $this; - $data->maxDepth = (int) $maxDepth; + $data->maxDepth = $maxDepth; return $data; } @@ -222,7 +222,7 @@ public function withMaxDepth(int $maxDepth) public function withMaxItemsPerDepth(int $maxItemsPerDepth) { $data = clone $this; - $data->maxItemsPerDepth = (int) $maxItemsPerDepth; + $data->maxItemsPerDepth = $maxItemsPerDepth; return $data; } diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 097b1a332051b..1e76c4fa1a634 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -669,7 +669,7 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer // no break case \in_array($scalar[0], ['+', '-', '.'], true) || is_numeric($scalar[0]): if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) { - $scalar = str_replace('_', '', (string) $scalar); + $scalar = str_replace('_', '', $scalar); } switch (true) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy