From f4b514a1d574b814b2e6259e26106b08752c69e2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 19 May 2021 15:18:37 +0200 Subject: [PATCH 01/79] Bump Symfony 6 to PHP 8 --- Cache/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 0f69892..81cac20 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/cache": "^1.0|^2.0|^3.0" }, "suggest": { diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 9f6dc41..3618127 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/event-dispatcher": "^1" }, "suggest": { diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 2633785..42646e6 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5" + "php": ">=8.0.2" }, "suggest": { "symfony/http-client-implementation": "" diff --git a/Service/composer.json b/Service/composer.json index ad4105c..549e12d 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/container": "^1.1" }, "conflict": { diff --git a/Translation/composer.json b/Translation/composer.json index 00e27f8..2f13cf4 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5" + "php": ">=8.0.2" }, "suggest": { "symfony/translation-implementation": "" diff --git a/composer.json b/composer.json index 7e011ac..d2ed108 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/cache": "^1.0|^2.0|^3.0", "psr/container": "^1.1", "psr/event-dispatcher": "^1.0" From c14702330d358f7cda49a24d1a84d513abde62c5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 2 Jun 2021 18:09:43 +0200 Subject: [PATCH 02/79] Update phpunit.xml.dist files for phpunit >= 9.3 --- phpunit.xml.dist | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index fd93d02..947db86 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ - - + + ./ - - ./Tests - ./Service/Test/ - ./Translation/Test/ - ./vendor - - - + + + ./Tests + ./Service/Test/ + ./Translation/Test/ + ./vendor + + From 6a39e56c1425a3552d36cd988708341a5ee5c5a1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Jun 2021 12:09:37 +0200 Subject: [PATCH 03/79] Bump Contracts to 2.5 --- Cache/ItemInterface.php | 2 +- Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/HttpClientInterface.php | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cache/ItemInterface.php b/Cache/ItemInterface.php index 10c0488..9795262 100644 --- a/Cache/ItemInterface.php +++ b/Cache/ItemInterface.php @@ -54,7 +54,7 @@ interface ItemInterface extends CacheItemInterface * @throws InvalidArgumentException When $tag is not valid * @throws CacheException When the item comes from a pool that is not tag-aware */ - public function tag($tags): self; + public function tag(string|iterable $tags): self; /** * Returns a list of metadata info that were saved alongside with the cached value. diff --git a/Cache/composer.json b/Cache/composer.json index 81cac20..f613e8a 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index 3884889..cc7cc12 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 3618127..8e2691f 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/HttpClientInterface.php b/HttpClient/HttpClientInterface.php index ea793ba..386b394 100644 --- a/HttpClient/HttpClientInterface.php +++ b/HttpClient/HttpClientInterface.php @@ -91,5 +91,5 @@ public function request(string $method, string $url, array $options = []): Respo * @param ResponseInterface|ResponseInterface[]|iterable $responses One or more responses created by the current HTTP client * @param float|null $timeout The idle timeout before yielding timeout chunks */ - public function stream($responses, float $timeout = null): ResponseStreamInterface; + public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface; } diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 42646e6..c6e3bc8 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/composer.json b/Service/composer.json index 549e12d..adcd6c9 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/composer.json b/Translation/composer.json index 2f13cf4..cc01431 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index d2ed108..5af1294 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" } } } From c1088c0d2932b9c4d0e3b60f14e8cc0839f2a391 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 12 Jul 2021 11:26:55 +0200 Subject: [PATCH 04/79] Add return types, round 1 --- Service/ServiceLocatorTrait.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index 74dfa43..2d21a27 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -50,10 +50,8 @@ public function has(string $id) /** * {@inheritdoc} - * - * @return mixed */ - public function get(string $id) + public function get(string $id): mixed { if (!isset($this->factories[$id])) { throw $this->createNotFoundException($id); From 48b558bdd110000c125646831a452429261a6f53 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 13 Jul 2021 13:47:05 +0200 Subject: [PATCH 05/79] [Contracts] add return types and bump to v3 --- Cache/CacheInterface.php | 2 +- Cache/CacheTrait.php | 6 ++---- Cache/CallbackInterface.php | 2 +- Cache/ItemInterface.php | 2 +- Cache/TagAwareCacheInterface.php | 2 +- Cache/composer.json | 4 ++-- Deprecation/composer.json | 4 ++-- EventDispatcher/composer.json | 2 +- HttpClient/ResponseInterface.php | 2 +- HttpClient/Test/TestHttpServer.php | 5 +---- HttpClient/composer.json | 2 +- Service/ServiceLocatorTrait.php | 4 +--- Service/ServiceSubscriberInterface.php | 2 +- Service/ServiceSubscriberTrait.php | 4 +--- Service/Test/ServiceLocatorTest.php | 5 +---- Service/composer.json | 4 ++-- Tests/Service/ServiceSubscriberTraitTest.php | 5 +---- Translation/LocaleAwareInterface.php | 6 +----- Translation/Test/TranslatorTest.php | 18 ++++++------------ Translation/TranslatorInterface.php | 2 +- Translation/TranslatorTrait.php | 4 +--- Translation/composer.json | 2 +- composer.json | 6 +++--- 23 files changed, 34 insertions(+), 61 deletions(-) diff --git a/Cache/CacheInterface.php b/Cache/CacheInterface.php index 4b1686b..419bc90 100644 --- a/Cache/CacheInterface.php +++ b/Cache/CacheInterface.php @@ -42,7 +42,7 @@ interface CacheInterface * * @throws InvalidArgumentException When $key is not valid or when $beta is negative */ - public function get(string $key, callable $callback, float $beta = null, array &$metadata = null); + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed; /** * Removes an item from the pool. diff --git a/Cache/CacheTrait.php b/Cache/CacheTrait.php index d340e06..d245df6 100644 --- a/Cache/CacheTrait.php +++ b/Cache/CacheTrait.php @@ -27,10 +27,8 @@ trait CacheTrait { /** * {@inheritdoc} - * - * @return mixed */ - public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed { return $this->doGet($this, $key, $callback, $beta, $metadata); } @@ -43,7 +41,7 @@ public function delete(string $key): bool return $this->deleteItem($key); } - private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null) + private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null): mixed { if (0 > $beta = $beta ?? 1.0) { throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { }; diff --git a/Cache/CallbackInterface.php b/Cache/CallbackInterface.php index 7dae2aa..437a3c9 100644 --- a/Cache/CallbackInterface.php +++ b/Cache/CallbackInterface.php @@ -26,5 +26,5 @@ interface CallbackInterface * * @return mixed The computed value for the passed item */ - public function __invoke(CacheItemInterface $item, bool &$save); + public function __invoke(CacheItemInterface $item, bool &$save): mixed; } diff --git a/Cache/ItemInterface.php b/Cache/ItemInterface.php index 9795262..8c4c512 100644 --- a/Cache/ItemInterface.php +++ b/Cache/ItemInterface.php @@ -54,7 +54,7 @@ interface ItemInterface extends CacheItemInterface * @throws InvalidArgumentException When $tag is not valid * @throws CacheException When the item comes from a pool that is not tag-aware */ - public function tag(string|iterable $tags): self; + public function tag(string|iterable $tags): static; /** * Returns a list of metadata info that were saved alongside with the cached value. diff --git a/Cache/TagAwareCacheInterface.php b/Cache/TagAwareCacheInterface.php index 7c4cf11..8e0b6be 100644 --- a/Cache/TagAwareCacheInterface.php +++ b/Cache/TagAwareCacheInterface.php @@ -34,5 +34,5 @@ interface TagAwareCacheInterface extends CacheInterface * * @throws InvalidArgumentException When $tags is not valid */ - public function invalidateTags(array $tags); + public function invalidateTags(array $tags): bool; } diff --git a/Cache/composer.json b/Cache/composer.json index f613e8a..1523e06 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "psr/cache": "^1.0|^2.0|^3.0" + "psr/cache": "^3.0" }, "suggest": { "symfony/cache-implementation": "" @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index cc7cc12..1c1b4ba 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=8.0.2" }, "autoload": { "files": [ @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 8e2691f..b4c3933 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/ResponseInterface.php b/HttpClient/ResponseInterface.php index df71488..62d0f8f 100644 --- a/HttpClient/ResponseInterface.php +++ b/HttpClient/ResponseInterface.php @@ -105,5 +105,5 @@ public function cancel(): void; * @return mixed An array of all available info, or one of them when $type is * provided, or null when an unsupported type is requested */ - public function getInfo(string $type = null); + public function getInfo(string $type = null): mixed; } diff --git a/HttpClient/Test/TestHttpServer.php b/HttpClient/Test/TestHttpServer.php index 55a744a..086d907 100644 --- a/HttpClient/Test/TestHttpServer.php +++ b/HttpClient/Test/TestHttpServer.php @@ -18,10 +18,7 @@ class TestHttpServer { private static $process = []; - /** - * @return Process - */ - public static function start(int $port = 8057) + public static function start(int $port = 8057): Process { if (isset(self::$process[$port])) { self::$process[$port]->stop(); diff --git a/HttpClient/composer.json b/HttpClient/composer.json index c6e3bc8..a26300f 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index 2d21a27..4a3558e 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -40,10 +40,8 @@ public function __construct(array $factories) /** * {@inheritdoc} - * - * @return bool */ - public function has(string $id) + public function has(string $id): bool { return isset($this->factories[$id]); } diff --git a/Service/ServiceSubscriberInterface.php b/Service/ServiceSubscriberInterface.php index 098ab90..881ab97 100644 --- a/Service/ServiceSubscriberInterface.php +++ b/Service/ServiceSubscriberInterface.php @@ -49,5 +49,5 @@ interface ServiceSubscriberInterface * * @return string[] The required service types, optionally keyed by service names */ - public static function getSubscribedServices(); + public static function getSubscribedServices(): array; } diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index cba0729..2e542ba 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -52,10 +52,8 @@ public static function getSubscribedServices(): array /** * @required - * - * @return ContainerInterface|null */ - public function setContainer(ContainerInterface $container) + public function setContainer(ContainerInterface $container): ?ContainerInterface { $this->container = $container; diff --git a/Service/Test/ServiceLocatorTest.php b/Service/Test/ServiceLocatorTest.php index 2a1b565..88f6a06 100644 --- a/Service/Test/ServiceLocatorTest.php +++ b/Service/Test/ServiceLocatorTest.php @@ -17,10 +17,7 @@ abstract class ServiceLocatorTest extends TestCase { - /** - * @return ContainerInterface - */ - protected function getServiceLocator(array $factories) + protected function getServiceLocator(array $factories): ContainerInterface { return new class($factories) implements ContainerInterface { use ServiceLocatorTrait; diff --git a/Service/composer.json b/Service/composer.json index adcd6c9..d3b047f 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "psr/container": "^1.1" + "psr/container": "^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 09453d8..2f85611 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -42,10 +42,7 @@ public function aParentService(): Service1 { } - /** - * @return ?ContainerInterface - */ - public function setContainer(ContainerInterface $container) + public function setContainer(ContainerInterface $container): ?ContainerInterface { return $container; } diff --git a/Translation/LocaleAwareInterface.php b/Translation/LocaleAwareInterface.php index 922ec1d..6923b97 100644 --- a/Translation/LocaleAwareInterface.php +++ b/Translation/LocaleAwareInterface.php @@ -16,16 +16,12 @@ interface LocaleAwareInterface /** * Sets the current locale. * - * @param string $locale The locale - * * @throws \InvalidArgumentException If the locale contains invalid characters */ public function setLocale(string $locale); /** * Returns the current locale. - * - * @return string The locale */ - public function getLocale(); + public function getLocale(): string; } diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 8903676..c2c30a9 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -43,10 +43,7 @@ protected function tearDown(): void \Locale::setDefault($this->defaultLocale); } - /** - * @return TranslatorInterface - */ - public function getTranslator() + public function getTranslator(): TranslatorInterface { return new class() implements TranslatorInterface { use TranslatorTrait; @@ -317,10 +314,8 @@ public function testLangcodes($nplural, $langCodes) * This array should contain all currently known langcodes. * * As it is impossible to have this ever complete we should try as hard as possible to have it almost complete. - * - * @return array */ - public function successLangcodes() + public function successLangcodes(): array { return [ ['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']], @@ -339,7 +334,7 @@ public function successLangcodes() * * @return array with nplural together with langcodes */ - public function failingLangcodes() + public function failingLangcodes(): array { return [ ['1', ['fa']], @@ -353,11 +348,10 @@ public function failingLangcodes() /** * We validate only on the plural coverage. Thus the real rules is not tested. * - * @param string $nplural Plural expected - * @param array $matrix Containing langcodes and their plural index values - * @param bool $expectSuccess + * @param string $nplural Plural expected + * @param array $matrix Containing langcodes and their plural index values */ - protected function validateMatrix($nplural, $matrix, $expectSuccess = true) + protected function validateMatrix(string $nplural, array $matrix, bool $expectSuccess = true) { foreach ($matrix as $langCode => $data) { $indexes = array_flip($data); diff --git a/Translation/TranslatorInterface.php b/Translation/TranslatorInterface.php index dc9bf7f..220ccf3 100644 --- a/Translation/TranslatorInterface.php +++ b/Translation/TranslatorInterface.php @@ -63,5 +63,5 @@ interface TranslatorInterface * * @throws \InvalidArgumentException If the locale contains invalid characters */ - public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null); + public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string; } diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 405ce8d..da1317b 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -32,10 +32,8 @@ public function setLocale(string $locale) /** * {@inheritdoc} - * - * @return string */ - public function getLocale() + public function getLocale(): string { return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en'); } diff --git a/Translation/composer.json b/Translation/composer.json index cc01431..875242f 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index 5af1294..c520738 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,8 @@ ], "require": { "php": ">=8.0.2", - "psr/cache": "^1.0|^2.0|^3.0", - "psr/container": "^1.1", + "psr/cache": "^3.0", + "psr/container": "^2.0", "psr/event-dispatcher": "^1.0" }, "require-dev": { @@ -52,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" } } } From 2897a0863a412b95a64101aa425fcf2bbdcdff92 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 15 Jul 2021 03:28:59 +0200 Subject: [PATCH 06/79] [Contracts] Add types to private properties Signed-off-by: Alexander M. Turek --- EventDispatcher/Event.php | 2 +- Service/ServiceLocatorTrait.php | 8 ++++---- Translation/TranslatorTrait.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/EventDispatcher/Event.php b/EventDispatcher/Event.php index 46dcb2b..384a650 100644 --- a/EventDispatcher/Event.php +++ b/EventDispatcher/Event.php @@ -30,7 +30,7 @@ */ class Event implements StoppableEventInterface { - private $propagationStopped = false; + private bool $propagationStopped = false; /** * {@inheritdoc} diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index 4a3558e..19d3e80 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -26,9 +26,9 @@ class_exists(NotFoundExceptionInterface::class); */ trait ServiceLocatorTrait { - private $factories; - private $loading = []; - private $providedTypes; + private array $factories; + private array $loading = []; + private array $providedTypes; /** * @param callable[] $factories @@ -76,7 +76,7 @@ public function get(string $id): mixed */ public function getProvidedServices(): array { - if (null === $this->providedTypes) { + if (!isset($this->providedTypes)) { $this->providedTypes = []; foreach ($this->factories as $name => $factory) { diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index da1317b..9c264bd 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -20,7 +20,7 @@ */ trait TranslatorTrait { - private $locale; + private ?string $locale = null; /** * {@inheritdoc} From 87fd917b22354ce0986421e80da3c5f55eef268f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Sep 2021 14:27:46 +0200 Subject: [PATCH 07/79] Turn `@method` annotations into real method declarations --- HttpClient/HttpClientInterface.php | 7 +++++-- Translation/TranslatorInterface.php | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/HttpClient/HttpClientInterface.php b/HttpClient/HttpClientInterface.php index 386b394..5ad0880 100644 --- a/HttpClient/HttpClientInterface.php +++ b/HttpClient/HttpClientInterface.php @@ -19,8 +19,6 @@ * * @see HttpClientTestCase for a reference test suite * - * @method static withOptions(array $options) Returns a new instance of the client with new default options - * * @author Nicolas Grekas */ interface HttpClientInterface @@ -92,4 +90,9 @@ public function request(string $method, string $url, array $options = []): Respo * @param float|null $timeout The idle timeout before yielding timeout chunks */ public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface; + + /** + * Returns a new instance of the client with new default options. + */ + public function withOptions(array $options): static; } diff --git a/Translation/TranslatorInterface.php b/Translation/TranslatorInterface.php index a691f5f..018db07 100644 --- a/Translation/TranslatorInterface.php +++ b/Translation/TranslatorInterface.php @@ -13,8 +13,6 @@ /** * @author Fabien Potencier - * - * @method string getLocale() Returns the default locale */ interface TranslatorInterface { @@ -62,4 +60,9 @@ interface TranslatorInterface * @throws \InvalidArgumentException If the locale contains invalid characters */ public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string; + + /** + * Returns the default locale. + */ + public function getLocale(): string; } From ff7d2af0bb9318c36c2fbe8476e862376cfa5e94 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Sep 2021 15:39:06 +0200 Subject: [PATCH 08/79] Remove deprecated code paths --- HttpClient/Test/HttpClientTestCase.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index da21de4..2bcffcd 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -1074,10 +1074,6 @@ public function testMaxDuration() public function testWithOptions() { $client = $this->getHttpClient(__FUNCTION__); - if (!method_exists($client, 'withOptions')) { - $this->markTestSkipped(sprintf('Not implementing "%s::withOptions()" is deprecated.', get_debug_type($client))); - } - $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); $this->assertNotSame($client, $client2); From 15e4e2ce63d9cca2e16606fc2ab232b541cd3b2b Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 27 Oct 2021 10:01:09 -0400 Subject: [PATCH 09/79] [DependencyInjection] remove ServiceSubscriberTrait deprecation layer --- Service/ServiceSubscriberTrait.php | 64 ++++++-------------- Tests/Service/ServiceSubscriberTraitTest.php | 29 --------- 2 files changed, 17 insertions(+), 76 deletions(-) diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index 46404db..f7db036 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -37,61 +37,31 @@ public static function getSubscribedServices(): array } $services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : []; - $attributeOptIn = false; - if (\PHP_VERSION_ID >= 80000) { - foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { - if (self::class !== $method->getDeclaringClass()->name) { - continue; - } - - if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { - continue; - } - - if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); - } - - if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); - } - - $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - - if ($returnType->allowsNull()) { - $serviceId = '?'.$serviceId; - } - - $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; - $attributeOptIn = true; + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; } - } - - if (!$attributeOptIn) { - foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { - if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - continue; - } - if (self::class !== $method->getDeclaringClass()->name) { - continue; - } + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } - if (!$returnType = $method->getReturnType()) { - continue; - } + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } - if ($returnType->isBuiltin()) { - continue; - } + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } - if (\PHP_VERSION_ID >= 80000) { - trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class); - } + $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); + if ($returnType->allowsNull()) { + $serviceId = '?'.$serviceId; } + + $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; } return $services; diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index d6a5b41..9ab7594 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -22,19 +22,6 @@ class ServiceSubscriberTraitTest extends TestCase { - /** - * @group legacy - */ - public function testLegacyMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices() - { - $expected = [LegacyTestService::class.'::aService' => '?'.Service2::class]; - - $this->assertEquals($expected, LegacyChildTestService::getSubscribedServices()); - } - - /** - * @requires PHP 8 - */ public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices() { $expected = [ @@ -67,22 +54,6 @@ public function setContainer(ContainerInterface $container) } } -class LegacyTestService extends ParentTestService implements ServiceSubscriberInterface -{ - use ServiceSubscriberTrait; - - public function aService(): Service2 - { - } -} - -class LegacyChildTestService extends LegacyTestService -{ - public function aChildService(): Service3 - { - } -} - class TestService extends ParentTestService implements ServiceSubscriberInterface { use ServiceSubscriberTrait; From dd4fb2a6785e99c8facaaca2810083acfb6c9ac4 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 2 Nov 2021 00:48:49 +0100 Subject: [PATCH 10/79] [Contracts] Add mixed type Signed-off-by: Alexander M. Turek --- Deprecation/function.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Deprecation/function.php b/Deprecation/function.php index d437150..2d56512 100644 --- a/Deprecation/function.php +++ b/Deprecation/function.php @@ -20,7 +20,7 @@ * * @author Nicolas Grekas */ - function trigger_deprecation(string $package, string $version, string $message, ...$args): void + function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void { @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); } From 5765493274e37538dcbf2caa80c25ad898779e6f Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 4 Nov 2021 18:15:53 +0100 Subject: [PATCH 11/79] Remove PHP 7 compat Signed-off-by: Alexander M. Turek --- Tests/Service/ServiceSubscriberTraitTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 09dc0be..1001218 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -42,9 +42,6 @@ public function testSetContainerIsCalledOnParent() $this->assertSame($container, (new TestService())->setContainer($container)); } - /** - * @requires PHP 8 - */ public function testMethodsWithUnionReturnTypesAreIgnored() { $expected = [TestServiceSubscriberUnion::class.'::method1' => '?Symfony\Contracts\Tests\Fixtures\Service1']; From f01c7beb28654ab38f08966ab5ddec076adb847f Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 4 Nov 2021 13:53:12 -0400 Subject: [PATCH 12/79] [DependencyInjection] remove deprecation layer --- Service/ServiceSubscriberTrait.php | 26 ------------------- Tests/Fixtures/TestServiceSubscriberUnion.php | 25 ------------------ Tests/Service/ServiceSubscriberTraitTest.php | 11 -------- 3 files changed, 62 deletions(-) delete mode 100644 Tests/Fixtures/TestServiceSubscriberUnion.php diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index 3e1d534..f7db036 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -36,7 +36,6 @@ public static function getSubscribedServices(): array return $services; } - $attributeOptIn = false; $services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : []; foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { @@ -63,31 +62,6 @@ public static function getSubscribedServices(): array } $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; - $attributeOptIn = true; - } - - if (!$attributeOptIn) { - foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { - if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - continue; - } - - if (self::class !== $method->getDeclaringClass()->name) { - continue; - } - - if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) { - continue; - } - - if ($returnType->isBuiltin()) { - continue; - } - - trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class); - - $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); - } } return $services; diff --git a/Tests/Fixtures/TestServiceSubscriberUnion.php b/Tests/Fixtures/TestServiceSubscriberUnion.php deleted file mode 100644 index 6bd8bbd..0000000 --- a/Tests/Fixtures/TestServiceSubscriberUnion.php +++ /dev/null @@ -1,25 +0,0 @@ -container->get(__METHOD__); - } - - private function method2(): Service1|Service2 - { - return $this->container->get(__METHOD__); - } - - private function method3(): Service1|Service2|null - { - return $this->container->get(__METHOD__); - } -} diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 35adbdb..9ab7594 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -19,7 +19,6 @@ use Symfony\Contracts\Service\ServiceLocatorTrait; use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberTrait; -use Symfony\Contracts\Tests\Fixtures\TestServiceSubscriberUnion; class ServiceSubscriberTraitTest extends TestCase { @@ -41,16 +40,6 @@ public function testSetContainerIsCalledOnParent() $this->assertSame($container, (new TestService())->setContainer($container)); } - - /** - * @group legacy - */ - public function testMethodsWithUnionReturnTypesAreIgnored() - { - $expected = [TestServiceSubscriberUnion::class.'::method1' => '?Symfony\Contracts\Tests\Fixtures\Service1']; - - $this->assertEquals($expected, TestServiceSubscriberUnion::getSubscribedServices()); - } } class ParentTestService From 1309f21c0ac2268f3a2e83e7c4d7ec94afbb0603 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 22 Nov 2021 16:19:30 +0100 Subject: [PATCH 13/79] [Contracts] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75d1729..5c9c3d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +3.0 +--- + + * Bump to PHP 8 minimum + * Add native return types + * Remove deprecated features + 2.5 --- From c494a32d4a4ffbc3349f95fcf84aaeceb3742dfe Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 29 Nov 2021 19:10:03 +0100 Subject: [PATCH 14/79] [Contracts] update branch-alias --- Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 1523e06..55769fe 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index 1c1b4ba..e85ed6f 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index b4c3933..436bb5a 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/composer.json b/HttpClient/composer.json index a26300f..5cea336 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/composer.json b/Service/composer.json index d3b047f..fd940fd 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/composer.json b/Translation/composer.json index 875242f..579dcd7 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index c520738..ac7fe73 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" } } } From c9d73180f0ba741e57eb15862bc43de507213a26 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Dec 2021 14:13:04 +0100 Subject: [PATCH 15/79] Leverage str_starts_with(), str_ends_with() and str_contains() --- HttpClient/Test/Fixtures/web/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient/Test/Fixtures/web/index.php b/HttpClient/Test/Fixtures/web/index.php index 30a7049..2c7af6d 100644 --- a/HttpClient/Test/Fixtures/web/index.php +++ b/HttpClient/Test/Fixtures/web/index.php @@ -15,7 +15,7 @@ foreach ($_SERVER as $k => $v) { switch ($k) { default: - if (0 !== strpos($k, 'HTTP_')) { + if (!str_starts_with($k, 'HTTP_')) { continue 2; } // no break From 6f5c1523b3a0ca3ccc512bacfc1e8ef1d1694fae Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 16 Dec 2021 11:11:51 +0100 Subject: [PATCH 16/79] Add more nullsafe operators --- Cache/CacheTrait.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache/CacheTrait.php b/Cache/CacheTrait.php index d245df6..9ac5a6d 100644 --- a/Cache/CacheTrait.php +++ b/Cache/CacheTrait.php @@ -43,7 +43,7 @@ public function delete(string $key): bool private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null): mixed { - if (0 > $beta = $beta ?? 1.0) { + if (0 > $beta ??= 1.0) { throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { }; } @@ -58,7 +58,7 @@ private function doGet(CacheItemPoolInterface $pool, string $key, callable $call if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, \PHP_INT_MAX) / \PHP_INT_MAX)) { // force applying defaultLifetime to expiry $item->expiresAt(null); - $logger && $logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ + $logger?->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ 'key' => $key, 'delta' => sprintf('%.1f', $expiry - $now), ]); From b436e3aa2d7557f2e3f1841f715714b5c57ef76c Mon Sep 17 00:00:00 2001 From: Alexander Menshchikov Date: Thu, 10 Feb 2022 00:11:02 +0300 Subject: [PATCH 17/79] [Contracts] EventDispatcherInterface phpdocs improvement for static analyze --- EventDispatcher/EventDispatcherInterface.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EventDispatcher/EventDispatcherInterface.php b/EventDispatcher/EventDispatcherInterface.php index 351dc51..610d6ac 100644 --- a/EventDispatcher/EventDispatcherInterface.php +++ b/EventDispatcher/EventDispatcherInterface.php @@ -21,11 +21,13 @@ interface EventDispatcherInterface extends PsrEventDispatcherInterface /** * Dispatches an event to all registered listeners. * - * @param object $event The event to pass to the event handlers/listeners + * @template T of object + * + * @param T $event The event to pass to the event handlers/listeners * @param string|null $eventName The name of the event to dispatch. If not supplied, * the class of $event should be used instead. * - * @return object The passed $event MUST be returned + * @return T The passed $event MUST be returned */ public function dispatch(object $event, string $eventName = null): object; } From 01a30f2a5d8aff8f43ee424884c93bb88e3c0e8e Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Tue, 15 Feb 2022 16:42:18 +0100 Subject: [PATCH 18/79] Leverage the match expression --- Translation/TranslatorTrait.php | 203 ++++++++++++++------------------ 1 file changed, 87 insertions(+), 116 deletions(-) diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 9c264bd..99a639c 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -140,121 +140,92 @@ private function getPluralizationRule(float $number, string $locale): int { $number = abs($number); - switch ('pt_BR' !== $locale && 'en_US_POSIX' !== $locale && \strlen($locale) > 3 ? substr($locale, 0, strrpos($locale, '_')) : $locale) { - case 'af': - case 'bn': - case 'bg': - case 'ca': - case 'da': - case 'de': - case 'el': - case 'en': - case 'en_US_POSIX': - case 'eo': - case 'es': - case 'et': - case 'eu': - case 'fa': - case 'fi': - case 'fo': - case 'fur': - case 'fy': - case 'gl': - case 'gu': - case 'ha': - case 'he': - case 'hu': - case 'is': - case 'it': - case 'ku': - case 'lb': - case 'ml': - case 'mn': - case 'mr': - case 'nah': - case 'nb': - case 'ne': - case 'nl': - case 'nn': - case 'no': - case 'oc': - case 'om': - case 'or': - case 'pa': - case 'pap': - case 'ps': - case 'pt': - case 'so': - case 'sq': - case 'sv': - case 'sw': - case 'ta': - case 'te': - case 'tk': - case 'ur': - case 'zu': - return (1 == $number) ? 0 : 1; - - case 'am': - case 'bh': - case 'fil': - case 'fr': - case 'gun': - case 'hi': - case 'hy': - case 'ln': - case 'mg': - case 'nso': - case 'pt_BR': - case 'ti': - case 'wa': - return ($number < 2) ? 0 : 1; - - case 'be': - case 'bs': - case 'hr': - case 'ru': - case 'sh': - case 'sr': - case 'uk': - return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - - case 'cs': - case 'sk': - return (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); - - case 'ga': - return (1 == $number) ? 0 : ((2 == $number) ? 1 : 2); - - case 'lt': - return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - - case 'sl': - return (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3)); - - case 'mk': - return (1 == $number % 10) ? 0 : 1; - - case 'mt': - return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); - - case 'lv': - return (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2); - - case 'pl': - return (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); - - case 'cy': - return (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3)); - - case 'ro': - return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); - - case 'ar': - return (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))); - - default: - return 0; - } + return match ('pt_BR' !== $locale && 'en_US_POSIX' !== $locale && \strlen($locale) > 3 ? substr($locale, 0, strrpos($locale, '_')) : $locale) { + 'af', + 'bn', + 'bg', + 'ca', + 'da', + 'de', + 'el', + 'en', + 'en_US_POSIX', + 'eo', + 'es', + 'et', + 'eu', + 'fa', + 'fi', + 'fo', + 'fur', + 'fy', + 'gl', + 'gu', + 'ha', + 'he', + 'hu', + 'is', + 'it', + 'ku', + 'lb', + 'ml', + 'mn', + 'mr', + 'nah', + 'nb', + 'ne', + 'nl', + 'nn', + 'no', + 'oc', + 'om', + 'or', + 'pa', + 'pap', + 'ps', + 'pt', + 'so', + 'sq', + 'sv', + 'sw', + 'ta', + 'te', + 'tk', + 'ur', + 'zu' => (1 == $number) ? 0 : 1, + 'am', + 'bh', + 'fil', + 'fr', + 'gun', + 'hi', + 'hy', + 'ln', + 'mg', + 'nso', + 'pt_BR', + 'ti', + 'wa' => ($number < 2) ? 0 : 1, + 'be', + 'bs', + 'hr', + 'ru', + 'sh', + 'sr', + 'uk' => ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2), + 'cs', + 'sk' => (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2), + 'ga' => (1 == $number) ? 0 : ((2 == $number) ? 1 : 2), + 'lt' => ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2), + 'sl' => (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3)), + 'mk' => (1 == $number % 10) ? 0 : 1, + 'mt' => (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)), + 'lv' => (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2), + 'pl' => (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2), + 'cy' => (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3)), + 'ro' => (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2), + 'ar' => (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))), + default => 0, + }; } } From d90a334898ef6a8c6ecb718f8e3674118856d9c6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Feb 2022 15:00:38 +0100 Subject: [PATCH 19/79] Bump minimum version of PHP to 8.1 --- Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 55769fe..2582e5a 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/cache": "^3.0" }, "suggest": { diff --git a/Deprecation/composer.json b/Deprecation/composer.json index e85ed6f..f5de4eb 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "autoload": { "files": [ diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 436bb5a..03ce8e4 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/event-dispatcher": "^1" }, "suggest": { diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 5cea336..4e877e5 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "suggest": { "symfony/http-client-implementation": "" diff --git a/Service/composer.json b/Service/composer.json index fd940fd..a4ff086 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/container": "^2.0" }, "conflict": { diff --git a/Translation/composer.json b/Translation/composer.json index 579dcd7..d078be8 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "suggest": { "symfony/translation-implementation": "" diff --git a/composer.json b/composer.json index ac7fe73..cba12a3 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/cache": "^3.0", "psr/container": "^2.0", "psr/event-dispatcher": "^1.0" From 8582682ae71fe89915076984be8dbc663def3326 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 8 Mar 2022 15:34:43 -0500 Subject: [PATCH 20/79] [DI] add `#[Required]` where applicable --- Service/ServiceSubscriberTrait.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index f7db036..8a6a424 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -12,6 +12,7 @@ namespace Symfony\Contracts\Service; use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; use Symfony\Contracts\Service\Attribute\SubscribedService; /** @@ -67,9 +68,7 @@ public static function getSubscribedServices(): array return $services; } - /** - * @required - */ + #[Required] public function setContainer(ContainerInterface $container): ?ContainerInterface { $this->container = $container; From 4095463562ce6efd9fa565d1fa089dbf25008b42 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 31 Mar 2022 18:23:12 +0200 Subject: [PATCH 21/79] Leverage non-capturing catches --- HttpClient/Test/HttpClientTestCase.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index 6a042d5..18d851f 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -226,13 +226,13 @@ public function testClientError() try { $response->getHeaders(); $this->fail(ClientExceptionInterface::class.' expected'); - } catch (ClientExceptionInterface $e) { + } catch (ClientExceptionInterface) { } try { $response->getContent(); $this->fail(ClientExceptionInterface::class.' expected'); - } catch (ClientExceptionInterface $e) { + } catch (ClientExceptionInterface) { } $this->assertSame(404, $response->getStatusCode()); @@ -246,7 +246,7 @@ public function testClientError() $this->assertTrue($chunk->isFirst()); } $this->fail(ClientExceptionInterface::class.' expected'); - } catch (ClientExceptionInterface $e) { + } catch (ClientExceptionInterface) { } } @@ -266,14 +266,14 @@ public function testDnsError() try { $response->getStatusCode(); $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } try { $response->getStatusCode(); $this->fail(TransportExceptionInterface::class.' still expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } @@ -283,7 +283,7 @@ public function testDnsError() foreach ($client->stream($response) as $r => $chunk) { } $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } @@ -432,7 +432,7 @@ public function testMaxRedirects() try { $response->getHeaders(); $this->fail(RedirectionExceptionInterface::class.' expected'); - } catch (RedirectionExceptionInterface $e) { + } catch (RedirectionExceptionInterface) { } $this->assertSame(302, $response->getStatusCode()); @@ -854,7 +854,7 @@ public function testTimeoutOnInitialize() try { $response->getContent(); $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { } } $responses = []; @@ -887,7 +887,7 @@ public function testTimeoutOnDestruct() try { unset($response); $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { } } @@ -1105,7 +1105,7 @@ public function testMaxDuration() try { $response->getContent(); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } From 39ee25e02d5eb56164d36650c7734f89067ae73c Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Thu, 21 Apr 2022 12:29:03 +0200 Subject: [PATCH 22/79] [HttpClient][Translation][Workflow] [Service] Exclude tests from classmaps --- HttpClient/composer.json | 5 ++++- Service/composer.json | 5 ++++- Translation/composer.json | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 4e877e5..0a99ad5 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -22,7 +22,10 @@ "symfony/http-client-implementation": "" }, "autoload": { - "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" } + "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" }, + "exclude-from-classmap": [ + "/Test/" + ] }, "minimum-stability": "dev", "extra": { diff --git a/Service/composer.json b/Service/composer.json index a4ff086..e7e4a64 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -26,7 +26,10 @@ "symfony/service-implementation": "" }, "autoload": { - "psr-4": { "Symfony\\Contracts\\Service\\": "" } + "psr-4": { "Symfony\\Contracts\\Service\\": "" }, + "exclude-from-classmap": [ + "/Test/" + ] }, "minimum-stability": "dev", "extra": { diff --git a/Translation/composer.json b/Translation/composer.json index d078be8..5240ed0 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -22,7 +22,10 @@ "symfony/translation-implementation": "" }, "autoload": { - "psr-4": { "Symfony\\Contracts\\Translation\\": "" } + "psr-4": { "Symfony\\Contracts\\Translation\\": "" }, + "exclude-from-classmap": [ + "/Test/" + ] }, "minimum-stability": "dev", "extra": { From a4a823e4e2ed8e49c29d08e42a0e797a4306585e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 5 May 2022 16:46:11 +0200 Subject: [PATCH 23/79] [Contracts/Service] Add generics to ServiceProviderInterface --- Service/ServiceProviderInterface.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Service/ServiceProviderInterface.php b/Service/ServiceProviderInterface.php index c60ad0b..e78827c 100644 --- a/Service/ServiceProviderInterface.php +++ b/Service/ServiceProviderInterface.php @@ -18,9 +18,23 @@ * * @author Nicolas Grekas * @author Mateusz Sip + * + * @template T of mixed */ interface ServiceProviderInterface extends ContainerInterface { + /** + * {@inheritdoc} + * + * @return T + */ + public function get(string $id): mixed; + + /** + * {@inheritdoc} + */ + public function has(string $id): bool; + /** * Returns an associative array of service types keyed by the identifiers provided by the current container. * From 9a6064f4c1c5adc88644db6979ea2d0ec0c305e5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 20 May 2022 15:56:22 +0200 Subject: [PATCH 24/79] Update branch alias for contracts --- Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 2582e5a..27b2c84 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index f5de4eb..be6c494 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 03ce8e4..eecac79 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 0a99ad5..d4176cc 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/composer.json b/Service/composer.json index e7e4a64..af3559e 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/composer.json b/Translation/composer.json index 5240ed0..15e4bc1 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index cba12a3..63bba36 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" } } } From c3a8721e2ebccf706d83337b07048f394a5c8ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Wed, 27 Jul 2022 15:32:56 +0200 Subject: [PATCH 25/79] Remove .gitignore file from dist package --- .gitattributes | 4 ++++ Cache/.gitattributes | 2 ++ Deprecation/.gitattributes | 2 ++ EventDispatcher/.gitattributes | 2 ++ HttpClient/.gitattributes | 2 ++ Service/.gitattributes | 2 ++ Translation/.gitattributes | 2 ++ 7 files changed, 16 insertions(+) create mode 100644 .gitattributes create mode 100644 Cache/.gitattributes create mode 100644 Deprecation/.gitattributes create mode 100644 EventDispatcher/.gitattributes create mode 100644 HttpClient/.gitattributes create mode 100644 Service/.gitattributes create mode 100644 Translation/.gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..84c7add --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/Cache/.gitattributes b/Cache/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/Cache/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/Deprecation/.gitattributes b/Deprecation/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/Deprecation/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/EventDispatcher/.gitattributes b/EventDispatcher/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/EventDispatcher/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/HttpClient/.gitattributes b/HttpClient/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/HttpClient/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/Service/.gitattributes b/Service/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/Service/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/Translation/.gitattributes b/Translation/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/Translation/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore From bc536ec1d52337b03cd170def6c09fe12545a519 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 28 Jul 2022 12:33:29 -0400 Subject: [PATCH 26/79] [DependencyInjection] Allow service subscribers to return `SubscribedService[]` --- CHANGELOG.md | 5 +++++ Service/Attribute/SubscribedService.php | 20 +++++++++++++++++--- Service/ServiceSubscriberInterface.php | 13 +++++++++++-- Service/ServiceSubscriberTrait.php | 16 ++++++++++------ Tests/Service/ServiceSubscriberTraitTest.php | 7 +++++++ 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c9c3d0..d8dd368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.2 +--- + + * Allow `ServiceSubscriberInterface::getSubscribedServices()` to return `SubscribedService[]` + 3.0 --- diff --git a/Service/Attribute/SubscribedService.php b/Service/Attribute/SubscribedService.php index 10d1bc3..d98e1df 100644 --- a/Service/Attribute/SubscribedService.php +++ b/Service/Attribute/SubscribedService.php @@ -11,9 +11,14 @@ namespace Symfony\Contracts\Service\Attribute; +use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberTrait; /** + * For use as the return value for {@see ServiceSubscriberInterface}. + * + * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) + * * Use with {@see ServiceSubscriberTrait} to mark a method's return type * as a subscribed service. * @@ -22,12 +27,21 @@ #[\Attribute(\Attribute::TARGET_METHOD)] final class SubscribedService { + /** @var object[] */ + public array $attributes; + /** - * @param string|null $key The key to use for the service - * If null, use "ClassName::methodName" + * @param string|null $key The key to use for the service + * @param class-string|null $type The service class + * @param bool $nullable Whether the service is optional + * @param object|object[] $attributes One or more dependency injection attributes to use */ public function __construct( - public ?string $key = null + public ?string $key = null, + public ?string $type = null, + public bool $nullable = false, + array|object $attributes = [], ) { + $this->attributes = \is_array($attributes) ? $attributes : [$attributes]; } } diff --git a/Service/ServiceSubscriberInterface.php b/Service/ServiceSubscriberInterface.php index 881ab97..3da1916 100644 --- a/Service/ServiceSubscriberInterface.php +++ b/Service/ServiceSubscriberInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Contracts\Service; +use Symfony\Contracts\Service\Attribute\SubscribedService; + /** * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. * @@ -29,7 +31,8 @@ interface ServiceSubscriberInterface { /** - * Returns an array of service types required by such instances, optionally keyed by the service names used internally. + * Returns an array of service types (or {@see SubscribedService} objects) required + * by such instances, optionally keyed by the service names used internally. * * For mandatory dependencies: * @@ -47,7 +50,13 @@ interface ServiceSubscriberInterface * * ['?Psr\Log\LoggerInterface'] is a shortcut for * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] * - * @return string[] The required service types, optionally keyed by service names + * additionally, an array of {@see SubscribedService}'s can be returned: + * + * * [new SubscribedService('logger', Psr\Log\LoggerInterface::class)] + * * [new SubscribedService(type: Psr\Log\LoggerInterface::class, nullable: true)] + * * [new SubscribedService('http_client', HttpClientInterface::class, attributes: new Target('githubApi'))] + * + * @return string[]|SubscribedService[] The required service types, optionally keyed by service names */ public static function getSubscribedServices(): array; } diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index e8c9b17..5301298 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -50,13 +50,17 @@ public static function getSubscribedServices(): array throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } - $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - - if ($returnType->allowsNull()) { - $serviceId = '?'.$serviceId; + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key ??= self::class.'::'.$method->name; + $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + $attribute->nullable = $returnType->allowsNull(); + + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type; } - - $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; } return $services; diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 296e946..a4b2ecc 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -15,6 +15,7 @@ use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Component1\Dir1\Service1; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Component1\Dir2\Service2; +use Symfony\Contracts\Service\Attribute\Required; use Symfony\Contracts\Service\Attribute\SubscribedService; use Symfony\Contracts\Service\ServiceLocatorTrait; use Symfony\Contracts\Service\ServiceSubscriberInterface; @@ -27,6 +28,7 @@ public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices $expected = [ TestService::class.'::aService' => Service2::class, TestService::class.'::nullableService' => '?'.Service2::class, + new SubscribedService(TestService::class.'::withAttribute', Service2::class, true, new Required()), ]; $this->assertEquals($expected, ChildTestService::getSubscribedServices()); @@ -93,6 +95,11 @@ public function aService(): Service2 public function nullableService(): ?Service2 { } + + #[SubscribedService(attributes: new Required())] + public function withAttribute(): ?Service2 + { + } } class ChildTestService extends TestService From 1be20ae9c8c42f8d4e0dbb935774392fccf4945a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 25 Aug 2022 16:59:21 +0200 Subject: [PATCH 27/79] [CS] Remove @inheritdoc PHPDoc --- Cache/CacheTrait.php | 6 ------ EventDispatcher/Event.php | 3 --- Service/ServiceLocatorTrait.php | 9 --------- Service/ServiceProviderInterface.php | 5 ----- Service/ServiceSubscriberTrait.php | 3 --- Translation/TranslatorTrait.php | 9 --------- 6 files changed, 35 deletions(-) diff --git a/Cache/CacheTrait.php b/Cache/CacheTrait.php index 9ac5a6d..b4fddfa 100644 --- a/Cache/CacheTrait.php +++ b/Cache/CacheTrait.php @@ -25,17 +25,11 @@ class_exists(InvalidArgumentException::class); */ trait CacheTrait { - /** - * {@inheritdoc} - */ public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed { return $this->doGet($this, $key, $callback, $beta, $metadata); } - /** - * {@inheritdoc} - */ public function delete(string $key): bool { return $this->deleteItem($key); diff --git a/EventDispatcher/Event.php b/EventDispatcher/Event.php index 384a650..2e7f998 100644 --- a/EventDispatcher/Event.php +++ b/EventDispatcher/Event.php @@ -32,9 +32,6 @@ class Event implements StoppableEventInterface { private bool $propagationStopped = false; - /** - * {@inheritdoc} - */ public function isPropagationStopped(): bool { return $this->propagationStopped; diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index 19d3e80..45c8d91 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -38,17 +38,11 @@ public function __construct(array $factories) $this->factories = $factories; } - /** - * {@inheritdoc} - */ public function has(string $id): bool { return isset($this->factories[$id]); } - /** - * {@inheritdoc} - */ public function get(string $id): mixed { if (!isset($this->factories[$id])) { @@ -71,9 +65,6 @@ public function get(string $id): mixed } } - /** - * {@inheritdoc} - */ public function getProvidedServices(): array { if (!isset($this->providedTypes)) { diff --git a/Service/ServiceProviderInterface.php b/Service/ServiceProviderInterface.php index e78827c..a28fd82 100644 --- a/Service/ServiceProviderInterface.php +++ b/Service/ServiceProviderInterface.php @@ -24,15 +24,10 @@ interface ServiceProviderInterface extends ContainerInterface { /** - * {@inheritdoc} - * * @return T */ public function get(string $id): mixed; - /** - * {@inheritdoc} - */ public function has(string $id): bool; /** diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index 5301298..f7cd3a9 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -26,9 +26,6 @@ trait ServiceSubscriberTrait /** @var ContainerInterface */ protected $container; - /** - * {@inheritdoc} - */ public static function getSubscribedServices(): array { $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 99a639c..46e9170 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -22,25 +22,16 @@ trait TranslatorTrait { private ?string $locale = null; - /** - * {@inheritdoc} - */ public function setLocale(string $locale) { $this->locale = $locale; } - /** - * {@inheritdoc} - */ public function getLocale(): string { return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en'); } - /** - * {@inheritdoc} - */ public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string { if (null === $id || '' === $id) { From 9f257272791806373ee9f03dee3d81477cea3d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Fri, 26 Aug 2022 16:19:22 +0200 Subject: [PATCH 28/79] Replace get_class() calls by ::class --- HttpClient/Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index 84df706..9489300 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -1125,7 +1125,7 @@ public function testWithOptions() $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); $this->assertNotSame($client, $client2); - $this->assertSame(\get_class($client), \get_class($client2)); + $this->assertSame($client::class, $client2::class); $response = $client2->request('GET', '/'); $this->assertSame(200, $response->getStatusCode()); From 10acfef1869af56730ed18c724e171d4f3db2423 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 2 Sep 2022 16:55:07 +0200 Subject: [PATCH 29/79] CS fixes --- Cache/CacheInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache/CacheInterface.php b/Cache/CacheInterface.php index 0840a8f..0d4f403 100644 --- a/Cache/CacheInterface.php +++ b/Cache/CacheInterface.php @@ -47,9 +47,9 @@ public function get(string $key, callable $callback, float $beta = null, array & * * @param string $key The key to delete * - * @throws InvalidArgumentException When $key is not valid - * * @return bool True if the item was successfully removed, false if there was any error + * + * @throws InvalidArgumentException When $key is not valid */ public function delete(string $key): bool; } From c47da22960a1eb5e39c1ad84120734e680265610 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 25 Nov 2022 11:21:52 +0100 Subject: [PATCH 30/79] [Contracts] update branch alias --- Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 27b2c84..770e20e 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index be6c494..774200f 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index eecac79..89d7cec 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/composer.json b/HttpClient/composer.json index d4176cc..61eac1e 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/composer.json b/Service/composer.json index af3559e..36b0d95 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/composer.json b/Translation/composer.json index 15e4bc1..3454800 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index 63bba36..031ad79 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" } } } From 8087e3e74e8e99361ba3577fc71ce749e4ae083b Mon Sep 17 00:00:00 2001 From: Adrien Roches Date: Wed, 18 Jan 2023 15:05:54 +0100 Subject: [PATCH 31/79] [DependencyInjection] Add missing template notation on ServiceLocator --- Service/ServiceProviderInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Service/ServiceProviderInterface.php b/Service/ServiceProviderInterface.php index a28fd82..c05e4bf 100644 --- a/Service/ServiceProviderInterface.php +++ b/Service/ServiceProviderInterface.php @@ -19,7 +19,7 @@ * @author Nicolas Grekas * @author Mateusz Sip * - * @template T of mixed + * @template-covariant T of mixed */ interface ServiceProviderInterface extends ContainerInterface { From 9c39bc6b0f4940d92b7c1609bcae51478396bee5 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 13 Feb 2023 00:00:11 +0100 Subject: [PATCH 32/79] Add missing PHPdoc return types --- Tests/Service/ServiceSubscriberTraitTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index a4b2ecc..06340a6 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -76,6 +76,9 @@ public function aParentService(): Service1 { } + /** + * @return ContainerInterface|null + */ public function setContainer(ContainerInterface $container) { return $container; From f0e74448dca6044a5f65bb3ccad1f18d9e13c12a Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 12 Feb 2023 23:57:18 +0100 Subject: [PATCH 33/79] Add void return types --- Translation/TranslatorTrait.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 46e9170..e3b0adf 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -22,6 +22,9 @@ trait TranslatorTrait { private ?string $locale = null; + /** + * @return void + */ public function setLocale(string $locale) { $this->locale = $locale; From 72030ac0173ac06510bcf16cc9444d70025d0244 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Feb 2023 09:53:37 +0100 Subject: [PATCH 34/79] Fix merge --- Translation/Test/TranslatorTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index c5c37b3..e4168cc 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -114,7 +114,7 @@ public function testGetLocaleReturnsDefaultLocaleIfNotSet() $this->assertEquals('en', $translator->getLocale()); } - public function getTransTests() + public static function getTransTests() { return [ ['Symfony is great!', 'Symfony is great!', []], @@ -122,7 +122,7 @@ public function getTransTests() ]; } - public function getTransChoiceTests() + public static function getTransChoiceTests() { return [ ['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0], @@ -146,7 +146,7 @@ public function testInterval($expected, $number, $interval) $this->assertEquals($expected, $translator->trans($interval.' foo|[1,Inf[ bar', ['%count%' => $number])); } - public function getInterval() + public static function getInterval() { return [ ['foo', 3, '{1,2, 3 ,4}'], @@ -189,7 +189,7 @@ public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number) $translator->trans($id, ['%count%' => $number]); } - public function getNonMatchingMessages() + public static function getNonMatchingMessages() { return [ ['{0} There are no apples|{1} There is one apple', 2], @@ -199,7 +199,7 @@ public function getNonMatchingMessages() ]; } - public function getChooseTests() + public static function getChooseTests() { return [ ['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0], @@ -315,7 +315,7 @@ public function testLangcodes($nplural, $langCodes) * * As it is impossible to have this ever complete we should try as hard as possible to have it almost complete. */ - public function successLangcodes(): array + public static function successLangcodes(): array { return [ ['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']], @@ -334,7 +334,7 @@ public function successLangcodes(): array * * @return array with nplural together with langcodes */ - public function failingLangcodes(): array + public static function failingLangcodes(): array { return [ ['1', ['fa']], From 82c00e67b15e950c088fc6e336a83b97509253bc Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 15 Feb 2023 00:58:54 +0100 Subject: [PATCH 35/79] Add missing return types to interfaces --- Tests/Service/ServiceSubscriberTraitTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 06340a6..e9c9087 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -76,10 +76,7 @@ public function aParentService(): Service1 { } - /** - * @return ContainerInterface|null - */ - public function setContainer(ContainerInterface $container) + public function setContainer(ContainerInterface $container): ?ContainerInterface { return $container; } From 949dfaa3a6531e45ae0f55e4ea298e417fed2d8c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 16 Feb 2023 11:55:45 +0100 Subject: [PATCH 36/79] [Contracts] Add missing return types --- Service/ResetInterface.php | 3 +++ Translation/LocaleAwareInterface.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Service/ResetInterface.php b/Service/ResetInterface.php index 1af1075..a4f389b 100644 --- a/Service/ResetInterface.php +++ b/Service/ResetInterface.php @@ -26,5 +26,8 @@ */ interface ResetInterface { + /** + * @return void + */ public function reset(); } diff --git a/Translation/LocaleAwareInterface.php b/Translation/LocaleAwareInterface.php index 6923b97..db40ba1 100644 --- a/Translation/LocaleAwareInterface.php +++ b/Translation/LocaleAwareInterface.php @@ -16,6 +16,8 @@ interface LocaleAwareInterface /** * Sets the current locale. * + * @return void + * * @throws \InvalidArgumentException If the locale contains invalid characters */ public function setLocale(string $locale); From c04bcf086c30aa0666c12b858dda01df0ef0f4a4 Mon Sep 17 00:00:00 2001 From: Jack Worman Date: Thu, 26 Jan 2023 12:56:19 -0500 Subject: [PATCH 37/79] Add cache contracts template annotations --- Cache/CacheInterface.php | 20 ++++++++++++-------- Cache/CallbackInterface.php | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Cache/CacheInterface.php b/Cache/CacheInterface.php index 0d4f403..a4fcea7 100644 --- a/Cache/CacheInterface.php +++ b/Cache/CacheInterface.php @@ -29,14 +29,18 @@ interface CacheInterface * requested key, that could be used e.g. for expiration control. It could also * be an ItemInterface instance when its additional features are needed. * - * @param string $key The key of the item to retrieve from the cache - * @param callable|CallbackInterface $callback Should return the computed value for the given key/item - * @param float|null $beta A float that, as it grows, controls the likeliness of triggering - * early expiration. 0 disables it, INF forces immediate expiration. - * The default (or providing null) is implementation dependent but should - * typically be 1.0, which should provide optimal stampede protection. - * See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration - * @param array &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()} + * @template T + * + * @param string $key The key of the item to retrieve from the cache + * @param (callable(CacheItemInterface,bool):T)|(callable(ItemInterface,bool):T)|CallbackInterface $callback + * @param float|null $beta A float that, as it grows, controls the likeliness of triggering + * early expiration. 0 disables it, INF forces immediate expiration. + * The default (or providing null) is implementation dependent but should + * typically be 1.0, which should provide optimal stampede protection. + * See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration + * @param array &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()} + * + * @return T * * @throws InvalidArgumentException When $key is not valid or when $beta is negative */ diff --git a/Cache/CallbackInterface.php b/Cache/CallbackInterface.php index 437a3c9..15941e9 100644 --- a/Cache/CallbackInterface.php +++ b/Cache/CallbackInterface.php @@ -17,6 +17,8 @@ * Computes and returns the cached value of an item. * * @author Nicolas Grekas + * + * @template T */ interface CallbackInterface { @@ -24,7 +26,7 @@ interface CallbackInterface * @param CacheItemInterface|ItemInterface $item The item to compute the value for * @param bool &$save Should be set to false when the value should not be saved in the pool * - * @return mixed The computed value for the passed item + * @return T The computed value for the passed item */ public function __invoke(CacheItemInterface $item, bool &$save): mixed; } From d77e0edd1d4b9465122a08e9e1efb468ba09ec95 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Mar 2023 11:25:45 +0100 Subject: [PATCH 38/79] Fix typo --- Deprecation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Deprecation/README.md b/Deprecation/README.md index 4957933..9814864 100644 --- a/Deprecation/README.md +++ b/Deprecation/README.md @@ -22,5 +22,5 @@ trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use This will generate the following message: `Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` -While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty +While not recommended, the deprecation notices can be completely ignored by declaring an empty `function trigger_deprecation() {}` in your application. From 8ec95320f72fd012bf6335498c8f6c8d64957346 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Mar 2023 11:32:47 +0100 Subject: [PATCH 39/79] Fix typo --- Cache/README.md | 2 +- EventDispatcher/README.md | 2 +- HttpClient/README.md | 2 +- Service/README.md | 2 +- Translation/README.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cache/README.md b/Cache/README.md index 7085a69..ffe0833 100644 --- a/Cache/README.md +++ b/Cache/README.md @@ -3,7 +3,7 @@ Symfony Cache Contracts A set of abstractions extracted out of the Symfony components. -Can be used to build on semantics that the Symfony components proved useful - and +Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/EventDispatcher/README.md b/EventDispatcher/README.md index b1ab4c0..332b961 100644 --- a/EventDispatcher/README.md +++ b/EventDispatcher/README.md @@ -3,7 +3,7 @@ Symfony EventDispatcher Contracts A set of abstractions extracted out of the Symfony components. -Can be used to build on semantics that the Symfony components proved useful - and +Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/HttpClient/README.md b/HttpClient/README.md index 03b3a69..24d72f5 100644 --- a/HttpClient/README.md +++ b/HttpClient/README.md @@ -3,7 +3,7 @@ Symfony HttpClient Contracts A set of abstractions extracted out of the Symfony components. -Can be used to build on semantics that the Symfony components proved useful - and +Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/Service/README.md b/Service/README.md index 41e054a..42841a5 100644 --- a/Service/README.md +++ b/Service/README.md @@ -3,7 +3,7 @@ Symfony Service Contracts A set of abstractions extracted out of the Symfony components. -Can be used to build on semantics that the Symfony components proved useful - and +Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/Translation/README.md b/Translation/README.md index 42e5c51..b211d58 100644 --- a/Translation/README.md +++ b/Translation/README.md @@ -3,7 +3,7 @@ Symfony Translation Contracts A set of abstractions extracted out of the Symfony components. -Can be used to build on semantics that the Symfony components proved useful - and +Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. From 25b5c433ff48f5ff425c22c473f19bc1e013ebc7 Mon Sep 17 00:00:00 2001 From: Artyum Petrov <17199757+artyuum@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:24:19 +0400 Subject: [PATCH 40/79] Add "composer require..." in all exception messages when needed --- Cache/composer.json | 3 --- EventDispatcher/composer.json | 3 --- HttpClient/composer.json | 3 --- Service/composer.json | 3 --- Translation/composer.json | 3 --- composer.json | 7 ------- 6 files changed, 22 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 770e20e..79a1d2d 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -19,9 +19,6 @@ "php": ">=8.1", "psr/cache": "^3.0" }, - "suggest": { - "symfony/cache-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\Cache\\": "" } }, diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 89d7cec..4b6a136 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -19,9 +19,6 @@ "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" } }, diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 61eac1e..0c2102f 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -18,9 +18,6 @@ "require": { "php": ">=8.1" }, - "suggest": { - "symfony/http-client-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" }, "exclude-from-classmap": [ diff --git a/Service/composer.json b/Service/composer.json index 36b0d95..a2530e9 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -22,9 +22,6 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" }, "exclude-from-classmap": [ diff --git a/Translation/composer.json b/Translation/composer.json index 3454800..49e6dc7 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -18,9 +18,6 @@ "require": { "php": ">=8.1" }, - "suggest": { - "symfony/translation-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\Translation\\": "" }, "exclude-from-classmap": [ diff --git a/composer.json b/composer.json index 031ad79..a165e44 100644 --- a/composer.json +++ b/composer.json @@ -35,13 +35,6 @@ "symfony/service-contracts": "self.version", "symfony/translation-contracts": "self.version" }, - "suggest": { - "symfony/cache-implementation": "", - "symfony/event-dispatcher-implementation": "", - "symfony/http-client-implementation": "", - "symfony/service-implementation": "", - "symfony/translation-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\": "" }, "files": [ "Deprecation/function.php" ], From d4e382f10430947b40280607e72eb37ab68e2523 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Thu, 27 Apr 2023 14:20:09 +0200 Subject: [PATCH 41/79] Fix test class name --- Service/Test/ServiceLocatorTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Service/Test/ServiceLocatorTestCase.php b/Service/Test/ServiceLocatorTestCase.php index 88f6a06..a0f20a6 100644 --- a/Service/Test/ServiceLocatorTestCase.php +++ b/Service/Test/ServiceLocatorTestCase.php @@ -15,7 +15,7 @@ use Psr\Container\ContainerInterface; use Symfony\Contracts\Service\ServiceLocatorTrait; -abstract class ServiceLocatorTest extends TestCase +abstract class ServiceLocatorTestCase extends TestCase { protected function getServiceLocator(array $factories): ContainerInterface { From 72e1b9fc27c6480063f3829edafa2dd7302ac0dc Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 9 May 2023 15:41:26 +0200 Subject: [PATCH 42/79] [HttpClient] Add option `crypto_method` to set the minimum TLS version and make it default to v1.2 --- CHANGELOG.md | 5 +++++ HttpClient/HttpClientInterface.php | 1 + 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8dd368..d944ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.3 +--- + + * Add option `crypto_method` to `HttpClientInterface` to define the minimum TLS version to accept + 3.2 --- diff --git a/HttpClient/HttpClientInterface.php b/HttpClient/HttpClientInterface.php index b148b19..5963625 100644 --- a/HttpClient/HttpClientInterface.php +++ b/HttpClient/HttpClientInterface.php @@ -66,6 +66,7 @@ interface HttpClientInterface 'ciphers' => null, 'peer_fingerprint' => null, 'capture_peer_cert_chain' => false, + 'crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, // STREAM_CRYPTO_METHOD_TLSv*_CLIENT - minimum TLS version 'extra' => [], // array - additional options that can be ignored if unsupported, unlike regular options ]; From 36bbef5a96aea43c1537bafc6094e79107c737fe Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 23 May 2023 16:45:45 +0200 Subject: [PATCH 43/79] Bump contracts to 3.4-dev --- Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cache/composer.json b/Cache/composer.json index 79a1d2d..f80d0b5 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index 774200f..c6d02d8 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 4b6a136..3618d53 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 0c2102f..084d490 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/composer.json b/Service/composer.json index a2530e9..a64188b 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/composer.json b/Translation/composer.json index 49e6dc7..213b5cd 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index a165e44..b04b9e6 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" } } } From 2dd3f6adc6e19f418f72be381581803e6d3008cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anderson=20M=C3=BCller?= Date: Thu, 15 Jun 2023 13:02:24 +0200 Subject: [PATCH 44/79] Improve return type of `getProvidedServices` in `ServiceProviderInterface` --- Service/ServiceProviderInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Service/ServiceProviderInterface.php b/Service/ServiceProviderInterface.php index c05e4bf..2e71f00 100644 --- a/Service/ServiceProviderInterface.php +++ b/Service/ServiceProviderInterface.php @@ -39,7 +39,7 @@ public function has(string $id): bool; * * ['foo' => '?'] means the container provides service name "foo" of unspecified type * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null * - * @return string[] The provided service types, keyed by service names + * @return array The provided service types, keyed by service names */ public function getProvidedServices(): array; } From 11492010cc3e80f8996725b3ea496dec6a4d94c2 Mon Sep 17 00:00:00 2001 From: "Roland Franssen :)" Date: Wed, 28 Jun 2023 18:56:50 +0200 Subject: [PATCH 45/79] [HttpClient] Allow custom working directory in TestHttpServer --- CHANGELOG.md | 5 +++++ HttpClient/Test/TestHttpServer.php | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d944ba1..4044866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.4 +--- + + * Allow custom working directory in `TestHttpServer` + 3.3 --- diff --git a/HttpClient/Test/TestHttpServer.php b/HttpClient/Test/TestHttpServer.php index 086d907..2ec4aa5 100644 --- a/HttpClient/Test/TestHttpServer.php +++ b/HttpClient/Test/TestHttpServer.php @@ -18,8 +18,13 @@ class TestHttpServer { private static $process = []; - public static function start(int $port = 8057): Process + /** + * @param string|null $workingDirectory + */ + public static function start(int $port = 8057/* , string $workingDirectory = null */): Process { + $workingDirectory = \func_get_args()[1] ?? __DIR__.'/Fixtures/web'; + if (isset(self::$process[$port])) { self::$process[$port]->stop(); } else { @@ -30,7 +35,7 @@ public static function start(int $port = 8057): Process $finder = new PhpExecutableFinder(); $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); - $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); + $process->setWorkingDirectory($workingDirectory); $process->start(); self::$process[$port] = $process; From 312bb1eb1506a3363ccd55d794bd3e810e3139b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anderson=20M=C3=BCller?= Date: Tue, 18 Jul 2023 11:21:39 +0200 Subject: [PATCH 46/79] Improve type of factories in `ServiceLocatorTrait` --- Service/ServiceLocatorTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index 45c8d91..b62ec3e 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -31,7 +31,7 @@ trait ServiceLocatorTrait private array $providedTypes; /** - * @param callable[] $factories + * @param array $factories */ public function __construct(array $factories) { From 8f121f37633a19d5dcdac81888e5eb8077a66ea9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 21 Jul 2023 18:41:43 +0200 Subject: [PATCH 47/79] Add types to private and internal properties --- HttpClient/Test/TestHttpServer.php | 2 +- Translation/Test/TranslatorTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HttpClient/Test/TestHttpServer.php b/HttpClient/Test/TestHttpServer.php index 2ec4aa5..86dfa7d 100644 --- a/HttpClient/Test/TestHttpServer.php +++ b/HttpClient/Test/TestHttpServer.php @@ -16,7 +16,7 @@ class TestHttpServer { - private static $process = []; + private static array $process = []; /** * @param string|null $workingDirectory diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 674b78b..18e6690 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -30,7 +30,7 @@ */ class TranslatorTest extends TestCase { - private $defaultLocale; + private string $defaultLocale; protected function setUp(): void { From 75c3ea9c14dbc9f70d5934784c8d54d4ef317e38 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 26 Jul 2023 17:12:55 +0200 Subject: [PATCH 48/79] More short closures + isset instead of null checks + etc. --- Tests/Service/ServiceSubscriberTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 3eb4b31..ba37026 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -146,7 +146,7 @@ class ParentTestService2 public function setContainer(ContainerInterface $container) { - $previous = $this->container; + $previous = $this->container ?? null; $this->container = $container; return $previous; From 4f58c3219dc017850c88468fccfa9e3db8f651ee Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 28 Jul 2023 15:17:19 +0200 Subject: [PATCH 49/79] More short closures --- HttpClient/Test/HttpClientTestCase.php | 2 +- Service/Test/ServiceLocatorTestCase.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index 9cfd33f..98838ef 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -135,7 +135,7 @@ public function testConditionalBuffering() $this->assertSame($firstContent, $secondContent); - $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () { return false; }]); + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => fn () => false]); $response->getContent(); $this->expectException(TransportExceptionInterface::class); diff --git a/Service/Test/ServiceLocatorTestCase.php b/Service/Test/ServiceLocatorTestCase.php index a0f20a6..583f72a 100644 --- a/Service/Test/ServiceLocatorTestCase.php +++ b/Service/Test/ServiceLocatorTestCase.php @@ -27,9 +27,9 @@ protected function getServiceLocator(array $factories): ContainerInterface public function testHas() { $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', + fn () => 'dummy', ]); $this->assertTrue($locator->has('foo')); @@ -40,8 +40,8 @@ function () { return 'dummy'; }, public function testGet() { $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', ]); $this->assertSame('bar', $locator->get('foo')); From 0182b1e69fc43f6fc8c6203b66ecc4085b14d487 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 25 Sep 2023 14:52:38 +0200 Subject: [PATCH 50/79] Minor CS fixes --- Cache/CacheTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cache/CacheTrait.php b/Cache/CacheTrait.php index b4fddfa..8a4b0bd 100644 --- a/Cache/CacheTrait.php +++ b/Cache/CacheTrait.php @@ -38,7 +38,7 @@ public function delete(string $key): bool private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null): mixed { if (0 > $beta ??= 1.0) { - throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { }; + throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException {}; } $item = $pool->getItem($key); From f59eb1feac6dcc21b5954f7ab3e7a902160de9d3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 2 Oct 2023 15:15:28 +0200 Subject: [PATCH 51/79] Add "dev" keyword to symfony/symfony package --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b04b9e6..e016cb8 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "symfony/contracts", "type": "library", "description": "A set of abstractions extracted out of the Symfony components", - "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards", "dev"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From bd6978fb5cb7e858e26bdaf9c7a261e7087570f8 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 19 Dec 2023 22:51:00 +0100 Subject: [PATCH 52/79] Allow psr/container 1.1 again --- Service/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Service/composer.json b/Service/composer.json index a64188b..32bb8a3 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" From db06a3f3c52adeb7a1e84745cece0a9c474f518a Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 1 Nov 2023 09:14:07 +0100 Subject: [PATCH 53/79] [Tests] Streamline --- Service/Test/ServiceLocatorTestCase.php | 16 ++++++++++------ Translation/Test/TranslatorTest.php | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Service/Test/ServiceLocatorTestCase.php b/Service/Test/ServiceLocatorTestCase.php index 583f72a..65a3fe3 100644 --- a/Service/Test/ServiceLocatorTestCase.php +++ b/Service/Test/ServiceLocatorTestCase.php @@ -12,7 +12,9 @@ namespace Symfony\Contracts\Service\Test; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Symfony\Contracts\Service\ServiceLocatorTrait; abstract class ServiceLocatorTestCase extends TestCase @@ -66,27 +68,29 @@ public function testGetDoesNotMemoize() public function testThrowsOnUndefinedInternalService() { - if (!$this->getExpectedException()) { - $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - } $locator = $this->getServiceLocator([ 'foo' => function () use (&$locator) { return $locator->get('bar'); }, ]); + if (!$this->getExpectedException()) { + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator->get('foo'); } public function testThrowsOnCircularReference() { - $this->expectException(\Psr\Container\ContainerExceptionInterface::class); - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); $locator = $this->getServiceLocator([ 'foo' => function () use (&$locator) { return $locator->get('bar'); }, 'bar' => function () use (&$locator) { return $locator->get('baz'); }, 'baz' => function () use (&$locator) { return $locator->get('bar'); }, ]); + $this->expectException(ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator->get('foo'); } } diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 18e6690..756228a 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -183,9 +183,10 @@ public function testReturnMessageIfExactlyOneStandardRuleIsGiven() */ public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number) { - $this->expectException(\InvalidArgumentException::class); $translator = $this->getTranslator(); + $this->expectException(\InvalidArgumentException::class); + $translator->trans($id, ['%count%' => $number]); } From 18ccc54507f9750ddffa7e607471885cb785b1e8 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 20 Dec 2023 13:09:40 -0500 Subject: [PATCH 54/79] [DependencyInjection] Add `ServiceCollectionInterface` --- CHANGELOG.md | 5 +++++ Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/composer.json | 2 +- Service/ServiceCollectionInterface.php | 26 ++++++++++++++++++++++++++ Service/composer.json | 2 +- Translation/composer.json | 2 +- composer.json | 2 +- 9 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 Service/ServiceCollectionInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4044866..02c9156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.5 +--- + + * Add `ServiceCollectionInterface` + 3.4 --- diff --git a/Cache/composer.json b/Cache/composer.json index f80d0b5..fe261d1 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index c6d02d8..ceb6c07 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 3618d53..35956eb 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/composer.json b/HttpClient/composer.json index 084d490..efb146e 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/ServiceCollectionInterface.php b/Service/ServiceCollectionInterface.php new file mode 100644 index 0000000..2333139 --- /dev/null +++ b/Service/ServiceCollectionInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceProviderInterface that is also countable and iterable. + * + * @author Kevin Bond + * + * @template-covariant T of mixed + * + * @extends ServiceProviderInterface + * @extends \IteratorAggregate + */ +interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate +{ +} diff --git a/Service/composer.json b/Service/composer.json index 32bb8a3..061561c 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/composer.json b/Translation/composer.json index 213b5cd..181651e 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index e016cb8..e43cff6 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" } } } From 1f3c96b9b6eeea05c51b1e1a288ebfdb4927e623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Pr=C3=A9vot?= Date: Tue, 9 Jan 2024 19:24:47 +0100 Subject: [PATCH 55/79] Allow psr/container 1.1 again This is a follow up from 80d34d0a809fab81809cb14b53fe89c22d54fa94. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e016cb8..b4be947 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=8.1", "psr/cache": "^3.0", - "psr/container": "^2.0", + "psr/container": "^1.1|^2.0", "psr/event-dispatcher": "^1.0" }, "require-dev": { From 5d4ea81748ef711275de44c7c6ea5d65a02025c8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 5 Apr 2024 11:11:55 +0200 Subject: [PATCH 56/79] [Contracts] Rename ServiceSubscriberTrait to ServiceMethodsSubscriberTrait --- CHANGELOG.md | 1 + Service/Attribute/SubscribedService.php | 4 +- Service/ServiceMethodsSubscriberTrait.php | 80 +++++++++ Service/ServiceSubscriberTrait.php | 16 +- Service/composer.json | 3 +- Tests/Service/LegacyTestService.php | 93 ++++++++++ .../ServiceMethodsSubscriberTraitTest.php | 170 ++++++++++++++++++ Tests/Service/ServiceSubscriberTraitTest.php | 100 ++--------- 8 files changed, 375 insertions(+), 92 deletions(-) create mode 100644 Service/ServiceMethodsSubscriberTrait.php create mode 100644 Tests/Service/LegacyTestService.php create mode 100644 Tests/Service/ServiceMethodsSubscriberTraitTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c9156..42fe6fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add `ServiceCollectionInterface` + * Deprecate `ServiceSubscriberTrait`, use `ServiceMethodsSubscriberTrait` instead 3.4 --- diff --git a/Service/Attribute/SubscribedService.php b/Service/Attribute/SubscribedService.php index d98e1df..f850b84 100644 --- a/Service/Attribute/SubscribedService.php +++ b/Service/Attribute/SubscribedService.php @@ -11,15 +11,15 @@ namespace Symfony\Contracts\Service\Attribute; +use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait; use Symfony\Contracts\Service\ServiceSubscriberInterface; -use Symfony\Contracts\Service\ServiceSubscriberTrait; /** * For use as the return value for {@see ServiceSubscriberInterface}. * * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) * - * Use with {@see ServiceSubscriberTrait} to mark a method's return type + * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type * as a subscribed service. * * @author Kevin Bond diff --git a/Service/ServiceMethodsSubscriberTrait.php b/Service/ServiceMethodsSubscriberTrait.php new file mode 100644 index 0000000..0d89d9f --- /dev/null +++ b/Service/ServiceMethodsSubscriberTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @author Kevin Bond + */ +trait ServiceMethodsSubscriberTrait +{ + protected ContainerInterface $container; + + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key ??= self::class.'::'.$method->name; + $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + $attribute->nullable = $returnType->allowsNull(); + + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type; + } + } + + return $services; + } + + #[Required] + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + $ret = null; + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + + $this->container = $container; + + return $ret; + } +} diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index f3b450c..cc3bc32 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -15,17 +15,23 @@ use Symfony\Contracts\Service\Attribute\Required; use Symfony\Contracts\Service\Attribute\SubscribedService; +trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class); + /** - * Implementation of ServiceSubscriberInterface that determines subscribed services from - * method return types. Service ids are available as "ClassName::methodName". + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @property ContainerInterface $container * * @author Kevin Bond + * + * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead */ trait ServiceSubscriberTrait { - /** @var ContainerInterface */ - protected $container; - public static function getSubscribedServices(): array { $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; diff --git a/Service/composer.json b/Service/composer.json index 061561c..fc8674a 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" diff --git a/Tests/Service/LegacyTestService.php b/Tests/Service/LegacyTestService.php new file mode 100644 index 0000000..9d55b9e --- /dev/null +++ b/Tests/Service/LegacyTestService.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Tests\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; +use Symfony\Contracts\Service\ServiceSubscriberInterface; +use Symfony\Contracts\Service\ServiceSubscriberTrait; + +class LegacyParentTestService +{ + public function aParentService(): Service1 + { + } + + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + return $container; + } +} + +class LegacyTestService extends LegacyParentTestService implements ServiceSubscriberInterface +{ + use ServiceSubscriberTrait; + + #[SubscribedService] + public function aService(): Service2 + { + return $this->container->get(__METHOD__); + } + + #[SubscribedService] + public function nullableService(): ?Service2 + { + return $this->container->get(__METHOD__); + } + + #[SubscribedService(attributes: new Required())] + public function withAttribute(): ?Service2 + { + return $this->container->get(__METHOD__); + } +} + +class LegacyChildTestService extends LegacyTestService +{ + #[SubscribedService()] + public function aChildService(): LegacyService3 + { + return $this->container->get(__METHOD__); + } +} + +class LegacyParentWithMagicCall +{ + public function __call($method, $args) + { + throw new \BadMethodCallException('Should not be called.'); + } + + public static function __callStatic($method, $args) + { + throw new \BadMethodCallException('Should not be called.'); + } +} + +class LegacyService3 +{ +} + +class LegacyParentTestService2 +{ + /** @var ContainerInterface */ + protected $container; + + public function setContainer(ContainerInterface $container) + { + $previous = $this->container ?? null; + $this->container = $container; + + return $previous; + } +} diff --git a/Tests/Service/ServiceMethodsSubscriberTraitTest.php b/Tests/Service/ServiceMethodsSubscriberTraitTest.php new file mode 100644 index 0000000..396ca7f --- /dev/null +++ b/Tests/Service/ServiceMethodsSubscriberTraitTest.php @@ -0,0 +1,170 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Tests\Service; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; +use Symfony\Contracts\Service\ServiceLocatorTrait; +use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait; +use Symfony\Contracts\Service\ServiceSubscriberInterface; + +class ServiceMethodsSubscriberTraitTest extends TestCase +{ + public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices() + { + $expected = [ + TestService::class.'::aService' => Service2::class, + TestService::class.'::nullableService' => '?'.Service2::class, + new SubscribedService(TestService::class.'::withAttribute', Service2::class, true, new Required()), + ]; + + $this->assertEquals($expected, ChildTestService::getSubscribedServices()); + } + + public function testSetContainerIsCalledOnParent() + { + $container = new class([]) implements ContainerInterface { + use ServiceLocatorTrait; + }; + + $this->assertSame($container, (new TestService())->setContainer($container)); + } + + public function testParentNotCalledIfHasMagicCall() + { + $container = new class([]) implements ContainerInterface { + use ServiceLocatorTrait; + }; + $service = new class() extends ParentWithMagicCall { + use ServiceMethodsSubscriberTrait; + }; + + $this->assertNull($service->setContainer($container)); + $this->assertSame([], $service::getSubscribedServices()); + } + + public function testParentNotCalledIfNoParent() + { + $container = new class([]) implements ContainerInterface { + use ServiceLocatorTrait; + }; + $service = new class() { + use ServiceMethodsSubscriberTrait; + }; + + $this->assertNull($service->setContainer($container)); + $this->assertSame([], $service::getSubscribedServices()); + } + + public function testSetContainerCalledFirstOnParent() + { + $container1 = new class([]) implements ContainerInterface { + use ServiceLocatorTrait; + }; + $container2 = clone $container1; + + $testService = new TestService2(); + $this->assertNull($testService->setContainer($container1)); + $this->assertSame($container1, $testService->setContainer($container2)); + } +} + +class ParentTestService +{ + public function aParentService(): Service1 + { + } + + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + return $container; + } +} + +class TestService extends ParentTestService implements ServiceSubscriberInterface +{ + use ServiceMethodsSubscriberTrait; + + protected ContainerInterface $container; + + #[SubscribedService] + public function aService(): Service2 + { + return $this->container->get(__METHOD__); + } + + #[SubscribedService] + public function nullableService(): ?Service2 + { + return $this->container->get(__METHOD__); + } + + #[SubscribedService(attributes: new Required())] + public function withAttribute(): ?Service2 + { + return $this->container->get(__METHOD__); + } +} + +class ChildTestService extends TestService +{ + #[SubscribedService] + public function aChildService(): Service3 + { + return $this->container->get(__METHOD__); + } +} + +class ParentWithMagicCall +{ + public function __call($method, $args) + { + throw new \BadMethodCallException('Should not be called.'); + } + + public static function __callStatic($method, $args) + { + throw new \BadMethodCallException('Should not be called.'); + } +} + +class Service1 +{ +} + +class Service2 +{ +} + +class Service3 +{ +} + +class ParentTestService2 +{ + protected ContainerInterface $container; + + public function setContainer(ContainerInterface $container) + { + $previous = $this->container ?? null; + $this->container = $container; + + return $previous; + } +} + +class TestService2 extends ParentTestService2 implements ServiceSubscriberInterface +{ + use ServiceMethodsSubscriberTrait; +} diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index ba37026..184d92d 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -13,25 +13,31 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Component1\Dir1\Service1; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Component1\Dir2\Service2; use Symfony\Contracts\Service\Attribute\Required; use Symfony\Contracts\Service\Attribute\SubscribedService; use Symfony\Contracts\Service\ServiceLocatorTrait; use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberTrait; +/** + * @group legacy + */ class ServiceSubscriberTraitTest extends TestCase { + public static function setUpBeforeClass(): void + { + class_exists(LegacyTestService::class); + } + public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices() { $expected = [ - TestService::class.'::aService' => Service2::class, - TestService::class.'::nullableService' => '?'.Service2::class, - new SubscribedService(TestService::class.'::withAttribute', Service2::class, true, new Required()), + LegacyTestService::class.'::aService' => Service2::class, + LegacyTestService::class.'::nullableService' => '?'.Service2::class, + new SubscribedService(LegacyTestService::class.'::withAttribute', Service2::class, true, new Required()), ]; - $this->assertEquals($expected, ChildTestService::getSubscribedServices()); + $this->assertEquals($expected, LegacyChildTestService::getSubscribedServices()); } public function testSetContainerIsCalledOnParent() @@ -40,7 +46,7 @@ public function testSetContainerIsCalledOnParent() use ServiceLocatorTrait; }; - $this->assertSame($container, (new TestService())->setContainer($container)); + $this->assertSame($container, (new LegacyTestService())->setContainer($container)); } public function testParentNotCalledIfHasMagicCall() @@ -76,84 +82,10 @@ public function testSetContainerCalledFirstOnParent() }; $container2 = clone $container1; - $testService = new TestService2(); + $testService = new class() extends LegacyParentTestService2 implements ServiceSubscriberInterface { + use ServiceSubscriberTrait; + }; $this->assertNull($testService->setContainer($container1)); $this->assertSame($container1, $testService->setContainer($container2)); } } - -class ParentTestService -{ - public function aParentService(): Service1 - { - } - - public function setContainer(ContainerInterface $container): ?ContainerInterface - { - return $container; - } -} - -class TestService extends ParentTestService implements ServiceSubscriberInterface -{ - use ServiceSubscriberTrait; - - #[SubscribedService] - public function aService(): Service2 - { - } - - #[SubscribedService] - public function nullableService(): ?Service2 - { - } - - #[SubscribedService(attributes: new Required())] - public function withAttribute(): ?Service2 - { - } -} - -class ChildTestService extends TestService -{ - #[SubscribedService] - public function aChildService(): Service3 - { - } -} - -class ParentWithMagicCall -{ - public function __call($method, $args) - { - throw new \BadMethodCallException('Should not be called.'); - } - - public static function __callStatic($method, $args) - { - throw new \BadMethodCallException('Should not be called.'); - } -} - -class Service3 -{ -} - -class ParentTestService2 -{ - /** @var ContainerInterface */ - protected $container; - - public function setContainer(ContainerInterface $container) - { - $previous = $this->container ?? null; - $this->container = $container; - - return $previous; - } -} - -class TestService2 extends ParentTestService2 implements ServiceSubscriberInterface -{ - use ServiceSubscriberTrait; -} From 6d8fc879230ec0cfd71ff04c86d0fb1238383f76 Mon Sep 17 00:00:00 2001 From: sam-bee <130986804+sam-bee@users.noreply.github.com> Date: Mon, 13 May 2024 12:43:33 +0100 Subject: [PATCH 57/79] Because PHP 8.4 is adding deprecation warnings for non-nullable parameters with null default, change typehints --- HttpClient/Test/TestHttpServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient/Test/TestHttpServer.php b/HttpClient/Test/TestHttpServer.php index 2a27847..35bfd45 100644 --- a/HttpClient/Test/TestHttpServer.php +++ b/HttpClient/Test/TestHttpServer.php @@ -21,7 +21,7 @@ class TestHttpServer /** * @param string|null $workingDirectory */ - public static function start(int $port = 8057/* , string $workingDirectory = null */): Process + public static function start(int $port = 8057/* , ?string $workingDirectory = null */): Process { $workingDirectory = \func_get_args()[1] ?? __DIR__.'/Fixtures/web'; From 94397e0cfd8b116fcd4e9c9b7c1a8a5d01585aa7 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 24 May 2024 11:59:23 +0200 Subject: [PATCH 58/79] use constructor property promotion --- Service/ServiceLocatorTrait.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index b62ec3e..a4f2873 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -26,16 +26,15 @@ class_exists(NotFoundExceptionInterface::class); */ trait ServiceLocatorTrait { - private array $factories; private array $loading = []; private array $providedTypes; /** * @param array $factories */ - public function __construct(array $factories) - { - $this->factories = $factories; + public function __construct( + private array $factories, + ) { } public function has(string $id): bool From 6cd7c229548d25bf9df3736331cce83180c0ccf0 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 20 Jun 2024 17:52:34 +0200 Subject: [PATCH 59/79] Prefix all sprintf() calls --- Cache/CacheTrait.php | 4 ++-- Service/ServiceLocatorTrait.php | 10 +++++----- Service/ServiceMethodsSubscriberTrait.php | 4 ++-- Service/ServiceSubscriberTrait.php | 4 ++-- Translation/TranslatorTrait.php | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cache/CacheTrait.php b/Cache/CacheTrait.php index c2f6580..4c5449b 100644 --- a/Cache/CacheTrait.php +++ b/Cache/CacheTrait.php @@ -38,7 +38,7 @@ public function delete(string $key): bool private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null, ?LoggerInterface $logger = null): mixed { if (0 > $beta ??= 1.0) { - throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException {}; + throw new class(\sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException {}; } $item = $pool->getItem($key); @@ -54,7 +54,7 @@ private function doGet(CacheItemPoolInterface $pool, string $key, callable $call $item->expiresAt(null); $logger?->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ 'key' => $key, - 'delta' => sprintf('%.1f', $expiry - $now), + 'delta' => \sprintf('%.1f', $expiry - $now), ]); } } diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index a4f2873..bbe4548 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -90,16 +90,16 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface } else { $last = array_pop($alternatives); if ($alternatives) { - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + $message = \sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); } else { - $message = sprintf('only knows about the "%s" service.', $last); + $message = \sprintf('only knows about the "%s" service.', $last); } } if ($this->loading) { - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); } else { - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); } return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { @@ -108,7 +108,7 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface { - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { }; } } diff --git a/Service/ServiceMethodsSubscriberTrait.php b/Service/ServiceMethodsSubscriberTrait.php index 0d89d9f..2c4c274 100644 --- a/Service/ServiceMethodsSubscriberTrait.php +++ b/Service/ServiceMethodsSubscriberTrait.php @@ -42,11 +42,11 @@ public static function getSubscribedServices(): array } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index cc3bc32..f22a303 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -46,11 +46,11 @@ public static function getSubscribedServices(): array } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 63f6fb3..06210b0 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -111,7 +111,7 @@ public function trans(?string $id, array $parameters = [], ?string $domain = nul return strtr($standardRules[0], $parameters); } - $message = sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); + $message = \sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); if (class_exists(InvalidArgumentException::class)) { throw new InvalidArgumentException($message); From 381ca9fef2e7d3fc31024f0900d93fa13a1bb797 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 25 Jun 2024 14:58:00 +0200 Subject: [PATCH 60/79] Add more precise types in reusable test cases --- Service/Test/ServiceLocatorTestCase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Service/Test/ServiceLocatorTestCase.php b/Service/Test/ServiceLocatorTestCase.php index 65a3fe3..a6b87eb 100644 --- a/Service/Test/ServiceLocatorTestCase.php +++ b/Service/Test/ServiceLocatorTestCase.php @@ -19,6 +19,9 @@ abstract class ServiceLocatorTestCase extends TestCase { + /** + * @param array $factories + */ protected function getServiceLocator(array $factories): ContainerInterface { return new class($factories) implements ContainerInterface { From 6b86ebe181ff58bd34def544f483e56a5dd29cd2 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 5 Aug 2024 09:12:25 +0200 Subject: [PATCH 61/79] Fix multiple CS errors --- HttpClient/Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index 39fd701..12d1c87 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -25,7 +25,7 @@ abstract class HttpClientTestCase extends TestCase { public static function setUpBeforeClass(): void { - if (!function_exists('ob_gzhandler')) { + if (!\function_exists('ob_gzhandler')) { static::markTestSkipped('The "ob_gzhandler" function is not available.'); } From f28c925b8c11fd4f6c0f4acfa9f2071d94488f3d Mon Sep 17 00:00:00 2001 From: Roy de Vos Burchart Date: Thu, 1 Aug 2024 17:21:17 +0200 Subject: [PATCH 62/79] Code style change in `@PER-CS2.0` affecting `@Symfony` (parentheses for anonymous classes) --- Tests/Service/ServiceMethodsSubscriberTraitTest.php | 4 ++-- Tests/Service/ServiceSubscriberTraitTest.php | 6 +++--- Translation/Test/TranslatorTest.php | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Tests/Service/ServiceMethodsSubscriberTraitTest.php b/Tests/Service/ServiceMethodsSubscriberTraitTest.php index 396ca7f..246cb61 100644 --- a/Tests/Service/ServiceMethodsSubscriberTraitTest.php +++ b/Tests/Service/ServiceMethodsSubscriberTraitTest.php @@ -46,7 +46,7 @@ public function testParentNotCalledIfHasMagicCall() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class() extends ParentWithMagicCall { + $service = new class extends ParentWithMagicCall { use ServiceMethodsSubscriberTrait; }; @@ -59,7 +59,7 @@ public function testParentNotCalledIfNoParent() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class() { + $service = new class { use ServiceMethodsSubscriberTrait; }; diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 184d92d..1023246 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -54,7 +54,7 @@ public function testParentNotCalledIfHasMagicCall() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class() extends ParentWithMagicCall { + $service = new class extends ParentWithMagicCall { use ServiceSubscriberTrait; }; @@ -67,7 +67,7 @@ public function testParentNotCalledIfNoParent() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class() { + $service = new class { use ServiceSubscriberTrait; }; @@ -82,7 +82,7 @@ public function testSetContainerCalledFirstOnParent() }; $container2 = clone $container1; - $testService = new class() extends LegacyParentTestService2 implements ServiceSubscriberInterface { + $testService = new class extends LegacyParentTestService2 implements ServiceSubscriberInterface { use ServiceSubscriberTrait; }; $this->assertNull($testService->setContainer($container1)); diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 756228a..54cba7c 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -45,7 +45,7 @@ protected function tearDown(): void public function getTranslator(): TranslatorInterface { - return new class() implements TranslatorInterface { + return new class implements TranslatorInterface { use TranslatorTrait; }; } @@ -366,7 +366,7 @@ protected function validateMatrix(string $nplural, array $matrix, bool $expectSu protected function generateTestData($langCodes) { - $translator = new class() { + $translator = new class { use TranslatorTrait { getPluralizationRule as public; } From 7058dde3c9583c6bd14a70b872003fa552438f77 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 5 Sep 2024 11:40:18 +0200 Subject: [PATCH 63/79] make test case classes compatible with PHPUnit 10+ --- CHANGELOG.md | 5 +++++ Cache/composer.json | 2 +- Deprecation/composer.json | 2 +- EventDispatcher/composer.json | 2 +- HttpClient/Test/HttpClientTestCase.php | 4 ++++ HttpClient/composer.json | 2 +- Service/composer.json | 2 +- Translation/Test/TranslatorTest.php | 13 +++++++++++++ Translation/composer.json | 2 +- composer.json | 2 +- 10 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42fe6fd..ffbd4d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.6 +--- + + * Make `HttpClientTestCase` and `TranslatorTest` compatible with PHPUnit 10+ + 3.5 --- diff --git a/Cache/composer.json b/Cache/composer.json index fe261d1..b713c29 100644 --- a/Cache/composer.json +++ b/Cache/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Deprecation/composer.json b/Deprecation/composer.json index ceb6c07..5533b5c 100644 --- a/Deprecation/composer.json +++ b/Deprecation/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/EventDispatcher/composer.json b/EventDispatcher/composer.json index 35956eb..d156b44 100644 --- a/EventDispatcher/composer.json +++ b/EventDispatcher/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index 12d1c87..14a7c1d 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Contracts\HttpClient\Test; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; @@ -1013,6 +1014,7 @@ public function testNoProxy() /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testAutoEncodingRequest() { $client = $this->getHttpClient(__FUNCTION__); @@ -1086,6 +1088,7 @@ public function testInformationalResponseStream() /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testUserlandEncodingRequest() { $client = $this->getHttpClient(__FUNCTION__); @@ -1108,6 +1111,7 @@ public function testUserlandEncodingRequest() /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testGzipBroken() { $client = $this->getHttpClient(__FUNCTION__); diff --git a/HttpClient/composer.json b/HttpClient/composer.json index efb146e..a67a753 100644 --- a/HttpClient/composer.json +++ b/HttpClient/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Service/composer.json b/Service/composer.json index fc8674a..bc2e99a 100644 --- a/Service/composer.json +++ b/Service/composer.json @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 54cba7c..4e3c60c 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -11,6 +11,8 @@ namespace Symfony\Contracts\Translation\Test; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorTrait; @@ -53,6 +55,7 @@ public function getTranslator(): TranslatorInterface /** * @dataProvider getTransTests */ + #[DataProvider('getTransTests')] public function testTrans($expected, $id, $parameters) { $translator = $this->getTranslator(); @@ -63,6 +66,7 @@ public function testTrans($expected, $id, $parameters) /** * @dataProvider getTransChoiceTests */ + #[DataProvider('getTransChoiceTests')] public function testTransChoiceWithExplicitLocale($expected, $id, $number) { $translator = $this->getTranslator(); @@ -75,6 +79,8 @@ public function testTransChoiceWithExplicitLocale($expected, $id, $number) * * @dataProvider getTransChoiceTests */ + #[DataProvider('getTransChoiceTests')] + #[RequiresPhpExtension('intl')] public function testTransChoiceWithDefaultLocale($expected, $id, $number) { $translator = $this->getTranslator(); @@ -85,6 +91,7 @@ public function testTransChoiceWithDefaultLocale($expected, $id, $number) /** * @dataProvider getTransChoiceTests */ + #[DataProvider('getTransChoiceTests')] public function testTransChoiceWithEnUsPosix($expected, $id, $number) { $translator = $this->getTranslator(); @@ -103,6 +110,7 @@ public function testGetSetLocale() /** * @requires extension intl */ + #[RequiresPhpExtension('intl')] public function testGetLocaleReturnsDefaultLocaleIfNotSet() { $translator = $this->getTranslator(); @@ -139,6 +147,7 @@ public static function getTransChoiceTests() /** * @dataProvider getInterval */ + #[DataProvider('getInterval')] public function testInterval($expected, $number, $interval) { $translator = $this->getTranslator(); @@ -164,6 +173,7 @@ public static function getInterval() /** * @dataProvider getChooseTests */ + #[DataProvider('getChooseTests')] public function testChoose($expected, $id, $number, $locale = null) { $translator = $this->getTranslator(); @@ -181,6 +191,7 @@ public function testReturnMessageIfExactlyOneStandardRuleIsGiven() /** * @dataProvider getNonMatchingMessages */ + #[DataProvider('getNonMatchingMessages')] public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number) { $translator = $this->getTranslator(); @@ -296,6 +307,7 @@ public static function getChooseTests() /** * @dataProvider failingLangcodes */ + #[DataProvider('failingLangcodes')] public function testFailedLangcodes($nplural, $langCodes) { $matrix = $this->generateTestData($langCodes); @@ -305,6 +317,7 @@ public function testFailedLangcodes($nplural, $langCodes) /** * @dataProvider successLangcodes */ + #[DataProvider('successLangcodes')] public function testLangcodes($nplural, $langCodes) { $matrix = $this->generateTestData($langCodes); diff --git a/Translation/composer.json b/Translation/composer.json index 181651e..b7220b8 100644 --- a/Translation/composer.json +++ b/Translation/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/composer.json b/composer.json index 3ff8a5e..be90b35 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } } } From 609f606bb5177bdc114266cbad94318d47771e6c Mon Sep 17 00:00:00 2001 From: Ibrahim Bougaoua <41789518+ibrahimBougaoua@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:14:24 +0100 Subject: [PATCH 64/79] Refactor some closure to arrow functions --- Tests/Cache/CacheTraitTest.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Tests/Cache/CacheTraitTest.php b/Tests/Cache/CacheTraitTest.php index baf6ef4..f36b8ef 100644 --- a/Tests/Cache/CacheTraitTest.php +++ b/Tests/Cache/CacheTraitTest.php @@ -43,9 +43,7 @@ public function testSave() $cache->expects($this->once()) ->method('save'); - $callback = function (CacheItemInterface $item) { - return 'computed data'; - }; + $callback = fn (CacheItemInterface $item) => 'computed data'; $cache->get('key', $callback); } @@ -101,9 +99,7 @@ public function testRecomputeOnBetaInf() $cache->expects($this->once()) ->method('save'); - $callback = function (CacheItemInterface $item) { - return 'computed data'; - }; + $callback = fn(CacheItemInterface $item) => 'computed data'; $cache->get('key', $callback, \INF); } @@ -114,9 +110,7 @@ public function testExceptionOnNegativeBeta() ->onlyMethods(['getItem', 'save']) ->getMock(); - $callback = function (CacheItemInterface $item) { - return 'computed data'; - }; + $callback = fn(CacheItemInterface $item) => 'computed data'; $this->expectException(\InvalidArgumentException::class); $cache->get('key', $callback, -2); From ebd19eb51cd00fd1d99de62f9190730695b6002e Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 18 Sep 2024 13:33:46 +0200 Subject: [PATCH 65/79] Miscellaneous tests improvements --- Tests/Cache/CacheTraitTest.php | 2 +- Translation/Test/TranslatorTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Cache/CacheTraitTest.php b/Tests/Cache/CacheTraitTest.php index baf6ef4..e421b08 100644 --- a/Tests/Cache/CacheTraitTest.php +++ b/Tests/Cache/CacheTraitTest.php @@ -71,7 +71,7 @@ public function testNoCallbackCallOnHit() ->method('save'); $callback = function (CacheItemInterface $item) { - $this->assertTrue(false, 'This code should never be reached'); + $this->fail('This code should never be reached'); }; $cache->get('key', $callback); diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 4e3c60c..da19d09 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -372,7 +372,7 @@ protected function validateMatrix(string $nplural, array $matrix, bool $expectSu if ($expectSuccess) { $this->assertCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms."); } else { - $this->assertNotEquals((int) $nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms."); + $this->assertNotCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms."); } } } From f21646e69b2a8898df5f18a609e6a62d201383fd Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 23 Sep 2024 12:42:15 +0200 Subject: [PATCH 66/79] Remove calls to getExpectedException() --- Service/Test/ServiceLocatorTestCase.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Service/Test/ServiceLocatorTestCase.php b/Service/Test/ServiceLocatorTestCase.php index a6b87eb..fdd5b27 100644 --- a/Service/Test/ServiceLocatorTestCase.php +++ b/Service/Test/ServiceLocatorTestCase.php @@ -75,10 +75,8 @@ public function testThrowsOnUndefinedInternalService() 'foo' => function () use (&$locator) { return $locator->get('bar'); }, ]); - if (!$this->getExpectedException()) { - $this->expectException(NotFoundExceptionInterface::class); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - } + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); $locator->get('foo'); } From 10257eb9e7813e3cc7a9fd537534b796cab84330 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 26 Sep 2024 10:09:09 +0200 Subject: [PATCH 67/79] Remove unused imports --- HttpClient/ResponseInterface.php | 1 - 1 file changed, 1 deletion(-) diff --git a/HttpClient/ResponseInterface.php b/HttpClient/ResponseInterface.php index 387345c..a425590 100644 --- a/HttpClient/ResponseInterface.php +++ b/HttpClient/ResponseInterface.php @@ -13,7 +13,6 @@ use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; From 1a4d9c467aa8d07a44298a2de48b62c92a21ac9c Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 30 Sep 2024 13:27:53 +0200 Subject: [PATCH 68/79] Fix CS By running curl https://fabbot.io/patch/symfony/symfony/58283/73967075e25dc5684f7301c0e09e62a0cd440cbe/cs.diff | patch -p0 --- Tests/Cache/CacheTraitTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Cache/CacheTraitTest.php b/Tests/Cache/CacheTraitTest.php index f36b8ef..f958c06 100644 --- a/Tests/Cache/CacheTraitTest.php +++ b/Tests/Cache/CacheTraitTest.php @@ -99,7 +99,7 @@ public function testRecomputeOnBetaInf() $cache->expects($this->once()) ->method('save'); - $callback = fn(CacheItemInterface $item) => 'computed data'; + $callback = fn (CacheItemInterface $item) => 'computed data'; $cache->get('key', $callback, \INF); } @@ -110,7 +110,7 @@ public function testExceptionOnNegativeBeta() ->onlyMethods(['getItem', 'save']) ->getMock(); - $callback = fn(CacheItemInterface $item) => 'computed data'; + $callback = fn (CacheItemInterface $item) => 'computed data'; $this->expectException(\InvalidArgumentException::class); $cache->get('key', $callback, -2); From ab8c95945c84a705cab69304c69191429f626bd0 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 3 Oct 2024 14:15:19 +0200 Subject: [PATCH 69/79] Various CS fix for consistency --- Tests/Service/LegacyTestService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Service/LegacyTestService.php b/Tests/Service/LegacyTestService.php index 9d55b9e..cea5fca 100644 --- a/Tests/Service/LegacyTestService.php +++ b/Tests/Service/LegacyTestService.php @@ -54,7 +54,7 @@ public function withAttribute(): ?Service2 class LegacyChildTestService extends LegacyTestService { - #[SubscribedService()] + #[SubscribedService] public function aChildService(): LegacyService3 { return $this->container->get(__METHOD__); From c8a43378de46da574fea9c68b3e19d546c4e6679 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 10 Oct 2024 10:06:15 +0200 Subject: [PATCH 70/79] add missing properties --- Tests/Service/LegacyTestService.php | 2 ++ Tests/Service/ServiceSubscriberTraitTest.php | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Tests/Service/LegacyTestService.php b/Tests/Service/LegacyTestService.php index 9d55b9e..0e781a4 100644 --- a/Tests/Service/LegacyTestService.php +++ b/Tests/Service/LegacyTestService.php @@ -33,6 +33,8 @@ class LegacyTestService extends LegacyParentTestService implements ServiceSubscr { use ServiceSubscriberTrait; + protected $container; + #[SubscribedService] public function aService(): Service2 { diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 184d92d..0d714a9 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -56,6 +56,8 @@ public function testParentNotCalledIfHasMagicCall() }; $service = new class() extends ParentWithMagicCall { use ServiceSubscriberTrait; + + private $container; }; $this->assertNull($service->setContainer($container)); @@ -69,6 +71,8 @@ public function testParentNotCalledIfNoParent() }; $service = new class() { use ServiceSubscriberTrait; + + private $container; }; $this->assertNull($service->setContainer($container)); From 53fb15f1d8f14d3fcc1bf2bf608a569ebc386a1d Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Mon, 2 Dec 2024 12:18:11 +0100 Subject: [PATCH 71/79] [HttpClient] Always set CURLOPT_CUSTOMREQUEST to the correct HTTP method in CurlHttpClient --- HttpClient/Test/Fixtures/web/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/HttpClient/Test/Fixtures/web/index.php b/HttpClient/Test/Fixtures/web/index.php index a750017..59033d5 100644 --- a/HttpClient/Test/Fixtures/web/index.php +++ b/HttpClient/Test/Fixtures/web/index.php @@ -42,6 +42,7 @@ exit; case '/head': + header('X-Request-Vars: '.json_encode($vars, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); header('Content-Length: '.strlen($json), true); break; From 5dfff0878b7758f5b67f7c0653b68693803d5588 Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Thu, 5 Dec 2024 14:35:19 +0100 Subject: [PATCH 72/79] [HttpClient] Test POST to GET redirects --- HttpClient/Test/Fixtures/web/index.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/HttpClient/Test/Fixtures/web/index.php b/HttpClient/Test/Fixtures/web/index.php index 59033d5..399f8bd 100644 --- a/HttpClient/Test/Fixtures/web/index.php +++ b/HttpClient/Test/Fixtures/web/index.php @@ -199,6 +199,16 @@ ]); exit; + + case '/custom': + if (isset($_GET['status'])) { + http_response_code((int) $_GET['status']); + } + if (isset($_GET['headers']) && is_array($_GET['headers'])) { + foreach ($_GET['headers'] as $header) { + header($header); + } + } } header('Content-Type: application/json', true); From 80427ec4496ca7b06f2ea6d412aa28ce037f895b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 19 Feb 2025 15:04:36 +0100 Subject: [PATCH 73/79] [Cache] Enable namespace-based invalidation by prefixing keys with backend-native namespace separators --- CHANGELOG.md | 1 + Cache/NamespacedPoolInterface.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 Cache/NamespacedPoolInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ffbd4d2..dc9ba96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Make `HttpClientTestCase` and `TranslatorTest` compatible with PHPUnit 10+ + * Add `NamespacedPoolInterface` to support namespace-based invalidation 3.5 --- diff --git a/Cache/NamespacedPoolInterface.php b/Cache/NamespacedPoolInterface.php new file mode 100644 index 0000000..cd67bc0 --- /dev/null +++ b/Cache/NamespacedPoolInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\InvalidArgumentException; + +/** + * Enables namespace-based invalidation by prefixing keys with backend-native namespace separators. + * + * Note that calling `withSubNamespace()` MUST NOT mutate the pool, but return a new instance instead. + * + * When tags are used, they MUST ignore sub-namespaces. + * + * @author Nicolas Grekas + */ +interface NamespacedPoolInterface +{ + /** + * @throws InvalidArgumentException If the namespace contains characters found in ItemInterface's RESERVED_CHARACTERS + */ + public function withSubNamespace(string $namespace): static; +} From 1a176bdca4cddc20b9324bd682fc1fcfbe766b9b Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Fri, 25 Apr 2025 11:18:22 +0200 Subject: [PATCH 74/79] Fix ServiceMethodsSubscriberTrait for nullable service --- Service/ServiceSubscriberTrait.php | 2 +- Tests/Service/ServiceSubscriberTraitTest.php | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index f3b450c..ec6a114 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -51,7 +51,7 @@ public static function getSubscribedServices(): array $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index ba37026..6b9785e 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -27,7 +27,8 @@ public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices { $expected = [ TestService::class.'::aService' => Service2::class, - TestService::class.'::nullableService' => '?'.Service2::class, + TestService::class.'::nullableInAttribute' => '?'.Service2::class, + TestService::class.'::nullableReturnType' => '?'.Service2::class, new SubscribedService(TestService::class.'::withAttribute', Service2::class, true, new Required()), ]; @@ -103,8 +104,18 @@ public function aService(): Service2 { } + #[SubscribedService(nullable: true)] + public function nullableInAttribute(): Service2 + { + if (!$this->container->has(__METHOD__)) { + throw new \LogicException(); + } + + return $this->container->get(__METHOD__); + } + #[SubscribedService] - public function nullableService(): ?Service2 + public function nullableReturnType(): ?Service2 { } From 5e9c95d3051aedafcda42679a9a5d270780ac778 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Fri, 25 Apr 2025 11:05:49 +0200 Subject: [PATCH 75/79] Fix ServiceMethodsSubscriberTrait for nullable service --- Service/ServiceMethodsSubscriberTrait.php | 2 +- Service/ServiceSubscriberTrait.php | 2 +- Tests/Service/LegacyTestService.php | 12 +++++++++++- .../Service/ServiceMethodsSubscriberTraitTest.php | 15 +++++++++++++-- Tests/Service/ServiceSubscriberTraitTest.php | 5 +++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Service/ServiceMethodsSubscriberTrait.php b/Service/ServiceMethodsSubscriberTrait.php index 2c4c274..844be89 100644 --- a/Service/ServiceMethodsSubscriberTrait.php +++ b/Service/ServiceMethodsSubscriberTrait.php @@ -53,7 +53,7 @@ public static function getSubscribedServices(): array $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index f22a303..ed4cec0 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -57,7 +57,7 @@ public static function getSubscribedServices(): array $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/Tests/Service/LegacyTestService.php b/Tests/Service/LegacyTestService.php index 760c8ef..471e186 100644 --- a/Tests/Service/LegacyTestService.php +++ b/Tests/Service/LegacyTestService.php @@ -41,8 +41,18 @@ public function aService(): Service2 return $this->container->get(__METHOD__); } + #[SubscribedService(nullable: true)] + public function nullableInAttribute(): Service2 + { + if (!$this->container->has(__METHOD__)) { + throw new \LogicException(); + } + + return $this->container->get(__METHOD__); + } + #[SubscribedService] - public function nullableService(): ?Service2 + public function nullableReturnType(): ?Service2 { return $this->container->get(__METHOD__); } diff --git a/Tests/Service/ServiceMethodsSubscriberTraitTest.php b/Tests/Service/ServiceMethodsSubscriberTraitTest.php index 246cb61..4d67a84 100644 --- a/Tests/Service/ServiceMethodsSubscriberTraitTest.php +++ b/Tests/Service/ServiceMethodsSubscriberTraitTest.php @@ -25,7 +25,8 @@ public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices { $expected = [ TestService::class.'::aService' => Service2::class, - TestService::class.'::nullableService' => '?'.Service2::class, + TestService::class.'::nullableInAttribute' => '?'.Service2::class, + TestService::class.'::nullableReturnType' => '?'.Service2::class, new SubscribedService(TestService::class.'::withAttribute', Service2::class, true, new Required()), ]; @@ -104,8 +105,18 @@ public function aService(): Service2 return $this->container->get(__METHOD__); } + #[SubscribedService(nullable: true)] + public function nullableInAttribute(): Service2 + { + if (!$this->container->has(__METHOD__)) { + throw new \LogicException(); + } + + return $this->container->get(__METHOD__); + } + #[SubscribedService] - public function nullableService(): ?Service2 + public function nullableReturnType(): ?Service2 { return $this->container->get(__METHOD__); } diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 739d693..bf0db2c 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -33,7 +33,8 @@ public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices { $expected = [ LegacyTestService::class.'::aService' => Service2::class, - LegacyTestService::class.'::nullableService' => '?'.Service2::class, + LegacyTestService::class.'::nullableInAttribute' => '?'.Service2::class, + LegacyTestService::class.'::nullableReturnType' => '?'.Service2::class, new SubscribedService(LegacyTestService::class.'::withAttribute', Service2::class, true, new Required()), ]; @@ -54,7 +55,7 @@ public function testParentNotCalledIfHasMagicCall() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class extends ParentWithMagicCall { + $service = new class extends LegacyParentWithMagicCall { use ServiceSubscriberTrait; private $container; From 54f0ba30895ce9a58c50043078cf2b93f8f413de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Karlovi=C4=87?= Date: Mon, 28 Apr 2025 17:14:25 +0200 Subject: [PATCH 76/79] align the type to the one in the human description --- HttpClient/ResponseInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpClient/ResponseInterface.php b/HttpClient/ResponseInterface.php index a425590..44611cd 100644 --- a/HttpClient/ResponseInterface.php +++ b/HttpClient/ResponseInterface.php @@ -36,7 +36,7 @@ public function getStatusCode(): int; * * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes * - * @return string[][] The headers of the response keyed by header names in lowercase + * @return array> The headers of the response keyed by header names in lowercase * * @throws TransportExceptionInterface When a network error occurs * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached From 4c287a7604bd0aa4c0d2acd1d362b53087354a6f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 10 Jul 2025 09:12:18 +0200 Subject: [PATCH 77/79] CS fixes --- Cache/CacheTrait.php | 4 ++-- HttpClient/Test/HttpClientTestCase.php | 2 +- Service/ServiceLocatorTrait.php | 10 +++++----- Service/ServiceSubscriberTrait.php | 4 ++-- Tests/Service/ServiceSubscriberTraitTest.php | 4 ++-- Translation/Test/TranslatorTest.php | 4 ++-- Translation/TranslatorTrait.php | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cache/CacheTrait.php b/Cache/CacheTrait.php index c2f6580..4c5449b 100644 --- a/Cache/CacheTrait.php +++ b/Cache/CacheTrait.php @@ -38,7 +38,7 @@ public function delete(string $key): bool private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null, ?LoggerInterface $logger = null): mixed { if (0 > $beta ??= 1.0) { - throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException {}; + throw new class(\sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException {}; } $item = $pool->getItem($key); @@ -54,7 +54,7 @@ private function doGet(CacheItemPoolInterface $pool, string $key, callable $call $item->expiresAt(null); $logger?->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ 'key' => $key, - 'delta' => sprintf('%.1f', $expiry - $now), + 'delta' => \sprintf('%.1f', $expiry - $now), ]); } } diff --git a/HttpClient/Test/HttpClientTestCase.php b/HttpClient/Test/HttpClientTestCase.php index b150f0c..a1464a3 100644 --- a/HttpClient/Test/HttpClientTestCase.php +++ b/HttpClient/Test/HttpClientTestCase.php @@ -25,7 +25,7 @@ abstract class HttpClientTestCase extends TestCase { public static function setUpBeforeClass(): void { - if (!function_exists('ob_gzhandler')) { + if (!\function_exists('ob_gzhandler')) { static::markTestSkipped('The "ob_gzhandler" function is not available.'); } diff --git a/Service/ServiceLocatorTrait.php b/Service/ServiceLocatorTrait.php index b62ec3e..acb37fe 100644 --- a/Service/ServiceLocatorTrait.php +++ b/Service/ServiceLocatorTrait.php @@ -91,16 +91,16 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface } else { $last = array_pop($alternatives); if ($alternatives) { - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + $message = \sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); } else { - $message = sprintf('only knows about the "%s" service.', $last); + $message = \sprintf('only knows about the "%s" service.', $last); } } if ($this->loading) { - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); } else { - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); } return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { @@ -109,7 +109,7 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface { - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { }; } } diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index ec6a114..c3c12ce 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -40,11 +40,11 @@ public static function getSubscribedServices(): array } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ diff --git a/Tests/Service/ServiceSubscriberTraitTest.php b/Tests/Service/ServiceSubscriberTraitTest.php index 6b9785e..7779de8 100644 --- a/Tests/Service/ServiceSubscriberTraitTest.php +++ b/Tests/Service/ServiceSubscriberTraitTest.php @@ -49,7 +49,7 @@ public function testParentNotCalledIfHasMagicCall() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class() extends ParentWithMagicCall { + $service = new class extends ParentWithMagicCall { use ServiceSubscriberTrait; }; @@ -62,7 +62,7 @@ public function testParentNotCalledIfNoParent() $container = new class([]) implements ContainerInterface { use ServiceLocatorTrait; }; - $service = new class() { + $service = new class { use ServiceSubscriberTrait; }; diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index 18e6690..b68d027 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -45,7 +45,7 @@ protected function tearDown(): void public function getTranslator(): TranslatorInterface { - return new class() implements TranslatorInterface { + return new class implements TranslatorInterface { use TranslatorTrait; }; } @@ -365,7 +365,7 @@ protected function validateMatrix(string $nplural, array $matrix, bool $expectSu protected function generateTestData($langCodes) { - $translator = new class() { + $translator = new class { use TranslatorTrait { getPluralizationRule as public; } diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 63f6fb3..06210b0 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -111,7 +111,7 @@ public function trans(?string $id, array $parameters = [], ?string $domain = nul return strtr($standardRules[0], $parameters); } - $message = sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); + $message = \sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); if (class_exists(InvalidArgumentException::class)) { throw new InvalidArgumentException($message); From 6c6270f9d3cf2b57b0ec1a11222015f62a5fa4f5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 12 Jul 2025 11:35:41 +0200 Subject: [PATCH 78/79] Fix @var phpdoc --- Service/ServiceSubscriberTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Service/ServiceSubscriberTrait.php b/Service/ServiceSubscriberTrait.php index c3c12ce..93d0d5f 100644 --- a/Service/ServiceSubscriberTrait.php +++ b/Service/ServiceSubscriberTrait.php @@ -47,7 +47,7 @@ public static function getSubscribedServices(): array throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } - /* @var SubscribedService $attribute */ + /** @var SubscribedService $attribute */ $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; From 888afe4b9606f923340860bb0b856ab9d7a41273 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 13 Jul 2025 16:04:15 +0200 Subject: [PATCH 79/79] [Translation] fix support of `TranslatableInterface` in `IdentityTranslator` --- Translation/Test/TranslatorTest.php | 11 +++++++---- Translation/TranslatorTrait.php | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Translation/Test/TranslatorTest.php b/Translation/Test/TranslatorTest.php index b68d027..fad5d75 100644 --- a/Translation/Test/TranslatorTest.php +++ b/Translation/Test/TranslatorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Contracts\Translation\Test; use PHPUnit\Framework\TestCase; +use Symfony\Component\Translation\TranslatableMessage; use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorTrait; @@ -116,10 +117,12 @@ public function testGetLocaleReturnsDefaultLocaleIfNotSet() public static function getTransTests() { - return [ - ['Symfony is great!', 'Symfony is great!', []], - ['Symfony is awesome!', 'Symfony is %what%!', ['%what%' => 'awesome']], - ]; + yield ['Symfony is great!', 'Symfony is great!', []]; + yield ['Symfony is awesome!', 'Symfony is %what%!', ['%what%' => 'awesome']]; + + if (class_exists(TranslatableMessage::class)) { + yield ['He said "Symfony is awesome!".', 'He said "%what%".', ['%what%' => new TranslatableMessage('Symfony is %what%!', ['%what%' => 'awesome'])]]; + } } public static function getTransChoiceTests() diff --git a/Translation/TranslatorTrait.php b/Translation/TranslatorTrait.php index 06210b0..afedd99 100644 --- a/Translation/TranslatorTrait.php +++ b/Translation/TranslatorTrait.php @@ -41,6 +41,12 @@ public function trans(?string $id, array $parameters = [], ?string $domain = nul return ''; } + foreach ($parameters as $k => $v) { + if ($v instanceof TranslatableInterface) { + $parameters[$k] = $v->trans($this, $locale); + } + } + if (!isset($parameters['%count%']) || !is_numeric($parameters['%count%'])) { return strtr($id, $parameters); }