diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d4182db630352..84dd98f43ad2b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 5.x for features / 4.4 or 5.2 for bug fixes +| Branch? | 5.4 for features / 4.4, 5.2 or 5.3 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no diff --git a/.travis.yml b/.travis.yml index 22c07536a060f..9a7239b3f5d69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ addons: env: global: - - SYMFONY_VERSION=5.x + - SYMFONY_VERSION=5.3 - MIN_PHP=7.2.5 - SYMFONY_PROCESS_PHP_TEST_BINARY=~/.phpenv/shims/php - SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 @@ -50,12 +50,14 @@ before_install: set -e stty cols 120 cp .github/composer-config.json "$(composer config home)/config.json" + git config --global user.email "" + git config --global user.name "Symfony" export PHPUNIT=$(readlink -f ./phpunit) export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data" export COMPOSER_UP='composer update --no-progress --ansi' export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) - export SYMFONY_DEPRECATIONS_HELPER=max[indirect]=170 export SYMFONY_FEATURE_BRANCH=$(curl -s https://flex.symfony.com/versions.json | jq -r '."dev-name"') + export SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) nanoseconds () { local cmd="date" @@ -180,11 +182,6 @@ install: - | # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - git config --global user.email "" - git config --global user.name "Symfony" - - SYMFONY_VERSIONS=$(git ls-remote -q --heads); - if [[ ! $deps ]]; then php .github/build-packages.php HEAD^ $SYMFONY_VERSION src/Symfony/Bridge/PhpUnit else @@ -201,10 +198,10 @@ install: fi - | - # For the feature-branch, when deps=high, the version before it is checked out and tested with the locally patched components - if [[ $deps = high && $TRAVIS_BRANCH = $SYMFONY_FEATURE_BRANCH ]]; then + # For the highest branch, when deps=high, the version before it is checked out and tested with the locally patched components + if [[ $deps = high && $SYMFONY_VERSION = $(echo "$SYMFONY_VERSIONS" | tail -n 1 | sed s/.//) ]]; then export FLIP='^' - export SYMFONY_VERSION=$(echo "$SYMFONY_VERSIONS" | grep -o '/[1-9]\.[0-9].*' | tail -n 1 | sed s/.//) && + export SYMFONY_VERSION=$(echo "$SYMFONY_VERSIONS" | grep -FB1 /$SYMFONY_VERSION | head -n 1 | sed s/.//) && git fetch --depth=2 origin $SYMFONY_VERSION && git checkout -m FETCH_HEAD && export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) @@ -212,7 +209,7 @@ install: - | # Skip the phpunit-bridge on bugfix-branches when $deps is empty - if [[ ! $deps && ! $TRAVIS_BRANCH = $SYMFONY_FEATURE_BRANCH ]]; then + if [[ ! $deps && $SYMFONY_VERSION != $SYMFONY_FEATURE_BRANCH ]]; then export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort) fi @@ -227,7 +224,7 @@ install: - | # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one - [[ $deps = high && ${SYMFONY_VERSION%.*} != $(echo "$SYMFONY_VERSIONS" | cut -f2 | grep -FA1 /$SYMFONY_VERSION | tail -n 1 | grep -o '[0-9]*' | head -n 1) ]] && export LEGACY=,legacy + [[ $deps = high && $SYMFONY_VERSION = *.4 ]] && export LEGACY=,legacy export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev if [[ $deps ]]; then mv composer.json.phpunit composer.json; fi @@ -264,7 +261,7 @@ install: (cd src/Symfony/Component/HttpFoundation; mv composer.bak composer.json) COMPONENTS=$(git diff --name-only src/ | grep composer.json || true) - if [[ $COMPONENTS && $LEGACY && ! $TRAVIS_BRANCH = $SYMFONY_FEATURE_BRANCH && $TRAVIS_PULL_REQUEST != false && $(echo "$SYMFONY_VERSIONS" | cut -f2 | grep -FA1 /$SYMFONY_VERSION | tail -n 1) = $SYMFONY_FEATURE_BRANCH ]]; then + if [[ $COMPONENTS && $SYMFONY_VERSION = *.4 && $TRAVIS_PULL_REQUEST != false ]]; then export FLIP='^' SYMFONY_VERSION=$(echo $SYMFONY_VERSION | awk '{print $1 - 1}') echo -e "\\n\\e[33;1mChecking out Symfony $SYMFONY_VERSION and running tests with patched components as deps\\e[0m" diff --git a/CHANGELOG-5.2.md b/CHANGELOG-5.2.md index c5dfdaa58eb1b..8af2ebff38ba2 100644 --- a/CHANGELOG-5.2.md +++ b/CHANGELOG-5.2.md @@ -7,6 +7,21 @@ in 5.2 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.2.0...v5.2.1 +* 5.2.9 (2021-05-19) + + * security #cve-2021-21424 [Security\Core] Fix user enumeration via response body on invalid credentials (chalasr) + * bug #41275 Fixes Undefined method call (faizanakram99) + * bug #41269 [SecurityBundle] Remove invalid unused service (chalasr) + * bug #41139 [Security] [DataCollector] Remove allows anonymous information in datacollector (ismail1432) + * bug #41230 [FrameworkBundle][Validator] Fix deprecations from Doctrine Annotations+Cache (derrabus) + * bug #41206 [Mailer] Fix SES API call with UTF-8 Addresses (jderusse) + * bug #41240 Fixed deprecation warnings about passing null as parameter (derrabus) + * bug #41241 [Finder] Fix gitignore regex build with "**" (mvorisek) + * bug #41224 [HttpClient] fix adding query string to relative URLs with scoped clients (nicolas-grekas) + * bug #41233 [DependencyInjection][ProxyManagerBridge] Don't call class_exists() on null (derrabus) + * bug #41211 [Notifier] Add missing charset to content-type for Slack notifier (norkunas) + * bug #41210 [Console] Fix Windows code page support (orkan) + * 5.2.8 (2021-05-12) * security #cve-2021-21424 [Security][Guard] Prevent user enumeration (chalasr) diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md index 3b528e0163299..d15bc4b4b1ab6 100644 --- a/CHANGELOG-5.3.md +++ b/CHANGELOG-5.3.md @@ -7,6 +7,24 @@ 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.0 (2021-05-31) + + * bug #41458 [FrameworkBundle] fix ConfigBuilderCacheWarmer (nicolas-grekas) + * bug #41456 [FrameworkBundle] fix creating ContainerBuilder at warmup/CLI time (nicolas-grekas) + * bug #41452 [FrameworkBundle] Remove redundant cache service (derrabus) + * bug #41451 [Translation] Remove PoEditor Provider (welcoMattic) + * bug #41000 [Form] Use !isset for checks cause this doesn't falsely include 0 (Kai Dederichs) + * bug #41407 [DependencyInjection] keep container.service_subscriber tag on the decorated definition (xabbuh) + * bug #40866 [Filesystem] fix readlink() for Windows (a1812) + * bug #41402 [HttpKernel] Throw when HttpKernel is created and the env is empty (nicolas-grekas) + * bug #41376 [SecurityBundle] Don't register deprecated listeners with authenticator manager enabled (chalasr) + * bug #41394 [Form] fix support for years outside of the 32b range on x86 arch (nicolas-grekas) + * bug #41380 Make Mailgun Header compatible with other Bridges (jderusse) + * bug #39847 [Messenger] Fix merging PrototypedArrayNode associative values (svityashchuk) + * bug #41367 [Ldap] Avoid calling the deprecated getUsername() (derrabus) + * bug #41346 [WebProfilerBundle] Wrapping exception js in Sfjs check and also loading base_js Sfjs if needed (weaverryan) + * bug #41344 [VarDumper] Don't pass null to parse_url() (derrabus) + * 5.3.0-RC1 (2021-05-19) * security #cve-2021-21424 [Security\Core] Fix user enumeration via response body on invalid credentials (chalasr) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c5ad1a9f263c8..082da17e5c9f3 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -146,12 +146,12 @@ The Symfony Connect username in parenthesis allows to get more information - Colin Frei - Javier Spagnoletti (phansys) - Joshua Thijssen + - Tomas Norkūnas (norkunas) - Yanick Witschi (toflar) - Daniel Wehner (dawehner) - Tugdual Saunier (tucksaun) - excelwebzone - Gordon Franke (gimler) - - Tomas Norkūnas (norkunas) - Jesse Rushlow (geeshoe) - Fabien Pennequin (fabienpennequin) - Théo FIDRY (theofidry) @@ -280,6 +280,7 @@ The Symfony Connect username in parenthesis allows to get more information - Stadly - Stepan Anchugov (kix) - François Pluchino (francoispluchino) + - Rokas Mikalkėnas (rokasm) - bronze1man - Jeroen Noten (jeroennoten) - sun (sun) @@ -318,7 +319,6 @@ The Symfony Connect username in parenthesis allows to get more information - Clara van Miert - Bastien Jaillot (bastnic) - Rui Marinho (ruimarinho) - - Rokas Mikalkėnas (rokasm) - Alexandre Daubois (alexandre-daubois) - Eugene Wissner - Bohan Yang (brentybh) @@ -387,6 +387,7 @@ The Symfony Connect username in parenthesis allows to get more information - Nguyen Xuan Quynh (xuanquynh) - Jan Sorgalla (jsor) - Ray + - Bozhidar Hristov (warxcell) - Chekote - Thomas Adam - Jhonny Lidfors (jhonne) @@ -403,6 +404,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mohammad Emran Hasan (phpfour) - Dmitriy Mamontov (mamontovdmitriy) - Ben Ramsey (ramsey) + - Michael Voříšek - Laurent Masforné (heisenberg) - Giorgio Premi - Guillaume (guill) @@ -453,7 +455,6 @@ The Symfony Connect username in parenthesis allows to get more information - realmfoo - Thomas Tourlourat (armetiz) - Andrey Esaulov (andremaha) - - Bozhidar Hristov (warxcell) - Grégoire Passault (gregwar) - Jerzy Zawadzki (jzawadzki) - Ismael Ambrosi (iambrosi) @@ -492,7 +493,6 @@ The Symfony Connect username in parenthesis allows to get more information - Gennady Telegin (gtelegin) - Krystian Marcisz (simivar) - Toni Rudolf (toooni) - - Michael Voříšek - Erin Millard - Artur Melo (restless) - Matthew Lewinski (lewinski) @@ -610,6 +610,7 @@ The Symfony Connect username in parenthesis allows to get more information - Steffen Roßkamp - Alexandru Furculita (afurculita) - Valentin Jonovs (valentins-jonovs) + - Andrii Bodnar - Bastien DURAND (deamon) - Jeanmonod David (jeanmonod) - Christopher Davis (chrisguitarguy) @@ -693,6 +694,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andreas Leathley (iquito) - Soufian EZ-ZANTAR (soezz) - Zander Baldwin + - Marek Zajac - Adam Harvey - Anton Bakai - Rhodri Pugh (rodnaph) @@ -1394,7 +1396,6 @@ The Symfony Connect username in parenthesis allows to get more information - Gary Houbre (thegarious) - Romain Monteil (ker0x) - sensio - - Andrii Bodnar - Thomas Jarrand - Antoine Bluchet (soyuka) - Patrick Kaufmann @@ -1713,7 +1714,6 @@ The Symfony Connect username in parenthesis allows to get more information - David Legatt (dlegatt) - Alain Flaus (halundra) - tsufeki - - Marek Zajac - Philipp Strube - Clement Herreman (clemherreman) - Dan Ionut Dumitriu (danionut90) @@ -1910,6 +1910,7 @@ The Symfony Connect username in parenthesis allows to get more information - Nicolas Eeckeloo (neeckeloo) - Andriy Prokopenko (sleepyboy) - Mathieu Morlon + - Ivo Valchev - Daniel Tschinder - Arnaud CHASSEUX - Wojciech Gorczyca @@ -2216,6 +2217,7 @@ The Symfony Connect username in parenthesis allows to get more information - Oliver Klee - Simon Sargeant - efeen + - Mikko Ala-Fossi - Jan Christoph Beyer - Nicolas Pion - Muhammed Akbulut diff --git a/README.md b/README.md index d3f5b5588d75a..52860457b2336 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@

-[Symfony][1] is a **PHP framework** for web and console applications and a set of reusable -**PHP components**. Symfony is used by thousands of web applications (including -BlaBlaCar.com and Spotify.com) and most of the [popular PHP projects][2] (including -Drupal and Magento). +[Symfony][1] is a **PHP framework** for web and console applications and a set +of reusable **PHP components**. Symfony is used by thousands of web +applications and most of the [popular PHP projects][2]. Installation ------------ @@ -15,6 +14,17 @@ Installation Support" (LTS) versions and has a [release process][6] that is predictable and business-friendly. +Sponsor +------- + +Symfony 5.3 is [backed][27] by [JoliCode][28]. + +JoliCode is a team of passionate developers and open-source lovers, with a +strong expertise in PHP & Symfony technologies. They can help you build your +projects using state-of-the-art practices. + +Help Symfony by [sponsoring][29] its development! + Documentation ------------- @@ -76,3 +86,6 @@ Symfony development is sponsored by [SensioLabs][21], led by the [24]: https://symfony.com/coc [25]: https://symfony.com/doc/current/contributing/code_of_conduct/care_team.html [26]: https://symfony.com/book +[27]: https://symfony.com/backers +[28]: https://jolicode.com/ +[29]: https://symfony.com/sponsor diff --git a/UPGRADE-5.1.md b/UPGRADE-5.1.md index 3143e173bd05e..a08df30d55591 100644 --- a/UPGRADE-5.1.md +++ b/UPGRADE-5.1.md @@ -80,7 +80,6 @@ Inflector Mailer ------ - * Deprecated passing Mailgun headers without their "h:" prefix. * Deprecated the `SesApiTransport` class. It has been replaced by SesApiAsyncAwsTransport Run `composer require async-aws/ses` to use the new classes. * Deprecated the `SesHttpTransport` class. It has been replaced by SesHttpAsyncAwsTransport Run `composer require async-aws/ses` to use the new classes. @@ -101,6 +100,7 @@ Notifier arguments were removed. * [BC BREAK] The `EmailMessage::fromNotification()` and `SmsMessage::fromNotification()` methods' `$transport` argument was removed. + * Deprecate `SlackOptions::channel()`, use `SlackOptions::recipient()` instead. OptionsResolver --------------- diff --git a/UPGRADE-5.2.md b/UPGRADE-5.2.md index c49e55445e34d..3334ed6665f2c 100644 --- a/UPGRADE-5.2.md +++ b/UPGRADE-5.2.md @@ -173,4 +173,3 @@ Security * Deprecated the `AbstractRememberMeServices::$providerKey` property in favor of `AbstractRememberMeServices::$firewallName`, the old property will be removed in 6.0. - diff --git a/UPGRADE-5.3.md b/UPGRADE-5.3.md index b9181da64272d..6a1552e3a8700 100644 --- a/UPGRADE-5.3.md +++ b/UPGRADE-5.3.md @@ -10,6 +10,7 @@ Console ------- * Deprecate `Helper::strlen()`, use `Helper::width()` instead. + * Deprecate `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead. DoctrineBridge -------------- diff --git a/UPGRADE-6.0.md b/UPGRADE-6.0.md index a37acd80e885f..9ec7d84f308d0 100644 --- a/UPGRADE-6.0.md +++ b/UPGRADE-6.0.md @@ -24,6 +24,7 @@ Console * `Command::setHidden()` has a default value (`true`) for `$hidden` parameter * Remove `Helper::strlen()`, use `Helper::width()` instead. + * Remove `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead. DependencyInjection ------------------- @@ -151,6 +152,11 @@ Monolog * The `$actionLevel` constructor argument of `Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy` has been replaced by the `$inner` one which expects an ActivationStrategyInterface to decorate instead. `Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy` is now final. * The `$actionLevel` constructor argument of `Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy` has been replaced by the `$inner` one which expects an ActivationStrategyInterface to decorate instead. `Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy` is now final. +Notifier +-------- + + * Remove `SlackOptions::channel()`, use `SlackOptions::recipient()` instead. + OptionsResolver --------------- diff --git a/composer.json b/composer.json index 77b8c2b3795bb..f244517786900 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "psr/simple-cache-implementation": "1.0", "symfony/cache-implementation": "1.0|2.0", "symfony/event-dispatcher-implementation": "2.0", - "symfony/http-client-implementation": "2.2", + "symfony/http-client-implementation": "2.4", "symfony/service-implementation": "1.0|2.0", "symfony/translation-implementation": "2.3" }, @@ -52,6 +52,7 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.11", "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php81": "^1.22", "symfony/polyfill-uuid": "^1.15", "symfony/runtime": "self.version" }, @@ -130,7 +131,6 @@ "doctrine/data-fixtures": "^1.1", "doctrine/dbal": "^2.10|^3.0", "doctrine/orm": "^2.7.3", - "doctrine/doctrine-bundle": "^2.0", "guzzlehttp/promises": "^1.4", "masterminds/html5": "^2.6", "monolog/monolog": "^1.25.1|^2", diff --git a/phpunit b/phpunit index 6ce03fd8eb783..7ca6ceeccbee8 100755 --- a/phpunit +++ b/phpunit @@ -1,14 +1,18 @@ #!/usr/bin/env php getMethod('evaluate')->hasReturnType()) { +} elseif (\PHP_VERSION_ID < 70100 || !$r->getMethod('evaluate')->hasReturnType()) { trait ConstraintTrait { use Legacy\ConstraintTraitForV8; diff --git a/src/Symfony/Bridge/PhpUnit/README.md b/src/Symfony/Bridge/PhpUnit/README.md index 89707340a8f80..b7c041a8ee5a7 100644 --- a/src/Symfony/Bridge/PhpUnit/README.md +++ b/src/Symfony/Bridge/PhpUnit/README.md @@ -7,8 +7,8 @@ especially user deprecation notices management. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/phpunit_bridge.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/phpunit_bridge.html) + * [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/Bridge/ProxyManager/README.md b/src/Symfony/Bridge/ProxyManager/README.md index 8297ce1ed914b..ff6c6b2f76505 100644 --- a/src/Symfony/Bridge/ProxyManager/README.md +++ b/src/Symfony/Bridge/ProxyManager/README.md @@ -7,9 +7,9 @@ Symfony components. 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) + * [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) [1]: https://github.com/FriendsOfPHP/proxy-manager-lts diff --git a/src/Symfony/Bridge/Twig/README.md b/src/Symfony/Bridge/Twig/README.md index 8077918405ab9..533d573dbcabe 100644 --- a/src/Symfony/Bridge/Twig/README.md +++ b/src/Symfony/Bridge/Twig/README.md @@ -7,7 +7,7 @@ various Symfony components. 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) + * [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/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php index 387e32edbaec7..ed20bbcb648d7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php @@ -12,10 +12,10 @@ namespace Symfony\Bundle\FrameworkBundle\CacheWarmer; use Psr\Log\LoggerInterface; -use Symfony\Bundle\FrameworkBundle\Command\BuildDebugContainerTrait; use Symfony\Component\Config\Builder\ConfigBuilderGenerator; use Symfony\Component\Config\Builder\ConfigBuilderGeneratorInterface; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; @@ -28,8 +28,6 @@ */ class ConfigBuilderCacheWarmer implements CacheWarmerInterface { - use BuildDebugContainerTrait; - private $kernel; private $logger; @@ -73,7 +71,7 @@ private function dumpExtension(ExtensionInterface $extension, ConfigBuilderGener if ($extension instanceof ConfigurationInterface) { $configuration = $extension; } elseif ($extension instanceof ConfigurationExtensionInterface) { - $configuration = $extension->getConfiguration([], $this->getContainerBuilder($this->kernel)); + $configuration = $extension->getConfiguration([], new ContainerBuilder($this->kernel->getContainer()->getParameterBag())); } if (!$configuration) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php index 7f2e0c871b02e..440c4762a95e9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php @@ -40,7 +40,11 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde } if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) { - $buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel)); + $buildContainer = \Closure::bind(function () { + $this->initializeBundles(); + + return $this->buildContainer(); + }, $kernel, \get_class($kernel)); $container = $buildContainer(); $container->getCompilerPassConfig()->setRemovingPasses([]); $container->getCompilerPassConfig()->setAfterRemovingPasses([]); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3c5a9759334c9..645d45a38b4d7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -172,7 +172,6 @@ use Symfony\Component\Translation\Bridge\Crowdin\CrowdinProviderFactory; use Symfony\Component\Translation\Bridge\Loco\LocoProviderFactory; use Symfony\Component\Translation\Bridge\Lokalise\LokaliseProviderFactory; -use Symfony\Component\Translation\Bridge\PoEditor\PoEditorProviderFactory; use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand; use Symfony\Component\Translation\PseudoLocalizationTranslator; use Symfony\Component\Translation\Translator; @@ -1016,31 +1015,33 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co ->replaceArgument(0, $config['default_uri']); } - if (\PHP_VERSION_ID >= 80000 || $this->annotationsConfigEnabled) { - $container->register('routing.loader.annotation', AnnotatedRouteControllerLoader::class) - ->setPublic(false) - ->addTag('routing.loader', ['priority' => -10]) - ->setArguments([ - new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE), - '%kernel.environment%', - ]); + if (\PHP_VERSION_ID < 80000 && !$this->annotationsConfigEnabled) { + return; + } - $container->register('routing.loader.annotation.directory', AnnotationDirectoryLoader::class) - ->setPublic(false) - ->addTag('routing.loader', ['priority' => -10]) - ->setArguments([ - new Reference('file_locator'), - new Reference('routing.loader.annotation'), - ]); + $container->register('routing.loader.annotation', AnnotatedRouteControllerLoader::class) + ->setPublic(false) + ->addTag('routing.loader', ['priority' => -10]) + ->setArguments([ + new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE), + '%kernel.environment%', + ]); - $container->register('routing.loader.annotation.file', AnnotationFileLoader::class) - ->setPublic(false) - ->addTag('routing.loader', ['priority' => -10]) - ->setArguments([ - new Reference('file_locator'), - new Reference('routing.loader.annotation'), - ]); - } + $container->register('routing.loader.annotation.directory', AnnotationDirectoryLoader::class) + ->setPublic(false) + ->addTag('routing.loader', ['priority' => -10]) + ->setArguments([ + new Reference('file_locator'), + new Reference('routing.loader.annotation'), + ]); + + $container->register('routing.loader.annotation.file', AnnotationFileLoader::class) + ->setPublic(false) + ->addTag('routing.loader', ['priority' => -10]) + ->setArguments([ + new Reference('file_locator'), + new Reference('routing.loader.annotation'), + ]); } private function registerSessionConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader) @@ -1343,15 +1344,12 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder CrowdinProviderFactory::class => 'translation.provider_factory.crowdin', LocoProviderFactory::class => 'translation.provider_factory.loco', LokaliseProviderFactory::class => 'translation.provider_factory.lokalise', - PoEditorProviderFactory::class => 'translation.provider_factory.poeditor', ]; $parentPackages = ['symfony/framework-bundle', 'symfony/translation', 'symfony/http-client']; foreach ($classToServices as $class => $service) { - switch ($package = substr($service, \strlen('translation.provider_factory.'))) { - case 'poeditor': $package = 'po-editor'; break; - } + $package = substr($service, \strlen('translation.provider_factory.')); if (!$container->hasDefinition('http_client') || !ContainerBuilder::willBeAvailable(sprintf('symfony/%s-translation-provider', $package), $class, $parentPackages)) { $container->removeDefinition($service); @@ -1553,7 +1551,7 @@ private function registerAnnotationsConfiguration(array $config, ContainerBuilde $container->setDefinition('annotations.cached_reader', $container->getDefinition('annotations.psr_cached_reader')); if ('php_array' === $config['cache']) { - $cacheService = 'annotations.psr_cache'; + $cacheService = 'annotations.cache_adapter'; // Enable warmer only if PHP array is used for cache $definition = $container->findDefinition('annotations.cache_warmer'); diff --git a/src/Symfony/Bundle/FrameworkBundle/README.md b/src/Symfony/Bundle/FrameworkBundle/README.md index 59e1b44643c88..76c7700fa03af 100644 --- a/src/Symfony/Bundle/FrameworkBundle/README.md +++ b/src/Symfony/Bundle/FrameworkBundle/README.md @@ -7,7 +7,7 @@ Symfony full-stack framework. 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) + * [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/Bundle/FrameworkBundle/Resources/config/annotations.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php index cec9f9499f6b2..e202c13f8ab03 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php @@ -68,10 +68,11 @@ param('kernel.cache_dir').'/annotations.php', service('cache.annotations'), ]) + ->tag('container.hot_path') ->set('annotations.cache', DoctrineProvider::class) ->args([ - service('annotations.cache_adapter') + service('annotations.cache_adapter'), ]) ->tag('container.hot_path') @@ -86,13 +87,6 @@ inline_service(ArrayAdapter::class), abstract_arg('Debug-Flag'), ]) - ->set('annotations.psr_cache', PhpArrayAdapter::class) - ->factory([PhpArrayAdapter::class, 'create']) - ->args([ - param('kernel.cache_dir').'/annotations.php', - service('cache.annotations'), - ]) - ->tag('container.hot_path') ; } }; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation_providers.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation_providers.php index 45f8e6363af9f..cd140f077c172 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation_providers.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation_providers.php @@ -14,7 +14,6 @@ use Symfony\Component\Translation\Bridge\Crowdin\CrowdinProviderFactory; use Symfony\Component\Translation\Bridge\Loco\LocoProviderFactory; use Symfony\Component\Translation\Bridge\Lokalise\LokaliseProviderFactory; -use Symfony\Component\Translation\Bridge\PoEditor\PoEditorProviderFactory; use Symfony\Component\Translation\Provider\NullProviderFactory; use Symfony\Component\Translation\Provider\TranslationProviderCollection; use Symfony\Component\Translation\Provider\TranslationProviderCollectionFactory; @@ -63,14 +62,5 @@ service('translation.loader.xliff'), ]) ->tag('translation.provider_factory') - - ->set('translation.provider_factory.poeditor', PoEditorProviderFactory::class) - ->args([ - service('http_client'), - service('logger'), - param('kernel.default_locale'), - service('translation.loader.xliff'), - ]) - ->tag('translation.provider_factory') ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/README.md b/src/Symfony/Bundle/SecurityBundle/README.md index 01f967c8d9e32..63b502f87ba5c 100644 --- a/src/Symfony/Bundle/SecurityBundle/README.md +++ b/src/Symfony/Bundle/SecurityBundle/README.md @@ -7,7 +7,7 @@ Symfony full-stack framework. 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) + * [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/Bundle/SecurityBundle/Resources/config/security_legacy.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_legacy.php index 1c3ee242cc0a7..ec829ea1cbf85 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_legacy.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_legacy.php @@ -13,6 +13,16 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager; +use Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider; +use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; +use Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider; +use Symfony\Component\Security\Core\Authentication\Provider\PreAuthenticatedAuthenticationProvider; +use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener; +use Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener; +use Symfony\Component\Security\Http\Firewall\RemoteUserAuthenticationListener; +use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener; +use Symfony\Component\Security\Http\Firewall\UsernamePasswordJsonAuthenticationListener; +use Symfony\Component\Security\Http\Firewall\X509AuthenticationListener; return static function (ContainerConfigurator $container) { $container->services() @@ -24,6 +34,117 @@ param('security.authentication.manager.erase_credentials'), ]) ->call('setEventDispatcher', [service('event_dispatcher')]) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') ->alias(AuthenticationManagerInterface::class, 'security.authentication.manager') + ->deprecate('symfony/security-bundle', '5.3', 'The "%alias_id%" alias is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.listener.anonymous', AnonymousAuthenticationListener::class) + ->args([ + service('security.untracked_token_storage'), + abstract_arg('Key'), + service('logger')->nullOnInvalid(), + service('security.authentication.manager'), + ]) + ->tag('monolog.logger', ['channel' => 'security']) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.provider.anonymous', AnonymousAuthenticationProvider::class) + ->args([abstract_arg('Key')]) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.listener.form', UsernamePasswordFormAuthenticationListener::class) + ->parent('security.authentication.listener.abstract') + ->abstract() + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.listener.x509', X509AuthenticationListener::class) + ->abstract() + ->args([ + service('security.token_storage'), + service('security.authentication.manager'), + abstract_arg('Provider-shared Key'), + abstract_arg('x509 user'), + abstract_arg('x509 credentials'), + service('logger')->nullOnInvalid(), + service('event_dispatcher')->nullOnInvalid(), + ]) + ->tag('monolog.logger', ['channel' => 'security']) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.listener.json', UsernamePasswordJsonAuthenticationListener::class) + ->abstract() + ->args([ + service('security.token_storage'), + service('security.authentication.manager'), + service('security.http_utils'), + abstract_arg('Provider-shared Key'), + abstract_arg('Failure handler'), + abstract_arg('Success Handler'), + [], // Options + service('logger')->nullOnInvalid(), + service('event_dispatcher')->nullOnInvalid(), + service('property_accessor')->nullOnInvalid(), + ]) + ->call('setTranslator', [service('translator')->ignoreOnInvalid()]) + ->tag('monolog.logger', ['channel' => 'security']) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.listener.remote_user', RemoteUserAuthenticationListener::class) + ->abstract() + ->args([ + service('security.token_storage'), + service('security.authentication.manager'), + abstract_arg('Provider-shared Key'), + abstract_arg('REMOTE_USER server env var'), + service('logger')->nullOnInvalid(), + service('event_dispatcher')->nullOnInvalid(), + ]) + ->tag('monolog.logger', ['channel' => 'security']) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.listener.basic', BasicAuthenticationListener::class) + ->abstract() + ->args([ + service('security.token_storage'), + service('security.authentication.manager'), + abstract_arg('Provider-shared Key'), + abstract_arg('Entry Point'), + service('logger')->nullOnInvalid(), + ]) + ->tag('monolog.logger', ['channel' => 'security']) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.provider.dao', DaoAuthenticationProvider::class) + ->abstract() + ->args([ + abstract_arg('User Provider'), + abstract_arg('User Checker'), + abstract_arg('Provider-shared Key'), + service('security.password_hasher_factory'), + param('security.authentication.hide_user_not_found'), + ]) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.provider.ldap_bind', LdapBindAuthenticationProvider::class) + ->abstract() + ->args([ + abstract_arg('User Provider'), + abstract_arg('UserChecker'), + abstract_arg('Provider-shared Key'), + abstract_arg('LDAP'), + abstract_arg('Base DN'), + param('security.authentication.hide_user_not_found'), + abstract_arg('search dn'), + abstract_arg('search password'), + ]) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') + + ->set('security.authentication.provider.pre_authenticated', PreAuthenticatedAuthenticationProvider::class) + ->abstract() + ->args([ + abstract_arg('User Provider'), + abstract_arg('UserChecker'), + ]) + ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php index 95398eae1911d..163e6a63ca041 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php @@ -11,10 +11,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider; -use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; -use Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider; -use Symfony\Component\Security\Core\Authentication\Provider\PreAuthenticatedAuthenticationProvider; use Symfony\Component\Security\Http\AccessMap; use Symfony\Component\Security\Http\Authentication\CustomAuthenticationFailureHandler; use Symfony\Component\Security\Http\Authentication\CustomAuthenticationSuccessHandler; @@ -27,33 +23,14 @@ use Symfony\Component\Security\Http\EventListener\DefaultLogoutListener; use Symfony\Component\Security\Http\EventListener\SessionLogoutListener; use Symfony\Component\Security\Http\Firewall\AccessListener; -use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener; -use Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener; use Symfony\Component\Security\Http\Firewall\ChannelListener; use Symfony\Component\Security\Http\Firewall\ContextListener; use Symfony\Component\Security\Http\Firewall\ExceptionListener; use Symfony\Component\Security\Http\Firewall\LogoutListener; -use Symfony\Component\Security\Http\Firewall\RemoteUserAuthenticationListener; use Symfony\Component\Security\Http\Firewall\SwitchUserListener; -use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener; -use Symfony\Component\Security\Http\Firewall\UsernamePasswordJsonAuthenticationListener; -use Symfony\Component\Security\Http\Firewall\X509AuthenticationListener; return static function (ContainerConfigurator $container) { $container->services() - ->set('security.authentication.listener.anonymous', AnonymousAuthenticationListener::class) - ->args([ - service('security.untracked_token_storage'), - abstract_arg('Key'), - service('logger')->nullOnInvalid(), - service('security.authentication.manager'), - ]) - ->tag('monolog.logger', ['channel' => 'security']) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.provider.anonymous', AnonymousAuthenticationProvider::class) - ->args([abstract_arg('Key')]) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') ->set('security.authentication.retry_entry_point', RetryAuthenticationEntryPoint::class) ->args([ @@ -160,101 +137,6 @@ ]) ->tag('monolog.logger', ['channel' => 'security']) - ->set('security.authentication.listener.form', UsernamePasswordFormAuthenticationListener::class) - ->parent('security.authentication.listener.abstract') - ->abstract() - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.listener.x509', X509AuthenticationListener::class) - ->abstract() - ->args([ - service('security.token_storage'), - service('security.authentication.manager'), - abstract_arg('Provider-shared Key'), - abstract_arg('x509 user'), - abstract_arg('x509 credentials'), - service('logger')->nullOnInvalid(), - service('event_dispatcher')->nullOnInvalid(), - ]) - ->tag('monolog.logger', ['channel' => 'security']) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.listener.json', UsernamePasswordJsonAuthenticationListener::class) - ->abstract() - ->args([ - service('security.token_storage'), - service('security.authentication.manager'), - service('security.http_utils'), - abstract_arg('Provider-shared Key'), - abstract_arg('Failure handler'), - abstract_arg('Success Handler'), - [], // Options - service('logger')->nullOnInvalid(), - service('event_dispatcher')->nullOnInvalid(), - service('property_accessor')->nullOnInvalid(), - ]) - ->call('setTranslator', [service('translator')->ignoreOnInvalid()]) - ->tag('monolog.logger', ['channel' => 'security']) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.listener.remote_user', RemoteUserAuthenticationListener::class) - ->abstract() - ->args([ - service('security.token_storage'), - service('security.authentication.manager'), - abstract_arg('Provider-shared Key'), - abstract_arg('REMOTE_USER server env var'), - service('logger')->nullOnInvalid(), - service('event_dispatcher')->nullOnInvalid(), - ]) - ->tag('monolog.logger', ['channel' => 'security']) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.listener.basic', BasicAuthenticationListener::class) - ->abstract() - ->args([ - service('security.token_storage'), - service('security.authentication.manager'), - abstract_arg('Provider-shared Key'), - abstract_arg('Entry Point'), - service('logger')->nullOnInvalid(), - ]) - ->tag('monolog.logger', ['channel' => 'security']) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.provider.dao', DaoAuthenticationProvider::class) - ->abstract() - ->args([ - abstract_arg('User Provider'), - abstract_arg('User Checker'), - abstract_arg('Provider-shared Key'), - service('security.password_hasher_factory'), - param('security.authentication.hide_user_not_found'), - ]) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.provider.ldap_bind', LdapBindAuthenticationProvider::class) - ->abstract() - ->args([ - abstract_arg('User Provider'), - abstract_arg('UserChecker'), - abstract_arg('Provider-shared Key'), - abstract_arg('LDAP'), - abstract_arg('Base DN'), - param('security.authentication.hide_user_not_found'), - abstract_arg('search dn'), - abstract_arg('search password'), - ]) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - - ->set('security.authentication.provider.pre_authenticated', PreAuthenticatedAuthenticationProvider::class) - ->abstract() - ->args([ - abstract_arg('User Provider'), - abstract_arg('UserChecker'), - ]) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use the new authenticator system instead.') - ->set('security.exception_listener', ExceptionListener::class) ->abstract() ->args([ diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/EventAliasTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/EventAliasTest.php index b30d4617785ac..55f7906e22d30 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/EventAliasTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/EventAliasTest.php @@ -31,18 +31,33 @@ public function testAliasedEvents() $dispatcher = $container->get('event_dispatcher'); $dispatcher->dispatch(new AuthenticationSuccessEvent($this->createMock(TokenInterface::class)), AuthenticationEvents::AUTHENTICATION_SUCCESS); - $dispatcher->dispatch(new AuthenticationFailureEvent($this->createMock(TokenInterface::class), new AuthenticationException()), AuthenticationEvents::AUTHENTICATION_FAILURE); $dispatcher->dispatch(new InteractiveLoginEvent($this->createMock(Request::class), $this->createMock(TokenInterface::class)), SecurityEvents::INTERACTIVE_LOGIN); $dispatcher->dispatch(new SwitchUserEvent($this->createMock(Request::class), $this->createMock(UserInterface::class), $this->createMock(TokenInterface::class)), SecurityEvents::SWITCH_USER); $this->assertEquals( [ 'onAuthenticationSuccess' => 1, - 'onAuthenticationFailure' => 1, 'onInteractiveLogin' => 1, 'onSwitchUser' => 1, ], $container->get('test_subscriber')->calledMethods ); } + + /** + * @group legacy + */ + public function testAliasedLegacyEvent() + { + $client = $this->createClient(['test_case' => 'AliasedEvents', 'root_config' => 'config.yml']); + $container = $client->getContainer(); + $dispatcher = $container->get('event_dispatcher'); + + $dispatcher->dispatch(new AuthenticationFailureEvent($this->createMock(TokenInterface::class), new AuthenticationException()), AuthenticationEvents::AUTHENTICATION_FAILURE); + + $this->assertEquals( + ['onAuthenticationFailure' => 1], + $container->get('test_subscriber')->calledMethods + ); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 761b3dbe172f7..1ebe4c7a8686c 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -32,7 +32,7 @@ "symfony/security-http": "^5.3" }, "require-dev": { - "doctrine/doctrine-bundle": "^2.0", + "doctrine/annotations": "^1.10.4", "symfony/asset": "^4.4|^5.0", "symfony/browser-kit": "^4.4|^5.0", "symfony/console": "^4.4|^5.0", diff --git a/src/Symfony/Bundle/TwigBundle/README.md b/src/Symfony/Bundle/TwigBundle/README.md index 2d6266ef807a0..3ae2985baef94 100644 --- a/src/Symfony/Bundle/TwigBundle/README.md +++ b/src/Symfony/Bundle/TwigBundle/README.md @@ -7,7 +7,7 @@ framework. 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) + * [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/Bundle/WebProfilerBundle/README.md b/src/Symfony/Bundle/WebProfilerBundle/README.md index 49df78bb32e24..e3c1400b1c6e9 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/README.md +++ b/src/Symfony/Bundle/WebProfilerBundle/README.md @@ -10,7 +10,7 @@ vulnerabilities in your project. 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) + * [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/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index 58d71055da88f..2dfa26918f420 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -5,7 +5,7 @@ them as JavaScript source code. Always use '/*' comments instead of '//' comments to avoid impossible-to-debug side-effects #} -if (typeof Sfjs === 'undefined') { +if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { Sfjs = (function() { "use strict"; diff --git a/src/Symfony/Component/Asset/README.md b/src/Symfony/Component/Asset/README.md index 3291698493bc1..37e7ea37014ff 100644 --- a/src/Symfony/Component/Asset/README.md +++ b/src/Symfony/Component/Asset/README.md @@ -7,8 +7,8 @@ CSS stylesheets, JavaScript files and image files. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/asset/introduction.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/asset/introduction.html) + * [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/BrowserKit/README.md b/src/Symfony/Component/BrowserKit/README.md index ef6d75b7837e5..aa5217096c7e4 100644 --- a/src/Symfony/Component/BrowserKit/README.md +++ b/src/Symfony/Component/BrowserKit/README.md @@ -10,8 +10,8 @@ component to make real HTTP requests. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/browser_kit/introduction.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/browser_kit/introduction.html) + * [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/Cache/README.md b/src/Symfony/Component/Cache/README.md index 8fc7564415770..74052052c8c33 100644 --- a/src/Symfony/Component/Cache/README.md +++ b/src/Symfony/Component/Cache/README.md @@ -12,8 +12,8 @@ interoperability between PSR-6 implementations. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/cache.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/cache.html) + * [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/Config/Definition/PrototypedArrayNode.php b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php index 306fcd613071e..59675240abf99 100644 --- a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php +++ b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php @@ -215,11 +215,11 @@ protected function normalizeValue($value) $value = $this->remapXml($value); - $isAssoc = array_keys($value) !== range(0, \count($value) - 1); + $isList = array_is_list($value); $normalized = []; foreach ($value as $k => $v) { if (null !== $this->keyAttribute && \is_array($v)) { - if (!isset($v[$this->keyAttribute]) && \is_int($k) && !$isAssoc) { + if (!isset($v[$this->keyAttribute]) && \is_int($k) && $isList) { $ex = new InvalidConfigurationException(sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath())); $ex->setPath($this->getPath()); @@ -261,7 +261,7 @@ protected function normalizeValue($value) } $prototype = $this->getPrototypeForChild($k); - if (null !== $this->keyAttribute || $isAssoc) { + if (null !== $this->keyAttribute || !$isList) { $normalized[$k] = $prototype->normalize($v); } else { $normalized[] = $prototype->normalize($v); @@ -294,9 +294,10 @@ protected function mergeValues($leftSide, $rightSide) return $rightSide; } + $isList = array_is_list($rightSide); foreach ($rightSide as $k => $v) { - // prototype, and key is irrelevant, append the element - if (null === $this->keyAttribute) { + // prototype, and key is irrelevant there are no named keys, append the element + if (null === $this->keyAttribute && $isList) { $leftSide[] = $v; continue; } diff --git a/src/Symfony/Component/Config/README.md b/src/Symfony/Component/Config/README.md index 5315624661e6a..10c2ddd05831b 100644 --- a/src/Symfony/Component/Config/README.md +++ b/src/Symfony/Component/Config/README.md @@ -8,8 +8,8 @@ files, or for instance a database). Resources --------- - * [Documentation](https://symfony.com/doc/current/components/config.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/config.html) + * [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/Config/Tests/Definition/PrototypedArrayNodeTest.php b/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php index 7a58ead8da967..58d2408a71c90 100644 --- a/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/PrototypedArrayNodeTest.php @@ -338,4 +338,56 @@ public function getDataForKeyRemovedLeftValueOnly() ], ]; } + + /** + * @dataProvider getPrototypedArrayNodeDataToMerge + */ + public function testPrototypedArrayNodeMerge($left, $right, $expected) + { + $node = new PrototypedArrayNode('options'); + $node->setNormalizeKeys(false); + $node->setPrototype(new VariableNode('value')); + $node->setDefaultValue([]); + + $result = $node->merge($left, $right); + + self::assertSame($result, $expected); + } + + public function getPrototypedArrayNodeDataToMerge() + { + return [ + // data to merged is a plain array + [ + ['foo', 'bar'], + ['foo', 'baz', 'qux'], + ['foo', 'bar', 'foo', 'baz', 'qux'], + ], + // data to be merged is an associative array + [ + ['option1' => true, 'option2' => 'foo'], + [ + 'option2' => 'bar', + 'option3' => 42, + 'option4' => [ + 'option41' => 'baz', + 'option42' => [ + 'option423' => 'qux', + ], + ], + ], + [ + 'option1' => true, + 'option2' => 'bar', + 'option3' => 42, + 'option4' => [ + 'option41' => 'baz', + 'option42' => [ + 'option423' => 'qux', + ], + ], + ], + ], + ]; + } } diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index 1e5a96f360688..b99d04c7d8654 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -20,7 +20,8 @@ "symfony/deprecation-contracts": "^2.1", "symfony/filesystem": "^4.4|^5.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php81": "^1.22" }, "require-dev": { "symfony/event-dispatcher": "^4.4|^5.0", diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 928589eb8244f..4bf3ed3960a0f 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -520,7 +520,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string if ($isNotStyledByTag) { $cellFormat = $cell->getStyle()->getCellFormat(); if (!\is_string($cellFormat)) { - $tag = http_build_query($cell->getStyle()->getTagOptions(), null, ';'); + $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';'); $cellFormat = '<'.$tag.'>%s'; } diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 6d10e696e8fac..04fd788a914d6 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -42,7 +42,7 @@ class InputOption public const VALUE_IS_ARRAY = 8; /** - * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). + * The option may have either positive or negative value (e.g. --ansi or --no-ansi). */ public const VALUE_NEGATABLE = 16; diff --git a/src/Symfony/Component/Console/README.md b/src/Symfony/Component/Console/README.md index 3e2fc605e5bfd..c89b4a1a2066b 100644 --- a/src/Symfony/Component/Console/README.md +++ b/src/Symfony/Component/Console/README.md @@ -7,11 +7,11 @@ interfaces. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/console.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/console.html) + * [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) Credits ------- diff --git a/src/Symfony/Component/CssSelector/README.md b/src/Symfony/Component/CssSelector/README.md index 7c4c411635dc2..ede4a3acc3157 100644 --- a/src/Symfony/Component/CssSelector/README.md +++ b/src/Symfony/Component/CssSelector/README.md @@ -6,11 +6,11 @@ The CssSelector component converts CSS selectors to XPath expressions. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/css_selector.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/css_selector.html) + * [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) Credits ------- diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php index 527eec80ef5c8..85c2f214a1a90 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php @@ -97,10 +97,12 @@ public function process(ContainerBuilder $container) $decoratingTags = $decoratingDefinition->getTags(); $resetTags = []; - if (isset($decoratingTags['container.service_locator'])) { - // container.service_locator has special logic and it must not be transferred out to decorators - $resetTags = ['container.service_locator' => $decoratingTags['container.service_locator']]; - unset($decoratingTags['container.service_locator']); + // container.service_locator and container.service_subscriber have special logic and they must not be transferred out to decorators + foreach (['container.service_locator', 'container.service_subscriber'] as $containerTag) { + if (isset($decoratingTags[$containerTag])) { + $resetTags[$containerTag] = $decoratingTags[$containerTag]; + unset($decoratingTags[$containerTag]); + } } $definition->setTags(array_merge($decoratingTags, $definition->getTags())); diff --git a/src/Symfony/Component/DependencyInjection/README.md b/src/Symfony/Component/DependencyInjection/README.md index cb2d4a11c5886..fa6719a7998f1 100644 --- a/src/Symfony/Component/DependencyInjection/README.md +++ b/src/Symfony/Component/DependencyInjection/README.md @@ -7,8 +7,8 @@ way objects are constructed in your application. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) + * [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/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php index ebc4b04da8f33..77f0742acd3a2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php @@ -242,6 +242,25 @@ public function testProcessLeavesServiceLocatorTagOnOriginalDefinition() $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); } + public function testProcessLeavesServiceSubscriberTagOnOriginalDefinition() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->setTags(['container.service_subscriber' => [], 'bar' => ['attr' => 'baz']]) + ; + $container + ->register('baz') + ->setTags(['foobar' => ['attr' => 'bar']]) + ->setDecoratedService('foo') + ; + + $this->process($container); + + $this->assertEquals(['container.service_subscriber' => []], $container->getDefinition('baz.inner')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); + } + public function testGenericInnerReference() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DomCrawler/README.md b/src/Symfony/Component/DomCrawler/README.md index 5fad2e27adc2f..c77a5e39cff2a 100644 --- a/src/Symfony/Component/DomCrawler/README.md +++ b/src/Symfony/Component/DomCrawler/README.md @@ -6,8 +6,8 @@ The DomCrawler component eases DOM navigation for HTML and XML documents. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/dom_crawler.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/dom_crawler.html) + * [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/Dotenv/README.md b/src/Symfony/Component/Dotenv/README.md index 855b8c02a1df6..08c90fcc88022 100644 --- a/src/Symfony/Component/Dotenv/README.md +++ b/src/Symfony/Component/Dotenv/README.md @@ -30,7 +30,7 @@ $dotenv->loadEnv(__DIR__.'/.env'); 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) + * [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/ErrorHandler/README.md b/src/Symfony/Component/ErrorHandler/README.md index 4ad3d0e2b43a7..12c0bfa6d6ca9 100644 --- a/src/Symfony/Component/ErrorHandler/README.md +++ b/src/Symfony/Component/ErrorHandler/README.md @@ -38,7 +38,7 @@ $data = ErrorHandler::call(static function () use ($filename, $datetimeFormat) { 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) + * [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/ErrorHandler/Resources/assets/js/exception.js b/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js index 8cc7b5318449a..0720a3a358aac 100644 --- a/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js +++ b/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js @@ -1,279 +1,280 @@ /* This file is based on WebProfilerBundle/Resources/views/Profiler/base_js.html.twig. If you make any change in this file, verify the same change is needed in the other file. */ /* .tab'); - var tabNavigation = document.createElement('ul'); - tabNavigation.className = 'tab-navigation'; - - var selectedTabId = 'tab-' + i + '-0'; /* select the first tab by default */ - for (var j = 0; j < tabs.length; j++) { - var tabId = 'tab-' + i + '-' + j; - var tabTitle = tabs[j].querySelector('.tab-title').innerHTML; - - var tabNavigationItem = document.createElement('li'); - tabNavigationItem.setAttribute('data-tab-id', tabId); - if (hasClass(tabs[j], 'active')) { selectedTabId = tabId; } - if (hasClass(tabs[j], 'disabled')) { addClass(tabNavigationItem, 'disabled'); } - tabNavigationItem.innerHTML = tabTitle; - tabNavigation.appendChild(tabNavigationItem); - - var tabContent = tabs[j].querySelector('.tab-content'); - tabContent.parentElement.setAttribute('id', tabId); - } +if (typeof Sfjs === 'undefined') { + Sfjs = (function() { + "use strict"; + + if ('classList' in document.documentElement) { + var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); }; + var removeClass = function(el, cssClass) { el.classList.remove(cssClass); }; + var addClass = function(el, cssClass) { el.classList.add(cssClass); }; + var toggleClass = function(el, cssClass) { el.classList.toggle(cssClass); }; + } else { + var hasClass = function (el, cssClass) { return el.className.match(new RegExp('\\b' + cssClass + '\\b')); }; + var removeClass = function(el, cssClass) { el.className = el.className.replace(new RegExp('\\b' + cssClass + '\\b'), ' '); }; + var addClass = function(el, cssClass) { if (!hasClass(el, cssClass)) { el.className += " " + cssClass; } }; + var toggleClass = function(el, cssClass) { hasClass(el, cssClass) ? removeClass(el, cssClass) : addClass(el, cssClass); }; + } - tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild); - addClass(document.querySelector('[data-tab-id="' + selectedTabId + '"]'), 'active'); - } + var addEventListener; + + var el = document.createElement('div'); + if (!('addEventListener' in el)) { + addEventListener = function (element, eventName, callback) { + element.attachEvent('on' + eventName, callback); + }; + } else { + addEventListener = function (element, eventName, callback) { + element.addEventListener(eventName, callback, false); + }; + } - /* display the active tab and add the 'click' event listeners */ - for (i = 0; i < tabGroups.length; i++) { - tabNavigation = tabGroups[i].querySelectorAll(':scope >.tab-navigation li'); + return { + addEventListener: addEventListener, - for (j = 0; j < tabNavigation.length; j++) { - tabId = tabNavigation[j].getAttribute('data-tab-id'); - document.getElementById(tabId).querySelector('.tab-title').className = 'hidden'; + createTabs: function() { + var tabGroups = document.querySelectorAll('.sf-tabs:not([data-processed=true])'); - if (hasClass(tabNavigation[j], 'active')) { - document.getElementById(tabId).className = 'block'; - } else { - document.getElementById(tabId).className = 'hidden'; + /* create the tab navigation for each group of tabs */ + for (var i = 0; i < tabGroups.length; i++) { + var tabs = tabGroups[i].querySelectorAll(':scope > .tab'); + var tabNavigation = document.createElement('ul'); + tabNavigation.className = 'tab-navigation'; + + var selectedTabId = 'tab-' + i + '-0'; /* select the first tab by default */ + for (var j = 0; j < tabs.length; j++) { + var tabId = 'tab-' + i + '-' + j; + var tabTitle = tabs[j].querySelector('.tab-title').innerHTML; + + var tabNavigationItem = document.createElement('li'); + tabNavigationItem.setAttribute('data-tab-id', tabId); + if (hasClass(tabs[j], 'active')) { selectedTabId = tabId; } + if (hasClass(tabs[j], 'disabled')) { addClass(tabNavigationItem, 'disabled'); } + tabNavigationItem.innerHTML = tabTitle; + tabNavigation.appendChild(tabNavigationItem); + + var tabContent = tabs[j].querySelector('.tab-content'); + tabContent.parentElement.setAttribute('id', tabId); } - tabNavigation[j].addEventListener('click', function(e) { - var activeTab = e.target || e.srcElement; + tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild); + addClass(document.querySelector('[data-tab-id="' + selectedTabId + '"]'), 'active'); + } - /* needed because when the tab contains HTML contents, user can click */ - /* on any of those elements instead of their parent '
  • ' element */ - while (activeTab.tagName.toLowerCase() !== 'li') { - activeTab = activeTab.parentNode; - } + /* display the active tab and add the 'click' event listeners */ + for (i = 0; i < tabGroups.length; i++) { + tabNavigation = tabGroups[i].querySelectorAll(':scope >.tab-navigation li'); - /* get the full list of tabs through the parent of the active tab element */ - var tabNavigation = activeTab.parentNode.children; - for (var k = 0; k < tabNavigation.length; k++) { - var tabId = tabNavigation[k].getAttribute('data-tab-id'); + for (j = 0; j < tabNavigation.length; j++) { + tabId = tabNavigation[j].getAttribute('data-tab-id'); + document.getElementById(tabId).querySelector('.tab-title').className = 'hidden'; + + if (hasClass(tabNavigation[j], 'active')) { + document.getElementById(tabId).className = 'block'; + } else { document.getElementById(tabId).className = 'hidden'; - removeClass(tabNavigation[k], 'active'); } - addClass(activeTab, 'active'); - var activeTabId = activeTab.getAttribute('data-tab-id'); - document.getElementById(activeTabId).className = 'block'; - }); - } - - tabGroups[i].setAttribute('data-processed', 'true'); - } - }, + tabNavigation[j].addEventListener('click', function(e) { + var activeTab = e.target || e.srcElement; - createToggles: function() { - var toggles = document.querySelectorAll('.sf-toggle:not([data-processed=true])'); + /* needed because when the tab contains HTML contents, user can click */ + /* on any of those elements instead of their parent '
  • ' element */ + while (activeTab.tagName.toLowerCase() !== 'li') { + activeTab = activeTab.parentNode; + } - for (var i = 0; i < toggles.length; i++) { - var elementSelector = toggles[i].getAttribute('data-toggle-selector'); - var element = document.querySelector(elementSelector); + /* get the full list of tabs through the parent of the active tab element */ + var tabNavigation = activeTab.parentNode.children; + for (var k = 0; k < tabNavigation.length; k++) { + var tabId = tabNavigation[k].getAttribute('data-tab-id'); + document.getElementById(tabId).className = 'hidden'; + removeClass(tabNavigation[k], 'active'); + } - addClass(element, 'sf-toggle-content'); + addClass(activeTab, 'active'); + var activeTabId = activeTab.getAttribute('data-tab-id'); + document.getElementById(activeTabId).className = 'block'; + }); + } - if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') { - addClass(toggles[i], 'sf-toggle-on'); - addClass(element, 'sf-toggle-visible'); - } else { - addClass(toggles[i], 'sf-toggle-off'); - addClass(element, 'sf-toggle-hidden'); + tabGroups[i].setAttribute('data-processed', 'true'); } + }, - addEventListener(toggles[i], 'click', function(e) { - e.preventDefault(); + createToggles: function() { + var toggles = document.querySelectorAll('.sf-toggle:not([data-processed=true])'); - if ('' !== window.getSelection().toString()) { - /* Don't do anything on text selection */ - return; - } + for (var i = 0; i < toggles.length; i++) { + var elementSelector = toggles[i].getAttribute('data-toggle-selector'); + var element = document.querySelector(elementSelector); - var toggle = e.target || e.srcElement; + addClass(element, 'sf-toggle-content'); - /* needed because when the toggle contains HTML contents, user can click */ - /* on any of those elements instead of their parent '.sf-toggle' element */ - while (!hasClass(toggle, 'sf-toggle')) { - toggle = toggle.parentNode; + if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') { + addClass(toggles[i], 'sf-toggle-on'); + addClass(element, 'sf-toggle-visible'); + } else { + addClass(toggles[i], 'sf-toggle-off'); + addClass(element, 'sf-toggle-hidden'); } - var element = document.querySelector(toggle.getAttribute('data-toggle-selector')); + addEventListener(toggles[i], 'click', function(e) { + e.preventDefault(); - toggleClass(toggle, 'sf-toggle-on'); - toggleClass(toggle, 'sf-toggle-off'); - toggleClass(element, 'sf-toggle-hidden'); - toggleClass(element, 'sf-toggle-visible'); + if ('' !== window.getSelection().toString()) { + /* Don't do anything on text selection */ + return; + } - /* the toggle doesn't change its contents when clicking on it */ - if (!toggle.hasAttribute('data-toggle-alt-content')) { - return; - } + var toggle = e.target || e.srcElement; - if (!toggle.hasAttribute('data-toggle-original-content')) { - toggle.setAttribute('data-toggle-original-content', toggle.innerHTML); - } + /* needed because when the toggle contains HTML contents, user can click */ + /* on any of those elements instead of their parent '.sf-toggle' element */ + while (!hasClass(toggle, 'sf-toggle')) { + toggle = toggle.parentNode; + } - var currentContent = toggle.innerHTML; - var originalContent = toggle.getAttribute('data-toggle-original-content'); - var altContent = toggle.getAttribute('data-toggle-alt-content'); - toggle.innerHTML = currentContent !== altContent ? altContent : originalContent; - }); + var element = document.querySelector(toggle.getAttribute('data-toggle-selector')); + + toggleClass(toggle, 'sf-toggle-on'); + toggleClass(toggle, 'sf-toggle-off'); + toggleClass(element, 'sf-toggle-hidden'); + toggleClass(element, 'sf-toggle-visible'); - /* Prevents from disallowing clicks on links inside toggles */ - var toggleLinks = toggles[i].querySelectorAll('a'); - for (var j = 0; j < toggleLinks.length; j++) { - addEventListener(toggleLinks[j], 'click', function(e) { - e.stopPropagation(); + /* the toggle doesn't change its contents when clicking on it */ + if (!toggle.hasAttribute('data-toggle-alt-content')) { + return; + } + + if (!toggle.hasAttribute('data-toggle-original-content')) { + toggle.setAttribute('data-toggle-original-content', toggle.innerHTML); + } + + var currentContent = toggle.innerHTML; + var originalContent = toggle.getAttribute('data-toggle-original-content'); + var altContent = toggle.getAttribute('data-toggle-alt-content'); + toggle.innerHTML = currentContent !== altContent ? altContent : originalContent; }); - } - toggles[i].setAttribute('data-processed', 'true'); - } - }, - - createFilters: function() { - document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) { - var filters = filter.closest('[data-filters]'), - type = 'choice', - name = filter.dataset.filter, - ucName = name.charAt(0).toUpperCase()+name.slice(1), - list = document.createElement('ul'), - values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'), - labels = {}, - defaults = null, - indexed = {}, - processed = {}; - if (typeof values === 'string') { - type = 'level'; - labels = values.split(','); - values = values.toLowerCase().split(','); - defaults = values.length - 1; - } - addClass(list, 'filter-list'); - addClass(list, 'filter-list-'+type); - values.forEach(function (value, i) { - if (value instanceof HTMLElement) { - value = value.dataset['filter'+ucName]; - } - if (value in processed) { - return; + /* Prevents from disallowing clicks on links inside toggles */ + var toggleLinks = toggles[i].querySelectorAll('a'); + for (var j = 0; j < toggleLinks.length; j++) { + addEventListener(toggleLinks[j], 'click', function(e) { + e.stopPropagation(); + }); } - var option = document.createElement('li'), - label = i in labels ? labels[i] : value, - active = false, - matches; - if ('' === label) { - option.innerHTML = '(none)'; - } else { - option.innerText = label; + + toggles[i].setAttribute('data-processed', 'true'); + } + }, + + createFilters: function() { + document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) { + var filters = filter.closest('[data-filters]'), + type = 'choice', + name = filter.dataset.filter, + ucName = name.charAt(0).toUpperCase()+name.slice(1), + list = document.createElement('ul'), + values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'), + labels = {}, + defaults = null, + indexed = {}, + processed = {}; + if (typeof values === 'string') { + type = 'level'; + labels = values.split(','); + values = values.toLowerCase().split(','); + defaults = values.length - 1; } - option.dataset.filter = value; - option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows'); - indexed[value] = i; - list.appendChild(option); - addEventListener(option, 'click', function () { - if ('choice' === type) { - filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { - if (option.dataset.filter === row.dataset['filter'+ucName]) { - toggleClass(row, 'filter-hidden-'+name); + addClass(list, 'filter-list'); + addClass(list, 'filter-list-'+type); + values.forEach(function (value, i) { + if (value instanceof HTMLElement) { + value = value.dataset['filter'+ucName]; + } + if (value in processed) { + return; + } + var option = document.createElement('li'), + label = i in labels ? labels[i] : value, + active = false, + matches; + if ('' === label) { + option.innerHTML = '(none)'; + } else { + option.innerText = label; + } + option.dataset.filter = value; + option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows'); + indexed[value] = i; + list.appendChild(option); + addEventListener(option, 'click', function () { + if ('choice' === type) { + filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { + if (option.dataset.filter === row.dataset['filter'+ucName]) { + toggleClass(row, 'filter-hidden-'+name); + } + }); + toggleClass(option, 'active'); + } else if ('level' === type) { + if (i === this.parentNode.querySelectorAll('.active').length - 1) { + return; } - }); - toggleClass(option, 'active'); - } else if ('level' === type) { - if (i === this.parentNode.querySelectorAll('.active').length - 1) { - return; - } - this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) { - if (j <= i) { - addClass(currentOption, 'active'); - if (i === j) { - addClass(currentOption, 'last-active'); + this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) { + if (j <= i) { + addClass(currentOption, 'active'); + if (i === j) { + addClass(currentOption, 'last-active'); + } else { + removeClass(currentOption, 'last-active'); + } } else { + removeClass(currentOption, 'active'); removeClass(currentOption, 'last-active'); } - } else { - removeClass(currentOption, 'active'); - removeClass(currentOption, 'last-active'); - } - }); - filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { - if (i < indexed[row.dataset['filter'+ucName]]) { - addClass(row, 'filter-hidden-'+name); - } else { - removeClass(row, 'filter-hidden-'+name); - } + }); + filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { + if (i < indexed[row.dataset['filter'+ucName]]) { + addClass(row, 'filter-hidden-'+name); + } else { + removeClass(row, 'filter-hidden-'+name); + } + }); + } + }); + if ('choice' === type) { + active = null === defaults || 0 <= defaults.indexOf(value); + } else if ('level' === type) { + active = i <= defaults; + if (active && i === defaults) { + addClass(option, 'last-active'); + } + } + if (active) { + addClass(option, 'active'); + } else { + filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) { + toggleClass(row, 'filter-hidden-'+name); }); } + processed[value] = true; }); - if ('choice' === type) { - active = null === defaults || 0 <= defaults.indexOf(value); - } else if ('level' === type) { - active = i <= defaults; - if (active && i === defaults) { - addClass(option, 'last-active'); - } - } - if (active) { - addClass(option, 'active'); - } else { - filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) { - toggleClass(row, 'filter-hidden-'+name); - }); + + if (1 < list.childNodes.length) { + filter.appendChild(list); + filter.dataset.filtered = ''; } - processed[value] = true; }); - - if (1 < list.childNodes.length) { - filter.appendChild(list); - filter.dataset.filtered = ''; - } - }); - } - }; -})(); - -Sfjs.addEventListener(document, 'DOMContentLoaded', function() { - Sfjs.createTabs(); - Sfjs.createToggles(); - Sfjs.createFilters(); -}); - + } + }; + })(); + + Sfjs.addEventListener(document, 'DOMContentLoaded', function() { + Sfjs.createTabs(); + Sfjs.createToggles(); + Sfjs.createFilters(); + }); +} /*]]>*/ diff --git a/src/Symfony/Component/EventDispatcher/CHANGELOG.md b/src/Symfony/Component/EventDispatcher/CHANGELOG.md index 82ce274be577c..4172876304155 100644 --- a/src/Symfony/Component/EventDispatcher/CHANGELOG.md +++ b/src/Symfony/Component/EventDispatcher/CHANGELOG.md @@ -48,21 +48,21 @@ CHANGELOG 3.4.0 ----- - * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. + * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. 3.3.0 ----- - * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. + * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. 3.0.0 ----- - * The method `getListenerPriority($eventName, $listener)` has been added to the - `EventDispatcherInterface`. - * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` - and `Event::getName()` have been removed. - The event dispatcher and the event name are passed to the listener call. + * The method `getListenerPriority($eventName, $listener)` has been added to the + `EventDispatcherInterface`. + * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` + and `Event::getName()` have been removed. + The event dispatcher and the event name are passed to the listener call. 2.5.0 ----- diff --git a/src/Symfony/Component/EventDispatcher/README.md b/src/Symfony/Component/EventDispatcher/README.md index e0d38eed017f8..dcdb68d218115 100644 --- a/src/Symfony/Component/EventDispatcher/README.md +++ b/src/Symfony/Component/EventDispatcher/README.md @@ -8,8 +8,8 @@ them. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) + * [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/ExpressionLanguage/README.md b/src/Symfony/Component/ExpressionLanguage/README.md index 08b310d10b140..2b2e3de535538 100644 --- a/src/Symfony/Component/ExpressionLanguage/README.md +++ b/src/Symfony/Component/ExpressionLanguage/README.md @@ -8,8 +8,8 @@ evaluate expressions. An expression is a one-liner that returns a value Resources --------- - * [Documentation](https://symfony.com/doc/current/components/expression_language/introduction.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/expression_language/introduction.html) + * [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/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 0cc97293b76d9..d4083feef6e24 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -423,14 +423,14 @@ public function readlink(string $path, bool $canonicalize = false) return null; } - if ('\\' === \DIRECTORY_SEPARATOR) { + if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70410) { $path = readlink($path); } return realpath($path); } - if ('\\' === \DIRECTORY_SEPARATOR) { + if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) { return realpath($path); } diff --git a/src/Symfony/Component/Filesystem/README.md b/src/Symfony/Component/Filesystem/README.md index cb03d43c15dd2..f2f6d45f7386e 100644 --- a/src/Symfony/Component/Filesystem/README.md +++ b/src/Symfony/Component/Filesystem/README.md @@ -6,8 +6,8 @@ The Filesystem component provides basic utilities for the filesystem. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/filesystem.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/filesystem.html) + * [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/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 4a1350de0b725..bedb2385e73e8 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -376,7 +376,7 @@ public function testRemoveCleansInvalidLinks() // create symlink to nonexistent dir rmdir($basePath.'dir'); - $this->assertFalse('\\' === \DIRECTORY_SEPARATOR ? @readlink($basePath.'dir-link') : is_dir($basePath.'dir-link')); + $this->assertFalse('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400 ? @readlink($basePath.'dir-link') : is_dir($basePath.'dir-link')); $this->filesystem->remove($basePath); @@ -1076,7 +1076,12 @@ public function testReadAbsoluteLink() $this->filesystem->symlink($link1, $link2); $this->assertEquals($file, $this->filesystem->readlink($link1)); - $this->assertEquals($link1, $this->filesystem->readlink($link2)); + + if (!('\\' == \DIRECTORY_SEPARATOR && \PHP_MAJOR_VERSION === 7 && \PHP_MINOR_VERSION === 3)) { + // Skip for Windows with PHP 7.3.* + $this->assertEquals($link1, $this->filesystem->readlink($link2)); + } + $this->assertEquals($file, $this->filesystem->readlink($link1, true)); $this->assertEquals($file, $this->filesystem->readlink($link2, true)); $this->assertEquals($file, $this->filesystem->readlink($file, true)); diff --git a/src/Symfony/Component/Finder/README.md b/src/Symfony/Component/Finder/README.md index 0b19c752572d8..22bdeb9bcf853 100644 --- a/src/Symfony/Component/Finder/README.md +++ b/src/Symfony/Component/Finder/README.md @@ -7,8 +7,8 @@ interface. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/finder.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/finder.html) + * [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/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php index e9896732f9020..2a4d10c0e3645 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php @@ -170,9 +170,9 @@ public function reverseTransform($value) empty($value['year']) ? $this->referenceDate->format('Y') : $value['year'], empty($value['month']) ? $this->referenceDate->format('m') : $value['month'], empty($value['day']) ? $this->referenceDate->format('d') : $value['day'], - empty($value['hour']) ? $this->referenceDate->format('H') : $value['hour'], - empty($value['minute']) ? $this->referenceDate->format('i') : $value['minute'], - empty($value['second']) ? $this->referenceDate->format('s') : $value['second'] + $value['hour'] ?? $this->referenceDate->format('H'), + $value['minute'] ?? $this->referenceDate->format('i'), + $value['second'] ?? $this->referenceDate->format('s') ), new \DateTimeZone($this->outputTimezone) ); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php index 2c34392ffde3b..e39a8607bd7cb 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -375,9 +375,7 @@ private function listYears(array $years) $result = []; foreach ($years as $year) { - if (false !== $y = gmmktime(0, 0, 0, 6, 15, $year)) { - $result[$y] = $year; - } + $result[\PHP_INT_SIZE === 4 ? \DateTime::createFromFormat('Y e', $year.' UTC')->format('U') : gmmktime(0, 0, 0, 6, 15, $year)] = $year; } return $result; diff --git a/src/Symfony/Component/Form/README.md b/src/Symfony/Component/Form/README.md index 5519cd00058dd..0cda654d7384f 100644 --- a/src/Symfony/Component/Form/README.md +++ b/src/Symfony/Component/Form/README.md @@ -6,8 +6,8 @@ The Form component allows you to easily create, process and reuse HTML forms. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/form.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/form.html) + * [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/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index 5891cc08aa29b..74e0a8d35524f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -204,6 +204,32 @@ public function testSubmitFromSingleTextRaw() $this->assertEquals('02.06.2010', $form->getViewData()); } + public function testArrayDateWithReferenceDoesUseReferenceTimeOnZero() + { + // we test against "de_DE", so we need the full implementation + IntlTestHelper::requireFullIntl($this, false); + + \Locale::setDefault('de_DE'); + + $input = [ + 'day' => '0', + 'month' => '0', + 'year' => '0', + ]; + + $form = $this->factory->create(static::TESTED_TYPE, $input, [ + 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, + 'model_timezone' => 'UTC', + 'view_timezone' => 'Europe/Berlin', + 'input' => 'array', + 'widget' => 'single_text', + ]); + + $this->assertSame($input, $form->getData()); + $this->assertEquals('01.01.1970', $form->getViewData()); + } + public function testSubmitFromText() { $form = $this->factory->create(static::TESTED_TYPE, null, [ @@ -927,19 +953,15 @@ public function testDayErrorsBubbleUp($widget) $this->assertSame([$error], iterator_to_array($form->getErrors())); } - public function testYearsFor32BitsMachines() + public function testYears() { - if (4 !== \PHP_INT_SIZE) { - $this->markTestSkipped('PHP 32 bit is required.'); - } - $view = $this->factory->create(static::TESTED_TYPE, null, [ - 'years' => range(1900, 2040), + 'years' => [1900, 2000, 2040], ]) ->createView(); $listChoices = []; - foreach (range(1902, 2037) as $y) { + foreach ([1900, 2000, 2040] as $y) { $listChoices[] = new ChoiceView($y, $y, $y); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php index 3c613065642dd..7d2bd950a9738 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php @@ -978,6 +978,28 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = [], $expectedDat $this->assertSame($expectedData, $form->getData()); } + public function testArrayTimeWithReferenceDoesNotUseReferenceTimeOnZero() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'Europe/Berlin', + 'reference_date' => new \DateTimeImmutable('01-01-2021 12:34:56', new \DateTimeZone('UTC')), + 'input' => 'array', + ]); + + $input = [ + 'hour' => '0', + 'minute' => '0', + ]; + $form->submit($input); + + $this->assertEquals([ + 'hour' => '23', + 'minute' => '0', + ], $form->getData()); + $this->assertSame($input, $form->getViewData()); + } + /** * @dataProvider provideEmptyData */ diff --git a/src/Symfony/Component/HttpClient/README.md b/src/Symfony/Component/HttpClient/README.md index 0c33db1c7c8e7..214489b7e7f76 100644 --- a/src/Symfony/Component/HttpClient/README.md +++ b/src/Symfony/Component/HttpClient/README.md @@ -6,8 +6,8 @@ The HttpClient component provides powerful methods to fetch HTTP resources synch Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_client.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/http_client.html) + * [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/HttpFoundation/README.md b/src/Symfony/Component/HttpFoundation/README.md index ac98f9b80ad5d..5cf9007444456 100644 --- a/src/Symfony/Component/HttpFoundation/README.md +++ b/src/Symfony/Component/HttpFoundation/README.md @@ -7,8 +7,8 @@ specification. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) + * [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/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php index e323fc3987ea9..27bf3e27a6de9 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php @@ -122,9 +122,6 @@ public function testGc() $this->proxy->gc(86400); } - /** - * @requires PHPUnit 5.1 - */ public function testValidateId() { $mock = $this->createMock(TestSessionHandler::class); @@ -137,9 +134,6 @@ public function testValidateId() $this->assertTrue($this->proxy->validateId('id')); } - /** - * @requires PHPUnit 5.1 - */ public function testUpdateTimestamp() { $mock = $this->createMock(TestSessionHandler::class); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Store.php b/src/Symfony/Component/HttpKernel/HttpCache/Store.php index c74a17f31d474..d3a79d7c9d15d 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/Store.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/Store.php @@ -347,7 +347,7 @@ private function load(string $key): ?string { $path = $this->getPath($key); - return is_file($path) && false !== ($contents = file_get_contents($path)) ? $contents : null; + return is_file($path) && false !== ($contents = @file_get_contents($path)) ? $contents : null; } /** diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b612558dcedd1..44bdd8d3398f2 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,19 +75,22 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '5.3.0-RC1'; + public const VERSION = '5.3.0'; public const VERSION_ID = 50300; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'RC1'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '05/2021'; public const END_OF_LIFE = '01/2022'; public function __construct(string $environment, bool $debug) { - $this->environment = $environment; + if (!$this->environment = $environment) { + throw new \InvalidArgumentException(sprintf('Invalid environment provided to "%s": the environment cannot be empty.', get_debug_type($this))); + } + $this->debug = $debug; } diff --git a/src/Symfony/Component/HttpKernel/README.md b/src/Symfony/Component/HttpKernel/README.md index 0136784a72d87..18d15f5ad835f 100644 --- a/src/Symfony/Component/HttpKernel/README.md +++ b/src/Symfony/Component/HttpKernel/README.md @@ -8,8 +8,8 @@ enough to create full-stack frameworks, micro-frameworks or advanced CMS systems Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_kernel.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/http_kernel.html) + * [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/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index e4df69e8672f7..47a337f006680 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -55,6 +55,14 @@ public function testConstructor() $this->assertLessThanOrEqual(microtime(true), $kernel->getStartTime()); } + public function testEmptyEnv() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage(sprintf('Invalid environment provided to "%s": the environment cannot be empty.', KernelForTest::class)); + + new KernelForTest('', false); + } + public function testClone() { $env = 'test_env'; diff --git a/src/Symfony/Component/Inflector/README.md b/src/Symfony/Component/Inflector/README.md index 4ad750db0c84d..e63fc09dcada0 100644 --- a/src/Symfony/Component/Inflector/README.md +++ b/src/Symfony/Component/Inflector/README.md @@ -12,7 +12,7 @@ The Inflector component converts words between their singular and plural forms 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) + * [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/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index 022624c284343..100443930315a 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -182,7 +182,7 @@ public static function create(?string $locale, ?int $datetype, ?int $timetype, $ /** * Format the date/time value (timestamp) as a string. * - * @param int|\DateTimeInterface $timestamp The timestamp to format + * @param int|string|\DateTimeInterface $timestamp The timestamp to format * * @return string|bool The formatted value or false if formatting failed * @@ -194,11 +194,15 @@ public function format($timestamp) { // intl allows timestamps to be passed as arrays - we don't if (\is_array($timestamp)) { - $message = 'Only integer Unix timestamps and DateTime objects are supported'; + $message = 'Only Unix timestamps and DateTime objects are supported'; throw new MethodArgumentValueNotImplementedException(__METHOD__, 'timestamp', $timestamp, $message); } + if (\is_string($timestamp) && $dt = \DateTime::createFromFormat('U', $timestamp)) { + $timestamp = $dt; + } + // behave like the intl extension $argumentError = null; if (!\is_int($timestamp) && !$timestamp instanceof \DateTimeInterface) { @@ -214,7 +218,7 @@ public function format($timestamp) } if ($timestamp instanceof \DateTimeInterface) { - $timestamp = $timestamp->getTimestamp(); + $timestamp = $timestamp->format('U'); } $transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId()); @@ -583,10 +587,9 @@ public function setTimeZone($timeZone) * * @return \DateTime */ - protected function createDateTime(int $timestamp) + protected function createDateTime(string $timestamp) { - $dateTime = new \DateTime(); - $dateTime->setTimestamp($timestamp); + $dateTime = \DateTime::createFromFormat('U', $timestamp); $dateTime->setTimezone($this->dateTimeZone); return $dateTime; diff --git a/src/Symfony/Component/Intl/README.md b/src/Symfony/Component/Intl/README.md index ae6d05336331f..96e0fdbf2c698 100644 --- a/src/Symfony/Component/Intl/README.md +++ b/src/Symfony/Component/Intl/README.md @@ -10,10 +10,10 @@ locales, you should [install the intl PHP extension][0] instead. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/intl.html) - * [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) - * [Docker images with intl support](https://hub.docker.com/r/jakzal/php-intl) - (for the Intl component development) + * [Documentation](https://symfony.com/doc/current/components/intl.html) + * [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) + * [Docker images with intl support](https://hub.docker.com/r/jakzal/php-intl) + (for the Intl component development) diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php index 214ddb26e95f4..765ac9cf9b8a0 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php @@ -75,7 +75,7 @@ public function testFormatWithUnsupportedTimestampArgument() } catch (\Exception $e) { $this->assertInstanceOf(MethodArgumentValueNotImplementedException::class, $e); - $this->assertStringEndsWith('Only integer Unix timestamps and DateTime objects are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage()); + $this->assertStringEndsWith('Only Unix timestamps and DateTime objects are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage()); } } diff --git a/src/Symfony/Component/Ldap/README.md b/src/Symfony/Component/Ldap/README.md index 81e7768c6fdd0..7bfbe4c20a040 100644 --- a/src/Symfony/Component/Ldap/README.md +++ b/src/Symfony/Component/Ldap/README.md @@ -15,8 +15,8 @@ previous version of the component will break with this version. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/ldap) - * [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) + * [Documentation](https://symfony.com/doc/current/components/ldap) + * [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/Ldap/Security/LdapUser.php b/src/Symfony/Component/Ldap/Security/LdapUser.php index 86d6b0c4ad19c..5188cbad4c0ca 100644 --- a/src/Symfony/Component/Ldap/Security/LdapUser.php +++ b/src/Symfony/Component/Ldap/Security/LdapUser.php @@ -76,7 +76,7 @@ public function getSalt(): ?string */ public function getUsername(): string { - trigger_deprecation('symfony/security-core', '5.3', 'Method "%s()" is deprecated and will be removed in 6.0, use getUserIdentifier() instead.', __METHOD__); + trigger_deprecation('symfony/ldap', '5.3', 'Method "%s()" is deprecated and will be removed in 6.0, use getUserIdentifier() instead.', __METHOD__); return $this->username; } @@ -121,7 +121,7 @@ public function isEqualTo(UserInterface $user): bool return false; } - if ($this->getUsername() !== $user->getUsername()) { + if ($this->getUserIdentifier() !== $user->getUserIdentifier()) { return false; } diff --git a/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php b/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php index 66b87a1c0d7e9..9a879c22490ef 100644 --- a/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php +++ b/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php @@ -138,6 +138,7 @@ public function testBindFailureShouldThrowAnException() $this->expectException(BadCredentialsException::class); $this->expectExceptionMessage('The presented password is invalid.'); + $this->ldap->method('escape')->willReturnArgument(0); $this->ldap->expects($this->any())->method('bind')->willThrowException(new ConnectionException()); $listener = $this->createListener(); @@ -178,6 +179,7 @@ public function testEmptyQueryResultShouldThrowAnException() ->withConsecutive( ['elsa', 'test1234A$'] ); + $this->ldap->method('escape')->willReturnArgument(0); $this->ldap->expects($this->once())->method('query')->willReturn($query); $listener = $this->createListener(); diff --git a/src/Symfony/Component/Lock/README.md b/src/Symfony/Component/Lock/README.md index 34ca84c13bc47..48c0591aa1435 100644 --- a/src/Symfony/Component/Lock/README.md +++ b/src/Symfony/Component/Lock/README.md @@ -2,13 +2,13 @@ Lock Component ============== The Lock component creates and manages locks, a mechanism to provide exclusive -access to a shared resource. +access to a shared resource. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/lock.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/lock.html) + * [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/Mailer/Bridge/Amazon/README.md b/src/Symfony/Component/Mailer/Bridge/Amazon/README.md index 1159927c41f9f..8624d50d2b99f 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/README.md @@ -6,7 +6,7 @@ Provides Amazon SES integration for Symfony Mailer. 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) + * [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/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php index 758dc3bd355c1..9180de06b26fe 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php @@ -13,8 +13,6 @@ use AsyncAws\Core\Configuration; use AsyncAws\Ses\SesClient; -use Symfony\Component\HttpClient\HttpClient; -use Symfony\Component\Mailer\Exception\LogicException; use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; use Symfony\Component\Mailer\Transport\AbstractTransportFactory; use Symfony\Component\Mailer\Transport\Dsn; @@ -35,46 +33,22 @@ public function create(Dsn $dsn): TransportInterface return new SesSmtpTransport($this->getUser($dsn), $this->getPassword($dsn), $region, $this->dispatcher, $this->logger); } - if (!class_exists(SesClient::class)) { - if (!class_exists(HttpClient::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component or AsyncAws package is not installed. Try running "composer require async-aws/ses".', __CLASS__)); - } - - trigger_deprecation('symfony/amazon-mailer', '5.1', 'Using the "%s" transport without AsyncAws is deprecated. Try running "composer require async-aws/ses".', $scheme, static::class); - - $user = $this->getUser($dsn); - $password = $this->getPassword($dsn); - $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); - $port = $dsn->getPort(); - - if ('ses+api' === $scheme) { - if (!\extension_loaded('simplexml')) { - throw new LogicException(sprintf('Cannot use "%s". Make sure you have "ext-simplexml" installed and enabled.', SesApiTransport::class)); - } - - return (new SesApiTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port); - } - if ('ses+https' === $scheme || 'ses' === $scheme) { - return (new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port); - } - } else { - switch ($scheme) { - case 'ses+api': - $class = SesApiAsyncAwsTransport::class; - // no break - case 'ses': - case 'ses+https': - $class = $class ?? SesHttpAsyncAwsTransport::class; - $options = [ - 'region' => $dsn->getOption('region') ?: 'eu-west-1', - 'accessKeyId' => $dsn->getUser(), - 'accessKeySecret' => $dsn->getPassword(), - ] + ( - 'default' === $dsn->getHost() ? [] : ['endpoint' => 'https://'.$dsn->getHost().($dsn->getPort() ? ':'.$dsn->getPort() : '')] - ); - - return new $class(new SesClient(Configuration::create($options), null, $this->client, $this->logger), $this->dispatcher, $this->logger); - } + switch ($scheme) { + case 'ses+api': + $class = SesApiAsyncAwsTransport::class; + // no break + case 'ses': + case 'ses+https': + $class = $class ?? SesHttpAsyncAwsTransport::class; + $options = [ + 'region' => $dsn->getOption('region') ?: 'eu-west-1', + 'accessKeyId' => $dsn->getUser(), + 'accessKeySecret' => $dsn->getPassword(), + ] + ( + 'default' === $dsn->getHost() ? [] : ['endpoint' => 'https://'.$dsn->getHost().($dsn->getPort() ? ':'.$dsn->getPort() : '')] + ); + + return new $class(new SesClient(Configuration::create($options), null, $this->client, $this->logger), $this->dispatcher, $this->logger); } throw new UnsupportedSchemeException($dsn, 'ses', $this->getSupportedSchemes()); diff --git a/src/Symfony/Component/Mailer/Bridge/Google/README.md b/src/Symfony/Component/Mailer/Bridge/Google/README.md index ac382d2169ddc..960cf705554c1 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Google/README.md @@ -6,7 +6,7 @@ Provides Google Gmail integration for Symfony Mailer. 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) + * [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/Mailer/Bridge/Mailchimp/README.md b/src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md index 56224554a504b..58860e6ada493 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md @@ -6,7 +6,7 @@ Provides Mandrill integration for Symfony Mailer. 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) + * [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/Mailer/Bridge/Mailgun/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md index be411a8ec9305..d2aa1d528220d 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md @@ -1,7 +1,13 @@ CHANGELOG ========= +5.2 +--- + + * Not prefixing headers with "h:" is no more deprecated + 5.1.0 +----- * Not prefixing headers with "h:" is deprecated. diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md b/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md index 4c04b71595d54..bfac5774f1bf7 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md @@ -6,7 +6,7 @@ Provides Mailgun integration for Symfony Mailer. 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) + * [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/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php index 1ea96bcd8fa55..61f3f43ee22f6 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php @@ -214,6 +214,7 @@ public function testTagAndMetadataHeaders() $json = json_encode(['foo' => 'bar']); $email = new Email(); $email->getHeaders()->addTextHeader('h:X-Mailgun-Variables', $json); + $email->getHeaders()->addTextHeader('Custom-Header', 'value'); $email->getHeaders()->add(new TagHeader('password-reset')); $email->getHeaders()->add(new MetadataHeader('Color', 'blue')); $email->getHeaders()->add(new MetadataHeader('Client-ID', '12345')); @@ -223,9 +224,10 @@ public function testTagAndMetadataHeaders() $method = new \ReflectionMethod(MailgunApiTransport::class, 'getPayload'); $method->setAccessible(true); $payload = $method->invoke($transport, $email, $envelope); - $this->assertArrayHasKey('h:x-mailgun-variables', $payload); $this->assertEquals($json, $payload['h:x-mailgun-variables']); + $this->assertArrayHasKey('h:custom-header', $payload); + $this->assertEquals('value', $payload['h:custom-header']); $this->assertArrayHasKey('o:tag', $payload); $this->assertSame('password-reset', $payload['o:tag']); $this->assertArrayHasKey('v:Color', $payload); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php index 692e209ef170c..174b82de32c8b 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php @@ -135,9 +135,7 @@ private function getPayload(Email $email, Envelope $envelope): array if (\in_array($prefix, ['h:', 't:', 'o:', 'v:']) || \in_array($name, ['recipient-variables', 'template', 'amp-html'])) { $headerName = $name; } else { - // fallback to prefix with "h:" to not break BC $headerName = 'h:'.$name; - trigger_deprecation('symfony/mailer', '5.1', 'Not prefixing the Mailgun header name with "h:" is deprecated. Use header name "%s" instead.', $headerName); } $payload[$headerName] = $header->getBodyAsString(); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json index 2e2534fff0251..728f11761c3da 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json @@ -17,7 +17,6 @@ ], "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", "symfony/mailer": "^5.2.6" }, "require-dev": { diff --git a/src/Symfony/Component/Mailer/Bridge/Mailjet/README.md b/src/Symfony/Component/Mailer/Bridge/Mailjet/README.md index 80635a357297e..634c674528fb2 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailjet/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Mailjet/README.md @@ -15,7 +15,7 @@ MAILER_DSN=mailjet+smtp://$PUBLIC_KEY:$PRIVATE_KEY@default 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) + * [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/Mailer/Bridge/Postmark/README.md b/src/Symfony/Component/Mailer/Bridge/Postmark/README.md index 44246cfe0904c..0f184a5f7db00 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/README.md @@ -6,7 +6,7 @@ Provides Postmark integration for Symfony Mailer. 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) + * [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/Mailer/Bridge/Sendgrid/README.md b/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md index 647d746be973f..1d5c6e1104b71 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md @@ -6,7 +6,7 @@ Provides Sendgrid integration for Symfony Mailer. 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) + * [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/Mailer/Bridge/Sendinblue/README.md b/src/Symfony/Component/Mailer/Bridge/Sendinblue/README.md index 2f19d94a92c85..15c896e1c4e86 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendinblue/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Sendinblue/README.md @@ -46,7 +46,7 @@ For more informations, you can refer to [Sendinblue API documentation](https://d 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) + * [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/Mailer/README.md b/src/Symfony/Component/Mailer/README.md index 173ebe44bc705..05c56fddf3259 100644 --- a/src/Symfony/Component/Mailer/README.md +++ b/src/Symfony/Component/Mailer/README.md @@ -36,16 +36,20 @@ set up the `BodyRenderer`: ```php use Symfony\Bridge\Twig\Mime\BodyRenderer; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Mailer\EventListener\MessageListener; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\Transport; use Twig\Environment as TwigEnvironment; $twig = new TwigEnvironment(...); -$messageListener = new MessageListener(new BodyRenderer($twig)); +$messageListener = new MessageListener(null, new BodyRenderer($twig)); $eventDispatcher = new EventDispatcher(); $eventDispatcher->addSubscriber($messageListener); +$transport = Transport::fromDsn('smtp://localhost', $eventDispatcher); $mailer = new Mailer($transport, null, $eventDispatcher); $email = (new TemplatedEmail()) @@ -56,14 +60,14 @@ $email = (new TemplatedEmail()) 'username' => 'foo', ]) ; -$mailer->mail($email); +$mailer->send($email); ``` Resources --------- - * [Documentation](https://symfony.com/doc/current/mailer.html) - * [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) + * [Documentation](https://symfony.com/doc/current/mailer.html) + * [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/Mailer/composer.json b/src/Symfony/Component/Mailer/composer.json index 627b1f714cea7..2fcd4c550fb2a 100644 --- a/src/Symfony/Component/Mailer/composer.json +++ b/src/Symfony/Component/Mailer/composer.json @@ -19,6 +19,7 @@ "php": ">=7.2.5", "egulias/email-validator": "^2.1.10|^3", "psr/log": "~1.0", + "symfony/deprecation-contracts": "^2.1", "symfony/event-dispatcher": "^4.4|^5.0", "symfony/mime": "^5.2.6", "symfony/polyfill-php80": "^1.15", diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/README.md b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/README.md index eabf1d6100b20..18da7769e90bb 100644 --- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/README.md +++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/README.md @@ -6,7 +6,7 @@ Provides Amazon SQS integration for Symfony Messenger. 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) + * [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/Messenger/Bridge/Amqp/README.md b/src/Symfony/Component/Messenger/Bridge/Amqp/README.md index 521b99ca9197e..c53ebcefad2cd 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/README.md +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/README.md @@ -6,7 +6,7 @@ Provides AMQP integration for Symfony Messenger. 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) + * [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/Messenger/Bridge/Beanstalkd/README.md b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/README.md index 56fa80511f11f..b0abb37b0cc3a 100644 --- a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/README.md +++ b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/README.md @@ -8,7 +8,7 @@ Full DSN with options: `beanstalkd://:?tube_name=&timeout=verify($hash, 'plain'); // returns true (valid) Resources --------- - * [Documentation](https://symfony.com/doc/current/password-hasher.html) - * [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) + * [Documentation](https://symfony.com/doc/current/password-hasher.html) + * [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/Process/README.md b/src/Symfony/Component/Process/README.md index b7ca5b4254942..afce5e45eee34 100644 --- a/src/Symfony/Component/Process/README.md +++ b/src/Symfony/Component/Process/README.md @@ -6,8 +6,8 @@ The Process component executes commands in sub-processes. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/process.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/process.html) + * [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/PropertyAccess/README.md b/src/Symfony/Component/PropertyAccess/README.md index f458b07c4e6e6..29cb233a010f3 100644 --- a/src/Symfony/Component/PropertyAccess/README.md +++ b/src/Symfony/Component/PropertyAccess/README.md @@ -7,8 +7,8 @@ object or array using a simple string notation. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/property_access.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/property_access.html) + * [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/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 276857c1d727c..33fd781fc742c 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -186,9 +186,6 @@ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetter() $this->propertyAccessor->getValue(new UninitializedPrivateProperty(), 'uninitialized'); } - /** - * @requires PHP 7 - */ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousClass() { $this->expectException(AccessException::class); @@ -206,9 +203,6 @@ public function getUninitialized(): array $this->propertyAccessor->getValue($object, 'uninitialized'); } - /** - * @requires PHP 7 - */ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass() { $this->expectException(AccessException::class); @@ -226,9 +220,6 @@ public function getUninitialized(): array $this->propertyAccessor->getValue($object, 'uninitialized'); } - /** - * @requires PHP 7 - */ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousChildClass() { $this->expectException(AccessException::class); diff --git a/src/Symfony/Component/PropertyInfo/README.md b/src/Symfony/Component/PropertyInfo/README.md index 92e91772a2b24..da3514fc9d013 100644 --- a/src/Symfony/Component/PropertyInfo/README.md +++ b/src/Symfony/Component/PropertyInfo/README.md @@ -7,8 +7,8 @@ using metadata of popular sources. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/property_info.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/property_info.html) + * [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/RateLimiter/README.md b/src/Symfony/Component/RateLimiter/README.md index 457978e364b92..fba1dd2281cd0 100644 --- a/src/Symfony/Component/RateLimiter/README.md +++ b/src/Symfony/Component/RateLimiter/README.md @@ -42,7 +42,7 @@ if ($limiter->consume(1)->isAccepted()) { 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) + * [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/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 9e1f14fc1cf62..b96638987bb86 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -81,15 +81,15 @@ CHANGELOG 3.3.0 ----- - * [DEPRECATION] Class parameters have been deprecated and will be removed in 4.0. - * router.options.generator_class - * router.options.generator_base_class - * router.options.generator_dumper_class - * router.options.matcher_class - * router.options.matcher_base_class - * router.options.matcher_dumper_class - * router.options.matcher.cache_class - * router.options.generator.cache_class + * [DEPRECATION] Class parameters have been deprecated and will be removed in 4.0. + * router.options.generator_class + * router.options.generator_base_class + * router.options.generator_dumper_class + * router.options.matcher_class + * router.options.matcher_base_class + * router.options.matcher_dumper_class + * router.options.matcher.cache_class + * router.options.generator.cache_class 3.2.0 ----- diff --git a/src/Symfony/Component/Routing/README.md b/src/Symfony/Component/Routing/README.md index 03b258ec8203b..49188191e5321 100644 --- a/src/Symfony/Component/Routing/README.md +++ b/src/Symfony/Component/Routing/README.md @@ -41,11 +41,26 @@ $url = $generator->generate('blog_show', [ // $url = '/blog/my-blog-post' ``` +Sponsor +------- + +The Routing component for Symfony 5.3 is [backed][1] by [redirection.io][2]. + +redirection.io logs all your website’s HTTP traffic, and lets you fix errors +with redirect rules in seconds. Give your marketing, SEO and IT teams the right +tool to manage your website traffic efficiently! + +Help Symfony by [sponsoring][3] its development! + Resources --------- - * [Documentation](https://symfony.com/doc/current/routing.html) - * [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) + * [Documentation](https://symfony.com/doc/current/routing.html) + * [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) + +[1]: https://symfony.com/backers +[2]: https://redirection.io/ +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php index d5f4e19291c6f..e249aa5da8903 100644 --- a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php @@ -74,17 +74,16 @@ public function testDeprecationArrayAsFirstArgument(string $parameter, $value, s * @requires PHP 8 * @dataProvider getValidParameters */ - public function testRouteParameters(string $methodName, string $getter, $expectedReturn) + public function testLoadFromAttribute(string $methodName, string $getter, $expectedReturn) { $route = $this->getMethodAnnotation($methodName, true); $this->assertEquals($route->$getter(), $expectedReturn); } /** - * @group legacy * @dataProvider getValidParameters */ - public function testLegacyRouteParameters(string $methodName, string $getter, $expectedReturn) + public function testLoadFromDoctrineAnnotation(string $methodName, string $getter, $expectedReturn) { $route = $this->getMethodAnnotation($methodName, false); $this->assertEquals($route->$getter(), $expectedReturn); diff --git a/src/Symfony/Component/Runtime/README.md b/src/Symfony/Component/Runtime/README.md index 0c6c051060415..2f533b0b5e234 100644 --- a/src/Symfony/Component/Runtime/README.md +++ b/src/Symfony/Component/Runtime/README.md @@ -11,8 +11,8 @@ are not covered by Symfony's Resources --------- - * [Documentation](https://symfony.com/doc/current/components/runtime.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/runtime.html) + * [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/Security/Core/README.md b/src/Symfony/Component/Security/Core/README.md index 70476d9e7f2b2..6b3e5c990107c 100644 --- a/src/Symfony/Component/Security/Core/README.md +++ b/src/Symfony/Component/Security/Core/README.md @@ -9,8 +9,8 @@ the Java Spring framework. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/security.html) + * [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/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php index 05340afa8537d..e60034f01f871 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php @@ -29,13 +29,13 @@ use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; +/** + * @group legacy + */ class DaoAuthenticationProviderTest extends TestCase { use ExpectDeprecationTrait; - /** - * @group legacy - */ public function testRetrieveUserWhenProviderDoesNotReturnAnUserInterface() { $this->expectException(AuthenticationServiceException::class); @@ -53,9 +53,6 @@ public function testRetrieveUserWhenProviderDoesNotReturnAnUserInterface() $method->invoke($provider, 'fabien', $this->getSupportedToken()); } - /** - * @group legacy - */ public function testRetrieveUserWhenUsernameIsNotFoundWithLegacyEncoderFactory() { $this->expectException(UserNotFoundException::class); diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php index 851758d8f46ab..c4bcd8f580100 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php @@ -26,6 +26,9 @@ use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\User\UserInterface; +/** + * @group legacy + */ class UserAuthenticationProviderTest extends TestCase { public function testSupports() diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/CustomUser.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/CustomUser.php new file mode 100644 index 0000000000000..52fea7a3ddd6d --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/CustomUser.php @@ -0,0 +1,48 @@ +username = $username; + $this->roles = $roles; + } + + public function getUsername(): string + { + return $this->username; + } + + public function getUserIdentifier(): string + { + return $this->username; + } + + public function getRoles(): array + { + return $this->roles; + } + + public function getPassword(): ?string + { + return null; + } + + public function getSalt(): ?string + { + return null; + } + + public function eraseCredentials(): void + { + } +} diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/switch-user-token-4.4.txt b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/switch-user-token-4.4.txt index 7b3f7c40920db..fc8af1432871f 100644 Binary files a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/switch-user-token-4.4.txt and b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Fixtures/switch-user-token-4.4.txt differ diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php index 477247e76da4f..e605615bc9a19 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Tests\Authentication\Token\Fixtures\CustomUser; use Symfony\Component\Security\Core\User\UserInterface; class SwitchUserTokenTest extends TestCase @@ -90,6 +91,25 @@ public function testSerializeNullImpersonateUrl() $this->assertNull($unserializedToken->getOriginatedFromUri()); } + /** + * Tests if an old version of SwitchUserToken can still be unserialized. + * + * The fixture was generated by running the following code with Symfony 4.4 and PHP 7.2. + * + * serialize( + * new SwitchUserToken( + * new CustomUser('john', ['ROLE_USER']), + * ['foo' => 'bar'], + * 'main', ['ROLE_USER'], + * new UsernamePasswordToken( + * new CustomUser('jane', ['ROLE_USER']), + * ['foo' => 'bar'], + * 'main', + * ['ROLE_USER'] + * ) + * ) + * ) + */ public function testUnserializeOldToken() { /** @var SwitchUserToken $token */ @@ -97,6 +117,7 @@ public function testUnserializeOldToken() self::assertInstanceOf(SwitchUserToken::class, $token); self::assertInstanceOf(UsernamePasswordToken::class, $token->getOriginalToken()); + self::assertInstanceOf(CustomUser::class, $token->getUser()); self::assertSame('john', $token->getUserIdentifier()); self::assertSame(['foo' => 'bar'], $token->getCredentials()); self::assertSame('main', $token->getFirewallName()); diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/switch-user-token-4.4.txt b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/switch-user-token-4.4.txt deleted file mode 100644 index f359ec4a3ddde..0000000000000 Binary files a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/switch-user-token-4.4.txt and /dev/null differ diff --git a/src/Symfony/Component/Security/Csrf/README.md b/src/Symfony/Component/Security/Csrf/README.md index 15b9ace238fb9..8933061585ff9 100644 --- a/src/Symfony/Component/Security/Csrf/README.md +++ b/src/Symfony/Component/Security/Csrf/README.md @@ -7,8 +7,8 @@ The Security CSRF (cross-site request forgery) component provides a class Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/security.html) + * [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/Security/Guard/README.md b/src/Symfony/Component/Security/Guard/README.md index 40083a48d7682..968558f79f86a 100644 --- a/src/Symfony/Component/Security/Guard/README.md +++ b/src/Symfony/Component/Security/Guard/README.md @@ -8,8 +8,8 @@ total control. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/security.html) + * [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/Security/Http/README.md b/src/Symfony/Component/Security/Http/README.md index dbac8c659c112..e12d19fbeb697 100644 --- a/src/Symfony/Component/Security/Http/README.md +++ b/src/Symfony/Component/Security/Http/README.md @@ -9,8 +9,8 @@ the Java Spring framework. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/security.html) + * [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/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php index 0e07a0805a821..02f6f0182f503 100644 --- a/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php @@ -99,11 +99,6 @@ public function provideCreateLoginLinkData() ['emailProperty' => 'ryan@symfonycasts.com', 'passwordProperty' => 'pwhash'], ]; - yield [ - new TestLoginLinkHandlerUser('weaverryan', 'ryan@symfonycasts.com', 'pwhash'), - ['emailProperty' => 'ryan@symfonycasts.com', 'passwordProperty' => 'pwhash'], - ]; - yield [ new TestLoginLinkHandlerUser('weaverryan', 'ryan@symfonycasts.com', 'pwhash'), ['lastAuthenticatedAt' => ''], diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php index 3eb39598276f6..44779829c613f 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php @@ -19,8 +19,8 @@ use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\CookieTheftException; -use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\InMemoryUser; +use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Http\RememberMe\PersistentRememberMeHandler; use Symfony\Component\Security\Http\RememberMe\RememberMeDetails; use Symfony\Component\Security\Http\RememberMe\ResponseListener; @@ -50,8 +50,8 @@ public function testCreateRememberMeCookie() ->method('createNewToken') ->with($this->callback(function ($persistentToken) { return $persistentToken instanceof PersistentToken - && $persistentToken->getUserIdentifier() === 'wouter' - && $persistentToken->getClass() === InMemoryUser::class; + && 'wouter' === $persistentToken->getUserIdentifier() + && InMemoryUser::class === $persistentToken->getClass(); })); $this->handler->createRememberMeCookie(new InMemoryUser('wouter', null)); @@ -71,7 +71,7 @@ public function testClearRememberMeCookie() /** @var Cookie $cookie */ $cookie = $this->request->attributes->get(ResponseListener::COOKIE_ATTR_NAME); - $this->assertEquals(null, $cookie->getValue()); + $this->assertNull($cookie->getValue()); } public function testConsumeRememberMeCookieValid() @@ -118,7 +118,7 @@ public function testConsumeRememberMeCookieExpired() $this->tokenProvider->expects($this->any()) ->method('loadTokenBySeries') ->with('series1') - ->willReturn(new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', new \DateTime('-'.(31536000 - 1).' years'))); + ->willReturn(new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', new \DateTime('-'.(31536000 + 1).' seconds'))); $this->tokenProvider->expects($this->never())->method('updateToken')->with('series1'); diff --git a/src/Symfony/Component/Semaphore/README.md b/src/Symfony/Component/Semaphore/README.md index 0b72c811b44e4..07eec132d3dd6 100644 --- a/src/Symfony/Component/Semaphore/README.md +++ b/src/Symfony/Component/Semaphore/README.md @@ -8,8 +8,8 @@ to provide exclusive access to a shared resource. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/semaphore.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/semaphore.html) + * [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/Serializer/README.md b/src/Symfony/Component/Serializer/README.md index 357d024a23ddc..22b2262682d62 100644 --- a/src/Symfony/Component/Serializer/README.md +++ b/src/Symfony/Component/Serializer/README.md @@ -8,8 +8,8 @@ JSON. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/serializer.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/serializer.html) + * [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/Stopwatch/README.md b/src/Symfony/Component/Stopwatch/README.md index 4c3cb7ecb3172..13a9dfa5f4f1f 100644 --- a/src/Symfony/Component/Stopwatch/README.md +++ b/src/Symfony/Component/Stopwatch/README.md @@ -36,7 +36,7 @@ $stopwatch->stopSection('phase_1'); 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) + * [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/String/README.md b/src/Symfony/Component/String/README.md index 23ad86ad8fe44..9c7e1e190dc49 100644 --- a/src/Symfony/Component/String/README.md +++ b/src/Symfony/Component/String/README.md @@ -7,8 +7,8 @@ with bytes, UTF-8 code points and grapheme clusters in a unified way. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/string.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/string.html) + * [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/String/Slugger/AsciiSlugger.php b/src/Symfony/Component/String/Slugger/AsciiSlugger.php index f45af71421725..5aecfeb5fcd7d 100644 --- a/src/Symfony/Component/String/Slugger/AsciiSlugger.php +++ b/src/Symfony/Component/String/Slugger/AsciiSlugger.php @@ -103,7 +103,7 @@ public function slug(string $string, string $separator = '-', string $locale = n $locale = $locale ?? $this->defaultLocale; $transliterator = []; - if ('de' === $locale || 0 === strpos($locale, 'de_')) { + if ($locale && ('de' === $locale || 0 === strpos($locale, 'de_'))) { // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl) $transliterator = ['de-ASCII']; } elseif (\function_exists('transliterator_transliterate') && $locale) { diff --git a/src/Symfony/Component/Templating/README.md b/src/Symfony/Component/Templating/README.md index a4798fdaafdef..72204d7cf89cb 100644 --- a/src/Symfony/Component/Templating/README.md +++ b/src/Symfony/Component/Templating/README.md @@ -36,7 +36,7 @@ Hello, escape($firstname) ?>! 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) + * [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/Translation/Bridge/Lokalise/README.md b/src/Symfony/Component/Translation/Bridge/Lokalise/README.md index 063996363eb89..64e6cd0de7800 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/README.md +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/README.md @@ -22,7 +22,7 @@ Go to the Project Settings in Lokalise to find the Project ID. 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) + * [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/Translation/Bridge/PoEditor/.gitattributes b/src/Symfony/Component/Translation/Bridge/PoEditor/.gitattributes deleted file mode 100644 index 84c7add058fb5..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -/Tests export-ignore -/phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/.gitignore b/src/Symfony/Component/Translation/Bridge/PoEditor/.gitignore deleted file mode 100644 index c49a5d8df5c65..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/CHANGELOG.md b/src/Symfony/Component/Translation/Bridge/PoEditor/CHANGELOG.md deleted file mode 100644 index bbb9efcaeb29b..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -CHANGELOG -========= - -5.3 ---- - - * Create the bridge diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/LICENSE b/src/Symfony/Component/Translation/Bridge/PoEditor/LICENSE deleted file mode 100644 index efb17f98e7dd3..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -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/Translation/Bridge/PoEditor/PoEditorHttpClient.php b/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorHttpClient.php deleted file mode 100644 index 110020815f297..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorHttpClient.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Translation\Bridge\PoEditor; - -use Symfony\Component\HttpClient\DecoratorTrait; -use Symfony\Component\HttpClient\ScopingHttpClient; -use Symfony\Contracts\HttpClient\HttpClientInterface; -use Symfony\Contracts\HttpClient\ResponseInterface; - -final class PoEditorHttpClient implements HttpClientInterface -{ - use DecoratorTrait; - - public function request(string $method, string $url, array $options = []): ResponseInterface - { - if (isset($options['poeditor_credentials'])) { - if ('POST' === $method) { - $options['body'] = $options['poeditor_credentials'] + $options['body']; - } - unset($options['poeditor_credentials']); - } - - return $this->client->request($method, $url, $options); - } - - public static function create(HttpClientInterface $client, string $baseUri, string $apiToken, string $projectId): HttpClientInterface - { - return ScopingHttpClient::forBaseUri(new self($client), $baseUri, [ - 'poeditor_credentials' => [ - 'api_token' => $apiToken, - 'id' => $projectId, - ], - ]); - } -} diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorProvider.php b/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorProvider.php deleted file mode 100644 index 5249e95307d8e..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorProvider.php +++ /dev/null @@ -1,214 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Translation\Bridge\PoEditor; - -use Psr\Log\LoggerInterface; -use Symfony\Component\Translation\Exception\ProviderException; -use Symfony\Component\Translation\Loader\LoaderInterface; -use Symfony\Component\Translation\Provider\ProviderInterface; -use Symfony\Component\Translation\TranslatorBag; -use Symfony\Component\Translation\TranslatorBagInterface; -use Symfony\Contracts\HttpClient\HttpClientInterface; - -/** - * @author Mathieu Santostefano - * - * In PoEditor: - * * Terms refer to Symfony's translation keys; - * * Translations refer to Symfony's translated messages; - * * Context fields refer to Symfony's translation domains - * - * PoEditor's API always returns 200 status code, even in case of failure. - * - * @experimental in 5.3 - */ -final class PoEditorProvider implements ProviderInterface -{ - private $client; - private $loader; - private $logger; - private $defaultLocale; - private $endpoint; - - public function __construct(HttpClientInterface $client, LoaderInterface $loader, LoggerInterface $logger, string $defaultLocale, string $endpoint) - { - $this->client = $client; - $this->loader = $loader; - $this->logger = $logger; - $this->defaultLocale = $defaultLocale; - $this->endpoint = $endpoint; - } - - public function __toString(): string - { - return sprintf('poeditor://%s', $this->endpoint); - } - - public function write(TranslatorBagInterface $translatorBag): void - { - $defaultCatalogue = $translatorBag->getCatalogue($this->defaultLocale); - - if (!$defaultCatalogue) { - $defaultCatalogue = $translatorBag->getCatalogues()[0]; - } - - $terms = $translationsToAdd = []; - foreach ($defaultCatalogue->all() as $domain => $messages) { - foreach ($messages as $id => $message) { - $terms[] = [ - 'term' => $id, - 'reference' => $id, - // tags field is mandatory to export all translations in read method. - 'tags' => [$domain], - 'context' => $domain, - ]; - } - } - $this->addTerms($terms); - - foreach ($translatorBag->getCatalogues() as $catalogue) { - $locale = $catalogue->getLocale(); - foreach ($catalogue->all() as $domain => $messages) { - foreach ($messages as $id => $message) { - $translationsToAdd[$locale][] = [ - 'term' => $id, - 'context' => $domain, - 'translation' => [ - 'content' => $message, - ], - ]; - } - } - } - - $this->addTranslations($translationsToAdd); - } - - public function read(array $domains, array $locales): TranslatorBag - { - $translatorBag = new TranslatorBag(); - $exportResponses = $downloadResponses = []; - - foreach ($locales as $locale) { - foreach ($domains as $domain) { - $response = $this->client->request('POST', 'projects/export', [ - 'body' => [ - 'language' => $locale, - 'type' => 'xlf', - 'filters' => json_encode(['translated']), - 'tags' => json_encode([$domain]), - ], - ]); - $exportResponses[] = [$response, $locale, $domain]; - } - } - - foreach ($exportResponses as [$response, $locale, $domain]) { - $responseContent = $response->toArray(false); - - if (200 !== $response->getStatusCode() || '200' !== (string) $responseContent['response']['code']) { - $this->logger->error('Unable to read the PoEditor response: '.$response->getContent(false)); - continue; - } - - $fileUrl = $responseContent['result']['url']; - $downloadResponses[] = [$this->client->request('GET', $fileUrl), $locale, $domain, $fileUrl]; - } - - foreach ($downloadResponses as [$response, $locale, $domain, $fileUrl]) { - $responseContent = $response->getContent(false); - - if (200 !== $response->getStatusCode()) { - $this->logger->error('Unable to download the PoEditor exported file: '.$responseContent); - continue; - } - - if (!$responseContent) { - $this->logger->error(sprintf('The exported file "%s" from PoEditor is empty.', $fileUrl)); - continue; - } - - $translatorBag->addCatalogue($this->loader->load($responseContent, $locale, $domain)); - } - - return $translatorBag; - } - - public function delete(TranslatorBagInterface $translatorBag): void - { - $deletedIds = $termsToDelete = []; - - foreach ($translatorBag->getCatalogues() as $catalogue) { - foreach ($catalogue->all() as $domain => $messages) { - foreach ($messages as $id => $message) { - if (\array_key_exists($domain, $deletedIds) && \in_array($id, $deletedIds[$domain], true)) { - continue; - } - - $deletedIds[$domain][] = $id; - $termsToDelete[] = [ - 'term' => $id, - 'context' => $domain, - ]; - } - } - } - - $this->deleteTerms($termsToDelete); - } - - private function addTerms(array $terms): void - { - $response = $this->client->request('POST', 'terms/add', [ - 'body' => [ - 'data' => json_encode($terms), - ], - ]); - - if (200 !== $response->getStatusCode() || '200' !== (string) $response->toArray(false)['response']['code']) { - throw new ProviderException(sprintf('Unable to add new translation keys to PoEditor: (status code: "%s") "%s".', $response->getStatusCode(), $response->getContent(false)), $response); - } - } - - private function addTranslations(array $translationsPerLocale): void - { - $responses = []; - - foreach ($translationsPerLocale as $locale => $translations) { - $responses = $this->client->request('POST', 'translations/add', [ - 'body' => [ - 'language' => $locale, - 'data' => json_encode($translations), - ], - ]); - } - - foreach ($responses as $response) { - if (200 !== $response->getStatusCode() || '200' !== (string) $response->toArray(false)['response']['code']) { - $this->logger->error(sprintf('Unable to add translation messages to PoEditor: "%s".', $response->getContent(false))); - } - } - } - - private function deleteTerms(array $ids): void - { - $response = $this->client->request('POST', 'terms/delete', [ - 'body' => [ - 'data' => json_encode($ids), - ], - ]); - - if (200 !== $response->getStatusCode() || '200' !== (string) $response->toArray(false)['response']['code']) { - throw new ProviderException(sprintf('Unable to delete translation keys on PoEditor: "%s".', $response->getContent(false)), $response); - } - } -} diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorProviderFactory.php b/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorProviderFactory.php deleted file mode 100644 index 07ea5ddfab3ed..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/PoEditorProviderFactory.php +++ /dev/null @@ -1,65 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Translation\Bridge\PoEditor; - -use Psr\Log\LoggerInterface; -use Symfony\Component\Translation\Exception\UnsupportedSchemeException; -use Symfony\Component\Translation\Loader\LoaderInterface; -use Symfony\Component\Translation\Provider\AbstractProviderFactory; -use Symfony\Component\Translation\Provider\Dsn; -use Symfony\Component\Translation\Provider\ProviderInterface; -use Symfony\Contracts\HttpClient\HttpClientInterface; - -/** - * @author Mathieu Santostefano - * - * @experimental in 5.3 - */ -final class PoEditorProviderFactory extends AbstractProviderFactory -{ - private const HOST = 'api.poeditor.com'; - - private $client; - private $logger; - private $defaultLocale; - private $loader; - - public function __construct(HttpClientInterface $client, LoggerInterface $logger, string $defaultLocale, LoaderInterface $loader) - { - $this->client = $client; - $this->logger = $logger; - $this->defaultLocale = $defaultLocale; - $this->loader = $loader; - } - - /** - * @return PoEditorProvider - */ - public function create(Dsn $dsn): ProviderInterface - { - if ('poeditor' !== $dsn->getScheme()) { - throw new UnsupportedSchemeException($dsn, 'poeditor', $this->getSupportedSchemes()); - } - - $endpoint = 'default' === $dsn->getHost() ? self::HOST : $dsn->getHost(); - $endpoint .= $dsn->getPort() ? ':'.$dsn->getPort() : ''; - - $client = PoEditorHttpClient::create($this->client, 'https://'.$endpoint.'/v2/', $this->getPassword($dsn), $this->getUser($dsn)); - - return new PoEditorProvider($client, $this->loader, $this->logger, $this->defaultLocale, $endpoint); - } - - protected function getSupportedSchemes(): array - { - return ['poeditor']; - } -} diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/README.md b/src/Symfony/Component/Translation/Bridge/PoEditor/README.md deleted file mode 100644 index 9622a5d4779d4..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/README.md +++ /dev/null @@ -1,28 +0,0 @@ -PoEditor Translation Provider -============================= - -Provides PoEditor integration for Symfony Translation. - -DSN example ------------ - -``` -// .env file -POEDITOR_DSN=poeditor://PROJECT_ID:API_KEY@default -``` - -where: - - `PROJECT_ID` is your PoEditor Project ID - - `API_KEY` is your PoEditor API key - -Go to the Project in PoEditor to find the Project ID in the url. - -[Generate an API key on PoEditor](https://poeditor.com/account/api) - -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/Translation/Bridge/PoEditor/Tests/PoEditorProviderFactoryTest.php b/src/Symfony/Component/Translation/Bridge/PoEditor/Tests/PoEditorProviderFactoryTest.php deleted file mode 100644 index b0e6b5f41f876..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/Tests/PoEditorProviderFactoryTest.php +++ /dev/null @@ -1,39 +0,0 @@ -getClient(), $this->getLogger(), $this->getDefaultLocale(), $this->getLoader()); - } -} diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/Tests/PoEditorProviderTest.php b/src/Symfony/Component/Translation/Bridge/PoEditor/Tests/PoEditorProviderTest.php deleted file mode 100644 index 708586c385a85..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/Tests/PoEditorProviderTest.php +++ /dev/null @@ -1,511 +0,0 @@ -getClient(), 'https://poeditor', 'API_KEY', 'PROJECT_ID'); - - yield [ - $this->createProvider($client, $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'api.poeditor.com'), - 'poeditor://api.poeditor.com', - ]; - - yield [ - $this->createProvider($client, $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com'), - 'poeditor://example.com', - ]; - - yield [ - $this->createProvider($client, $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com:99'), - 'poeditor://example.com:99', - ]; - } - - public function testCompleteWriteProcess() - { - $successResponse = new MockResponse(json_encode([ - 'response' => [ - 'status' => 'success', - 'code' => '200', - 'message' => 'OK', - ], - ])); - - $responses = [ - 'addTerms' => function (string $method, string $url, array $options = []) use ($successResponse): MockResponse { - $this->assertSame('POST', $method); - $this->assertSame(http_build_query([ - 'api_token' => 'API_KEY', - 'id' => 'PROJECT_ID', - 'data' => json_encode([ - [ - 'term' => 'a', - 'reference' => 'a', - 'tags' => ['messages'], - 'context' => 'messages', - ], - [ - 'term' => 'post.num_comments', - 'reference' => 'post.num_comments', - 'tags' => ['validators'], - 'context' => 'validators', - ], - ]), - ]), $options['body']); - - return $successResponse; - }, - 'addTranslationsEn' => function (string $method, string $url, array $options = []) use ($successResponse): MockResponse { - $this->assertSame('POST', $method); - $this->assertSame(http_build_query([ - 'api_token' => 'API_KEY', - 'id' => 'PROJECT_ID', - 'language' => 'en', - 'data' => json_encode([ - [ - 'term' => 'a', - 'context' => 'messages', - 'translation' => ['content' => 'trans_en_a'], - ], - [ - 'term' => 'post.num_comments', - 'context' => 'validators', - 'translation' => ['content' => '{count, plural, one {# comment} other {# comments}}'], - ], - ]), - ]), $options['body']); - - return $successResponse; - }, - 'addTranslationsFr' => function (string $method, string $url, array $options = []) use ($successResponse): MockResponse { - $this->assertSame('POST', $method); - $this->assertSame(http_build_query([ - 'api_token' => 'API_KEY', - 'id' => 'PROJECT_ID', - 'language' => 'fr', - 'data' => json_encode([ - [ - 'term' => 'a', - 'context' => 'messages', - 'translation' => ['content' => 'trans_fr_a'], - ], - [ - 'term' => 'post.num_comments', - 'context' => 'validators', - 'translation' => ['content' => '{count, plural, one {# commentaire} other {# commentaires}}'], - ], - ]), - ]), $options['body']); - - return $successResponse; - }, - ]; - - $translatorBag = new TranslatorBag(); - $translatorBag->addCatalogue(new MessageCatalogue('en', [ - 'messages' => ['a' => 'trans_en_a'], - 'validators' => ['post.num_comments' => '{count, plural, one {# comment} other {# comments}}'], - ])); - $translatorBag->addCatalogue(new MessageCatalogue('fr', [ - 'messages' => ['a' => 'trans_fr_a'], - 'validators' => ['post.num_comments' => '{count, plural, one {# commentaire} other {# commentaires}}'], - ])); - - $provider = $this->createProvider( - new MockHttpClient($responses, 'https://api.poeditor.com/v2/'), - $this->getLoader(), - $this->getLogger(), - $this->getDefaultLocale(), - 'api.poeditor.com' - ); - - $provider->write($translatorBag); - } - - /** - * @dataProvider getResponsesForOneLocaleAndOneDomain - */ - public function testReadForOneLocaleAndOneDomain(string $locale, string $domain, string $responseContent, TranslatorBag $expectedTranslatorBag) - { - $loader = $this->getLoader(); - $loader->expects($this->once()) - ->method('load') - ->willReturn((new XliffFileLoader())->load($responseContent, $locale, $domain)); - - $responses = [ - new MockResponse(json_encode([ - 'response' => [ - 'status' => 'success', - 'code' => '200', - 'message' => 'OK', - ], - 'result' => [ - 'url' => 'https://api.poeditor.com/v2/download/file/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - ], - ])), - new MockResponse($responseContent), - ]; - - $provider = $this->createProvider( - new MockHttpClient($responses, 'https://api.poeditor.com/v2/'), - $loader, - $this->getLogger(), - $this->getDefaultLocale(), - 'api.poeditor.com' - ); - - $translatorBag = $provider->read([$domain], [$locale]); - // We don't want to assert equality of metadata here, due to the ArrayLoader usage. - foreach ($translatorBag->getCatalogues() as $catalogue) { - $catalogue->deleteMetadata('', ''); - } - - $this->assertEquals($expectedTranslatorBag->getCatalogues(), $translatorBag->getCatalogues()); - } - - /** - * @dataProvider getResponsesForManyLocalesAndManyDomains - */ - public function testReadForManyLocalesAndManyDomains(array $locales, array $domains, array $responseContents, TranslatorBag $expectedTranslatorBag) - { - $exportResponses = $downloadResponses = []; - $consecutiveLoadArguments = []; - $consecutiveLoadReturns = []; - foreach ($locales as $locale) { - foreach ($domains as $domain) { - $exportResponses[] = new MockResponse(json_encode([ - 'response' => [ - 'status' => 'success', - 'code' => '200', - 'message' => 'OK', - ], - 'result' => [ - 'url' => 'https://api.poeditor.com/v2/download/file/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - ], - ])); - $downloadResponses[] = new MockResponse($responseContents[$locale][$domain]); - $consecutiveLoadArguments[] = [$responseContents[$locale][$domain], $locale, $domain]; - $consecutiveLoadReturns[] = (new XliffFileLoader())->load($responseContents[$locale][$domain], $locale, $domain); - } - } - - $loader = $this->getLoader(); - $loader->expects($this->exactly(\count($consecutiveLoadArguments))) - ->method('load') - ->withConsecutive(...$consecutiveLoadArguments) - ->willReturnOnConsecutiveCalls(...$consecutiveLoadReturns); - - $provider = $this->createProvider( - new MockHttpClient(array_merge($exportResponses, $downloadResponses), 'https://api.poeditor.com/v2/'), - $loader, - $this->getLogger(), - $this->getDefaultLocale(), - 'api.poeditor.com' - ); - - $translatorBag = $provider->read($domains, $locales); - // We don't want to assert equality of metadata here, due to the ArrayLoader usage. - foreach ($translatorBag->getCatalogues() as $catalogue) { - $catalogue->deleteMetadata('', ''); - } - - $this->assertEquals($expectedTranslatorBag->getCatalogues(), $translatorBag->getCatalogues()); - } - - public function testDeleteProcess() - { - $successResponse = new MockResponse(json_encode([ - 'response' => [ - 'status' => 'success', - 'code' => '200', - 'message' => 'OK', - ], - ])); - - $translatorBag = new TranslatorBag(); - $translatorBag->addCatalogue(new MessageCatalogue('en', [ - 'messages' => ['a' => 'trans_en_a'], - 'validators' => ['post.num_comments' => '{count, plural, one {# comment} other {# comments}}'], - ])); - $translatorBag->addCatalogue(new MessageCatalogue('fr', [ - 'messages' => ['a' => 'trans_fr_a'], - 'validators' => ['post.num_comments' => '{count, plural, one {# commentaire} other {# commentaires}}'], - ])); - - $provider = $this->createProvider( - new MockHttpClient(function (string $method, string $url, array $options = []) use ($successResponse): MockResponse { - $this->assertSame('POST', $method); - $this->assertSame(http_build_query([ - 'api_token' => 'API_KEY', - 'id' => 'PROJECT_ID', - 'data' => json_encode([ - [ - 'term' => 'a', - 'context' => 'messages', - ], - [ - 'term' => 'post.num_comments', - 'context' => 'validators', - ], - ]), - ]), $options['body']); - - return $successResponse; - }, 'https://api.poeditor.com/v2/'), - $this->getLoader(), - $this->getLogger(), - $this->getDefaultLocale(), - 'api.poeditor.com' - ); - - $provider->delete($translatorBag); - } - - public function getResponsesForOneLocaleAndOneDomain(): \Generator - { - $arrayLoader = new ArrayLoader(); - - $expectedTranslatorBagEn = new TranslatorBag(); - $expectedTranslatorBagEn->addCatalogue($arrayLoader->load([ - 'index.hello' => 'Hello', - 'index.greetings' => 'Welcome, {firstname}!', - ], 'en')); - - yield ['en', 'messages', <<<'XLIFF' - - - - - - index.hello - Hello - index.hello - - index.hello - - - - - index.greetings - Welcome, {firstname}! - index.greetings - - index.greetings - - - - - - -XLIFF - , - $expectedTranslatorBagEn, - ]; - - $expectedTranslatorBagFr = new TranslatorBag(); - $expectedTranslatorBagFr->addCatalogue($arrayLoader->load([ - 'index.hello' => 'Bonjour', - 'index.greetings' => 'Bienvenue, {firstname} !', - ], 'fr')); - - yield ['fr', 'messages', <<<'XLIFF' - - - - - - index.hello - Bonjour - index.hello - - index.hello - - - - - index.greetings - Bienvenue, {firstname} ! - index.greetings - - index.greetings - - - - - - -XLIFF - , - $expectedTranslatorBagFr, - ]; - } - - public function getResponsesForManyLocalesAndManyDomains(): \Generator - { - $arrayLoader = new ArrayLoader(); - - $expectedTranslatorBag = new TranslatorBag(); - $expectedTranslatorBag->addCatalogue($arrayLoader->load([ - 'index.hello' => 'Hello', - 'index.greetings' => 'Welcome, {firstname}!', - ], 'en')); - $expectedTranslatorBag->addCatalogue($arrayLoader->load([ - 'index.hello' => 'Bonjour', - 'index.greetings' => 'Bienvenue, {firstname} !', - ], 'fr')); - $expectedTranslatorBag->addCatalogue($arrayLoader->load([ - 'firstname.error' => 'Firstname must contains only letters.', - 'lastname.error' => 'Lastname must contains only letters.', - ], 'en', 'validators')); - $expectedTranslatorBag->addCatalogue($arrayLoader->load([ - 'firstname.error' => 'Le prénom ne peut contenir que des lettres.', - 'lastname.error' => 'Le nom de famille ne peut contenir que des lettres.', - ], 'fr', 'validators')); - - yield [ - ['en', 'fr'], - ['messages', 'validators'], - [ - 'en' => [ - 'messages' => <<<'XLIFF' - - - - - - index.hello - Hello - index.hello - - index.hello - - - - - index.greetings - Welcome, {firstname}! - index.greetings - - index.greetings - - - - - - -XLIFF - , - 'validators' => <<<'XLIFF' - - - - - - firstname.error - Firstname must contains only letters. - firstname.error - - firstname.error - - - - - lastname.error - Lastname must contains only letters. - lastname.error - - lastname.error - - - - - - -XLIFF - , - ], - 'fr' => [ - 'messages' => <<<'XLIFF' - - - - - - index.hello - Bonjour - index.hello - - index.hello - - - - - index.greetings - Bienvenue, {firstname} ! - index.greetings - - index.greetings - - - - - - -XLIFF - , - 'validators' => <<<'XLIFF' - - - - - - firstname.error - Le prénom ne peut contenir que des lettres. - firstname.error - - firstname.error - - - - - lastname.error - Le nom de famille ne peut contenir que des lettres. - lastname.error - - lastname.error - - - - - - -XLIFF - , - ], - ], - $expectedTranslatorBag, - ]; - } -} diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/composer.json b/src/Symfony/Component/Translation/Bridge/PoEditor/composer.json deleted file mode 100644 index 1ddc1d87cd8ef..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/composer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "symfony/po-editor-translation-provider", - "type": "symfony-bridge", - "description": "Symfony PoEditor Translation Provider Bridge", - "keywords": ["poeditor", "translation", "provider"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Mathieu Santostefano", - "homepage": "https://github.com/welcomattic" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=7.2.5", - "symfony/config": "^5.3", - "symfony/http-client": "^5.3", - "symfony/translation": "^5.3" - }, - "autoload": { - "psr-4": { "Symfony\\Component\\Translation\\Bridge\\PoEditor\\": "" }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "minimum-stability": "dev" -} diff --git a/src/Symfony/Component/Translation/Bridge/PoEditor/phpunit.xml.dist b/src/Symfony/Component/Translation/Bridge/PoEditor/phpunit.xml.dist deleted file mode 100644 index d23f853f5e8e6..0000000000000 --- a/src/Symfony/Component/Translation/Bridge/PoEditor/phpunit.xml.dist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - diff --git a/src/Symfony/Component/Translation/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Translation/Exception/UnsupportedSchemeException.php index b59ba81c09808..7fbaa8f04d08f 100644 --- a/src/Symfony/Component/Translation/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Translation/Exception/UnsupportedSchemeException.php @@ -29,10 +29,6 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Lokalise\LokaliseProviderFactory::class, 'package' => 'symfony/lokalise-translation-provider', ], - 'poeditor' => [ - 'class' => Bridge\PoEditor\PoEditorProviderFactory::class, - 'package' => 'symfony/po-editor-translation-provider', - ], ]; public function __construct(Dsn $dsn, string $name = null, array $supported = []) diff --git a/src/Symfony/Component/Translation/README.md b/src/Symfony/Component/Translation/README.md index dc090df5b3317..720bee3b81086 100644 --- a/src/Symfony/Component/Translation/README.md +++ b/src/Symfony/Component/Translation/README.md @@ -26,8 +26,8 @@ echo $translator->trans('Hello World!'); // outputs « Bonjour ! » Resources --------- - * [Documentation](https://symfony.com/doc/current/translation.html) - * [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) + * [Documentation](https://symfony.com/doc/current/translation.html) + * [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/Translation/Tests/Exception/UnsupportedSchemeExceptionTest.php b/src/Symfony/Component/Translation/Tests/Exception/UnsupportedSchemeExceptionTest.php index 99c1c89babffa..5fa018d8090a1 100644 --- a/src/Symfony/Component/Translation/Tests/Exception/UnsupportedSchemeExceptionTest.php +++ b/src/Symfony/Component/Translation/Tests/Exception/UnsupportedSchemeExceptionTest.php @@ -16,7 +16,6 @@ use Symfony\Component\Translation\Bridge\Crowdin\CrowdinProviderFactory; use Symfony\Component\Translation\Bridge\Loco\LocoProviderFactory; use Symfony\Component\Translation\Bridge\Lokalise\LokaliseProviderFactory; -use Symfony\Component\Translation\Bridge\PoEditor\PoEditorProviderFactory; use Symfony\Component\Translation\Exception\UnsupportedSchemeException; use Symfony\Component\Translation\Provider\Dsn; @@ -32,7 +31,6 @@ public static function setUpBeforeClass(): void CrowdinProviderFactory::class => false, LocoProviderFactory::class => false, LokaliseProviderFactory::class => false, - PoEditorProviderFactory::class => false, ]); } @@ -54,7 +52,6 @@ public function messageWhereSchemeIsPartOfSchemeToPackageMapProvider(): \Generat yield ['crowdin', 'symfony/crowdin-translation-provider']; yield ['loco', 'symfony/loco-translation-provider']; yield ['lokalise', 'symfony/lokalise-translation-provider']; - yield ['poeditor', 'symfony/po-editor-translation-provider']; } /** diff --git a/src/Symfony/Component/Uid/README.md b/src/Symfony/Component/Uid/README.md index 09b075584ad34..2ec5b761bc7b1 100644 --- a/src/Symfony/Component/Uid/README.md +++ b/src/Symfony/Component/Uid/README.md @@ -6,8 +6,8 @@ The UID component provides an object-oriented API to generate and represent UIDs Resources --------- - * [Documentation](https://symfony.com/doc/current/components/uid.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/uid.html) + * [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/Validator/README.md b/src/Symfony/Component/Validator/README.md index 410a4213eef07..8f3fd0efb2567 100644 --- a/src/Symfony/Component/Validator/README.md +++ b/src/Symfony/Component/Validator/README.md @@ -7,10 +7,10 @@ The Validator component provides tools to validate values following the Resources --------- - * [Documentation](https://symfony.com/doc/current/components/validator.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/validator.html) + * [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) [1]: https://jcp.org/en/jsr/detail?id=303 diff --git a/src/Symfony/Component/VarDumper/README.md b/src/Symfony/Component/VarDumper/README.md index 339f73eba3052..bdac24477a819 100644 --- a/src/Symfony/Component/VarDumper/README.md +++ b/src/Symfony/Component/VarDumper/README.md @@ -8,8 +8,8 @@ of `var_dump`. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html) + * [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/VarDumper/Tests/Caster/SplCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php index 24701be4119ef..ff308aaa0ccd2 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php @@ -50,12 +50,12 @@ public function getCastFileInfoTests() %A} EOTXT ], - ['https://example.com/about', <<<'EOTXT' + ['http://example.com/about', <<<'EOTXT' SplFileInfo { -%Apath: "https://example.com" +%Apath: "http://example.com" filename: "about" basename: "about" - pathname: "https://example.com/about" + pathname: "http://example.com/about" extension: "" realPath: false %A} diff --git a/src/Symfony/Component/VarDumper/VarDumper.php b/src/Symfony/Component/VarDumper/VarDumper.php index 470a24fe8d211..b223e065106d2 100644 --- a/src/Symfony/Component/VarDumper/VarDumper.php +++ b/src/Symfony/Component/VarDumper/VarDumper.php @@ -71,7 +71,7 @@ private static function register(): void $dumper = new CliDumper(); break; case 'server' === $format: - case 'tcp' === parse_url($format, \PHP_URL_SCHEME): + case $format && 'tcp' === parse_url($format, \PHP_URL_SCHEME): $host = 'server' === $format ? $_SERVER['VAR_DUMPER_SERVER'] ?? '127.0.0.1:9912' : $format; $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliDumper() : new HtmlDumper(); $dumper = new ServerDumper($host, $dumper, self::getDefaultContextProviders()); diff --git a/src/Symfony/Component/VarExporter/README.md b/src/Symfony/Component/VarExporter/README.md index bb13960e0d929..a34e4c23d725b 100644 --- a/src/Symfony/Component/VarExporter/README.md +++ b/src/Symfony/Component/VarExporter/README.md @@ -31,8 +31,8 @@ It also provides a few improvements over `var_export()`/`serialize()`: Resources --------- - * [Documentation](https://symfony.com/doc/current/components/var_exporter.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/var_exporter.html) + * [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/WebLink/README.md b/src/Symfony/Component/WebLink/README.md index 9daf39e8c1079..fe33a9c497f8e 100644 --- a/src/Symfony/Component/WebLink/README.md +++ b/src/Symfony/Component/WebLink/README.md @@ -35,8 +35,8 @@ echo 'Hello'; Resources --------- - * [Documentation](https://symfony.com/doc/current/web_link.html) - * [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) + * [Documentation](https://symfony.com/doc/current/web_link.html) + * [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/Workflow/README.md b/src/Symfony/Component/Workflow/README.md index b0f092eaf22a9..66fb6013a59ed 100644 --- a/src/Symfony/Component/Workflow/README.md +++ b/src/Symfony/Component/Workflow/README.md @@ -7,8 +7,8 @@ machine. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/workflow.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/workflow.html) + * [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/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 70f4c35c44a9e..3a6fe03e8dee6 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -692,17 +692,22 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar): return (float) str_replace('_', '', $scalar); case Parser::preg_match(self::getTimestampRegex(), $scalar): + // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. + $time = new \DateTime($scalar, new \DateTimeZone('UTC')); + if (Yaml::PARSE_DATETIME & $flags) { - // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. - return new \DateTime($scalar, new \DateTimeZone('UTC')); + return $time; } - $timeZone = date_default_timezone_get(); - date_default_timezone_set('UTC'); - $time = strtotime($scalar); - date_default_timezone_set($timeZone); + try { + if (false !== $scalar = $time->getTimestamp()) { + return $scalar; + } + } catch (\ValueError $e) { + // no-op + } - return $time; + return $time->format('U'); } } diff --git a/src/Symfony/Component/Yaml/README.md b/src/Symfony/Component/Yaml/README.md index b914e7836c7a5..ac25024b63438 100644 --- a/src/Symfony/Component/Yaml/README.md +++ b/src/Symfony/Component/Yaml/README.md @@ -6,8 +6,8 @@ The Yaml component loads and dumps YAML files. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/yaml.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/yaml.html) + * [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/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index e6e61981900e2..e839ae68ea904 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -326,7 +326,7 @@ public function getTestsForParse() ['2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)], ['2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)], ['1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)], - ['1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)], + ['1730-10-30T02:59:43Z', \PHP_INT_SIZE === 4 ? '-7547547617' : gmmktime(2, 59, 43, 10, 30, 1730)], ['"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''], ["'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''], @@ -397,7 +397,7 @@ public function getTestsForParseWithMapObjects() ['2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)], ['2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)], ['1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)], - ['1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)], + ['1730-10-30T02:59:43Z', \PHP_INT_SIZE === 4 ? '-7547547617' : gmmktime(2, 59, 43, 10, 30, 1730)], ['"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''], ["'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''], diff --git a/src/Symfony/Contracts/README.md b/src/Symfony/Contracts/README.md index 5beb497d7eab5..617a78f28ec74 100644 --- a/src/Symfony/Contracts/README.md +++ b/src/Symfony/Contracts/README.md @@ -47,8 +47,8 @@ the declared contracts will directly or indirectly contribute to the PHP-FIG. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/contracts.html) - * [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) + * [Documentation](https://symfony.com/doc/current/components/contracts.html) + * [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)