From db06a3f3c52adeb7a1e84745cece0a9c474f518a Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 1 Nov 2023 09:14:07 +0100 Subject: [PATCH 01/20] [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 02/20] [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 5d4ea81748ef711275de44c7c6ea5d65a02025c8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 5 Apr 2024 11:11:55 +0200 Subject: [PATCH 03/20] [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 04/20] 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 05/20] 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 06/20] 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 07/20] 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 08/20] 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 09/20] 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 10/20] 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 11/20] 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 12/20] 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 13/20] 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 14/20] 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 15/20] 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 16/20] 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 17/20] 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 80427ec4496ca7b06f2ea6d412aa28ce037f895b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 19 Feb 2025 15:04:36 +0100 Subject: [PATCH 18/20] [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 5e9c95d3051aedafcda42679a9a5d270780ac778 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Fri, 25 Apr 2025 11:05:49 +0200 Subject: [PATCH 19/20] 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 20/20] 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 pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy