Version in base suite: 2.5.2-1+deb12u1 Base version: php-symfony-contracts_2.5.2-1+deb12u1 Target version: php-symfony-contracts_2.5.5-0+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/php-symfony-contracts/php-symfony-contracts_2.5.2-1+deb12u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/php-symfony-contracts/php-symfony-contracts_2.5.5-0+deb12u1.dsc .gitignore | 3 Cache/.gitignore | 3 Cache/CacheInterface.php | 6 - Cache/CacheTrait.php | 4 - Cache/LICENSE | 2 Deprecation/.gitignore | 3 Deprecation/LICENSE | 2 EventDispatcher/.gitignore | 3 EventDispatcher/EventDispatcherInterface.php | 2 EventDispatcher/LICENSE | 2 HttpClient/.gitignore | 3 HttpClient/HttpClientInterface.php | 12 +-- HttpClient/LICENSE | 2 HttpClient/ResponseInterface.php | 2 HttpClient/Test/Fixtures/web/index.php | 43 +++++++----- HttpClient/Test/HttpClientTestCase.php | 59 ++++++++++++++++ HttpClient/Test/TestHttpServer.php | 18 ++++- LICENSE | 2 Service/.gitignore | 3 Service/LICENSE | 2 Service/ServiceSubscriberTrait.php | 9 +- Service/Test/ServiceLocatorTest.php | 80 +--------------------- Service/Test/ServiceLocatorTestCase.php | 95 +++++++++++++++++++++++++++ Tests/Cache/CacheTraitTest.php | 8 +- Tests/Service/ServiceSubscriberTraitTest.php | 32 +++++++++ Translation/.gitignore | 3 Translation/LICENSE | 2 Translation/Test/TranslatorTest.php | 24 +++--- Translation/TranslatableInterface.php | 2 Translation/TranslatorInterface.php | 2 Translation/TranslatorTrait.php | 2 debian/changelog | 13 +++ 32 files changed, 291 insertions(+), 157 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpcexxmxeq/php-symfony-contracts_2.5.2-1+deb12u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpcexxmxeq/php-symfony-contracts_2.5.5-0+deb12u1.dsc: no acceptable signature found diff -Nru php-symfony-contracts-2.5.2/.gitignore php-symfony-contracts-2.5.5/.gitignore --- php-symfony-contracts-2.5.2/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -composer.lock -phpunit.xml -vendor/ diff -Nru php-symfony-contracts-2.5.2/Cache/.gitignore php-symfony-contracts-2.5.5/Cache/.gitignore --- php-symfony-contracts-2.5.2/Cache/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Cache/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff -Nru php-symfony-contracts-2.5.2/Cache/CacheInterface.php php-symfony-contracts-2.5.5/Cache/CacheInterface.php --- php-symfony-contracts-2.5.2/Cache/CacheInterface.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Cache/CacheInterface.php 2024-11-28 08:37:04.000000000 +0000 @@ -42,16 +42,16 @@ * * @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); /** * Removes an item from the pool. * * @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; } diff -Nru php-symfony-contracts-2.5.2/Cache/CacheTrait.php php-symfony-contracts-2.5.5/Cache/CacheTrait.php --- php-symfony-contracts-2.5.2/Cache/CacheTrait.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Cache/CacheTrait.php 2024-11-28 08:37:04.000000000 +0000 @@ -30,7 +30,7 @@ * * @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) { return $this->doGet($this, $key, $callback, $beta, $metadata); } @@ -43,7 +43,7 @@ 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) { 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 -Nru php-symfony-contracts-2.5.2/Cache/LICENSE php-symfony-contracts-2.5.5/Cache/LICENSE --- php-symfony-contracts-2.5.2/Cache/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Cache/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/Deprecation/.gitignore php-symfony-contracts-2.5.5/Deprecation/.gitignore --- php-symfony-contracts-2.5.2/Deprecation/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Deprecation/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff -Nru php-symfony-contracts-2.5.2/Deprecation/LICENSE php-symfony-contracts-2.5.5/Deprecation/LICENSE --- php-symfony-contracts-2.5.2/Deprecation/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Deprecation/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2020-2022 Fabien Potencier +Copyright (c) 2020-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/EventDispatcher/.gitignore php-symfony-contracts-2.5.5/EventDispatcher/.gitignore --- php-symfony-contracts-2.5.2/EventDispatcher/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/EventDispatcher/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff -Nru php-symfony-contracts-2.5.2/EventDispatcher/EventDispatcherInterface.php php-symfony-contracts-2.5.5/EventDispatcher/EventDispatcherInterface.php --- php-symfony-contracts-2.5.2/EventDispatcher/EventDispatcherInterface.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/EventDispatcher/EventDispatcherInterface.php 2024-11-28 08:37:04.000000000 +0000 @@ -27,5 +27,5 @@ * * @return object The passed $event MUST be returned */ - public function dispatch(object $event, string $eventName = null): object; + public function dispatch(object $event, ?string $eventName = null): object; } diff -Nru php-symfony-contracts-2.5.2/EventDispatcher/LICENSE php-symfony-contracts-2.5.5/EventDispatcher/LICENSE --- php-symfony-contracts-2.5.2/EventDispatcher/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/EventDispatcher/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/HttpClient/.gitignore php-symfony-contracts-2.5.5/HttpClient/.gitignore --- php-symfony-contracts-2.5.2/HttpClient/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff -Nru php-symfony-contracts-2.5.2/HttpClient/HttpClientInterface.php php-symfony-contracts-2.5.5/HttpClient/HttpClientInterface.php --- php-symfony-contracts-2.5.2/HttpClient/HttpClientInterface.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/HttpClientInterface.php 2024-11-28 08:37:04.000000000 +0000 @@ -48,14 +48,14 @@ 'buffer' => true, // bool|resource|\Closure - whether the content of the response should be buffered or not, // or a stream resource where the response body should be written, // or a closure telling if/where the response should be buffered based on its headers - 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort - // the request; it MUST be called on DNS resolution, on arrival of headers and on - // completion; it SHOULD be called on upload/download of data and at least 1/s + 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort the + // request; it MUST be called on connection, on headers and on completion; it SHOULD be + // called on upload/download of data and at least 1/s 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached - 'timeout' => null, // float - the idle timeout - defaults to ini_get('default_socket_timeout') - 'max_duration' => 0, // float - the maximum execution time for the request+response as a whole; + 'timeout' => null, // float - the idle timeout (in seconds) - defaults to ini_get('default_socket_timeout') + 'max_duration' => 0, // float - the maximum execution time (in seconds) for the request+response as a whole; // a value lower than or equal to 0 means it is unlimited 'bindto' => '0', // string - the interface or the local socket to bind to 'verify_peer' => true, // see https://php.net/context.ssl for the following options @@ -91,5 +91,5 @@ * @param 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($responses, ?float $timeout = null): ResponseStreamInterface; } diff -Nru php-symfony-contracts-2.5.2/HttpClient/LICENSE php-symfony-contracts-2.5.5/HttpClient/LICENSE --- php-symfony-contracts-2.5.2/HttpClient/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/HttpClient/ResponseInterface.php php-symfony-contracts-2.5.5/HttpClient/ResponseInterface.php --- php-symfony-contracts-2.5.2/HttpClient/ResponseInterface.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/ResponseInterface.php 2024-11-28 08:37:04.000000000 +0000 @@ -105,5 +105,5 @@ * @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); } diff -Nru php-symfony-contracts-2.5.2/HttpClient/Test/Fixtures/web/index.php php-symfony-contracts-2.5.5/HttpClient/Test/Fixtures/web/index.php --- php-symfony-contracts-2.5.2/HttpClient/Test/Fixtures/web/index.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/Test/Fixtures/web/index.php 2024-11-28 08:37:04.000000000 +0000 @@ -12,26 +12,32 @@ $_POST['content-type'] = $_SERVER['HTTP_CONTENT_TYPE'] ?? '?'; } +$headers = [ + 'SERVER_PROTOCOL', + 'SERVER_NAME', + 'REQUEST_URI', + 'REQUEST_METHOD', + 'PHP_AUTH_USER', + 'PHP_AUTH_PW', + 'REMOTE_ADDR', + 'REMOTE_PORT', +]; + +foreach ($headers as $k) { + if (isset($_SERVER[$k])) { + $vars[$k] = $_SERVER[$k]; + } +} + foreach ($_SERVER as $k => $v) { - switch ($k) { - default: - if (0 !== strpos($k, 'HTTP_')) { - continue 2; - } - // no break - case 'SERVER_NAME': - case 'SERVER_PROTOCOL': - case 'REQUEST_URI': - case 'REQUEST_METHOD': - case 'PHP_AUTH_USER': - case 'PHP_AUTH_PW': - $vars[$k] = $v; + if (0 === strpos($k, 'HTTP_')) { + $vars[$k] = $v; } } $json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); -switch ($vars['REQUEST_URI']) { +switch (parse_url($vars['REQUEST_URI'], \PHP_URL_PATH)) { default: exit; @@ -86,9 +92,16 @@ header('Location: //?foo=bar', true, 301); break; + case '/301/proxy': + case 'http://localhost:8057/301/proxy': + case 'http://127.0.0.1:8057/301/proxy': + header('Location: http://localhost:8057/', true, 301); + break; + case '/302': if (!isset($vars['HTTP_AUTHORIZATION'])) { - header('Location: http://localhost:8057/', true, 302); + $location = $_GET['location'] ?? 'http://localhost:8057/'; + header('Location: '.$location, true, 302); } break; diff -Nru php-symfony-contracts-2.5.2/HttpClient/Test/HttpClientTestCase.php php-symfony-contracts-2.5.5/HttpClient/Test/HttpClientTestCase.php --- php-symfony-contracts-2.5.2/HttpClient/Test/HttpClientTestCase.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/Test/HttpClientTestCase.php 2024-11-28 08:37:04.000000000 +0000 @@ -25,9 +25,19 @@ { public static function setUpBeforeClass(): void { + if (!function_exists('ob_gzhandler')) { + static::markTestSkipped('The "ob_gzhandler" function is not available.'); + } + TestHttpServer::start(); } + public static function tearDownAfterClass(): void + { + TestHttpServer::stop(8067); + TestHttpServer::stop(8077); + } + abstract protected function getHttpClient(string $testCase): HttpClientInterface; public function testGetRequest() @@ -724,6 +734,18 @@ $this->assertSame(200, $response->getStatusCode()); } + public function testIPv6Resolve() + { + TestHttpServer::start(-8087); + + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://symfony.com:8087/', [ + 'resolve' => ['symfony.com' => '::1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + } + public function testNotATimeout() { $client = $this->getHttpClient(__FUNCTION__); @@ -969,6 +991,14 @@ } finally { unset($_SERVER['http_proxy']); } + + $response = $client->request('GET', 'http://localhost:8057/301/proxy', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); } public function testNoProxy() @@ -1134,4 +1164,33 @@ $response = $client2->request('GET', '/'); $this->assertSame(200, $response->getStatusCode()); } + + public function testBindToPort() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', ['bindto' => '127.0.0.1:9876']); + $response->getStatusCode(); + + $vars = $response->toArray(); + + self::assertSame('127.0.0.1', $vars['REMOTE_ADDR']); + self::assertSame('9876', $vars['REMOTE_PORT']); + } + + public function testBindToPortV6() + { + TestHttpServer::start(-8087); + + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://[::1]:8087', ['bindto' => '[::1]:9876']); + $response->getStatusCode(); + + $vars = $response->toArray(); + + self::assertSame('::1', $vars['REMOTE_ADDR']); + + if ('\\' !== \DIRECTORY_SEPARATOR) { + self::assertSame('9876', $vars['REMOTE_PORT']); + } + } } diff -Nru php-symfony-contracts-2.5.2/HttpClient/Test/TestHttpServer.php php-symfony-contracts-2.5.5/HttpClient/Test/TestHttpServer.php --- php-symfony-contracts-2.5.2/HttpClient/Test/TestHttpServer.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/HttpClient/Test/TestHttpServer.php 2024-11-28 08:37:04.000000000 +0000 @@ -23,6 +23,13 @@ */ public static function start(int $port = 8057) { + if (0 > $port) { + $port = -$port; + $ip = '[::1]'; + } else { + $ip = '127.0.0.1'; + } + if (isset(self::$process[$port])) { self::$process[$port]->stop(); } else { @@ -32,15 +39,22 @@ } $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 = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', $ip.':'.$port])); $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); $process->start(); self::$process[$port] = $process; do { usleep(50000); - } while (!@fopen('http://127.0.0.1:'.$port, 'r')); + } while (!@fopen('http://'.$ip.':'.$port, 'r')); return $process; } + + public static function stop(int $port = 8057) + { + if (isset(self::$process[$port])) { + self::$process[$port]->stop(); + } + } } diff -Nru php-symfony-contracts-2.5.2/LICENSE php-symfony-contracts-2.5.5/LICENSE --- php-symfony-contracts-2.5.2/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/Service/.gitignore php-symfony-contracts-2.5.5/Service/.gitignore --- php-symfony-contracts-2.5.2/Service/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Service/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff -Nru php-symfony-contracts-2.5.2/Service/LICENSE php-symfony-contracts-2.5.5/Service/LICENSE --- php-symfony-contracts-2.5.2/Service/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Service/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/Service/ServiceSubscriberTrait.php php-symfony-contracts-2.5.5/Service/ServiceSubscriberTrait.php --- php-symfony-contracts-2.5.2/Service/ServiceSubscriberTrait.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Service/ServiceSubscriberTrait.php 2024-11-28 08:37:04.000000000 +0000 @@ -98,12 +98,13 @@ */ public function setContainer(ContainerInterface $container) { - $this->container = $container; - + $ret = null; if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { - return parent::setContainer($container); + $ret = parent::setContainer($container); } - return null; + $this->container = $container; + + return $ret; } } diff -Nru php-symfony-contracts-2.5.2/Service/Test/ServiceLocatorTest.php php-symfony-contracts-2.5.5/Service/Test/ServiceLocatorTest.php --- php-symfony-contracts-2.5.2/Service/Test/ServiceLocatorTest.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Service/Test/ServiceLocatorTest.php 2024-11-28 08:37:04.000000000 +0000 @@ -11,85 +11,13 @@ namespace Symfony\Contracts\Service\Test; -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Contracts\Service\ServiceLocatorTrait; +class_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class); -abstract class ServiceLocatorTest extends TestCase -{ +if (false) { /** - * @return ContainerInterface + * @deprecated since PHPUnit 9.6 */ - protected function getServiceLocator(array $factories) + class ServiceLocatorTest { - return new class($factories) implements ContainerInterface { - use ServiceLocatorTrait; - }; - } - - public function testHas() - { - $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, - ]); - - $this->assertTrue($locator->has('foo')); - $this->assertTrue($locator->has('bar')); - $this->assertFalse($locator->has('dummy')); - } - - public function testGet() - { - $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('baz', $locator->get('bar')); - } - - public function testGetDoesNotMemoize() - { - $i = 0; - $locator = $this->getServiceLocator([ - 'foo' => function () use (&$i) { - ++$i; - - return 'bar'; - }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame(2, $i); - } - - 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'); }, - ]); - - $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'); }, - ]); - - $locator->get('foo'); } } diff -Nru php-symfony-contracts-2.5.2/Service/Test/ServiceLocatorTestCase.php php-symfony-contracts-2.5.5/Service/Test/ServiceLocatorTestCase.php --- php-symfony-contracts-2.5.2/Service/Test/ServiceLocatorTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ php-symfony-contracts-2.5.5/Service/Test/ServiceLocatorTestCase.php 2024-11-28 08:37:04.000000000 +0000 @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTestCase extends TestCase +{ + /** + * @return ContainerInterface + */ + protected function getServiceLocator(array $factories) + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + 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'); }, + ]); + + $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'); }, + ]); + + $locator->get('foo'); + } +} diff -Nru php-symfony-contracts-2.5.2/Tests/Cache/CacheTraitTest.php php-symfony-contracts-2.5.5/Tests/Cache/CacheTraitTest.php --- php-symfony-contracts-2.5.2/Tests/Cache/CacheTraitTest.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Tests/Cache/CacheTraitTest.php 2024-11-28 08:37:04.000000000 +0000 @@ -34,7 +34,7 @@ ->with('computed data'); $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) + ->onlyMethods(['getItem', 'save']) ->getMock(); $cache->expects($this->once()) ->method('getItem') @@ -60,7 +60,7 @@ ->method('set'); $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) + ->onlyMethods(['getItem', 'save']) ->getMock(); $cache->expects($this->once()) @@ -91,7 +91,7 @@ ->with('computed data'); $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) + ->onlyMethods(['getItem', 'save']) ->getMock(); $cache->expects($this->once()) @@ -111,7 +111,7 @@ public function testExceptionOnNegativeBeta() { $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) + ->onlyMethods(['getItem', 'save']) ->getMock(); $callback = function (CacheItemInterface $item) { diff -Nru php-symfony-contracts-2.5.2/Tests/Service/ServiceSubscriberTraitTest.php php-symfony-contracts-2.5.5/Tests/Service/ServiceSubscriberTraitTest.php --- php-symfony-contracts-2.5.2/Tests/Service/ServiceSubscriberTraitTest.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Tests/Service/ServiceSubscriberTraitTest.php 2024-11-28 08:37:04.000000000 +0000 @@ -81,8 +81,21 @@ $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)); + } + /** * @requires PHP 8 + * * @group legacy */ public function testMethodsWithUnionReturnTypesAreIgnored() @@ -160,3 +173,22 @@ class Service3 { } + +class ParentTestService2 +{ + /** @var ContainerInterface */ + protected $container; + + public function setContainer(ContainerInterface $container) + { + $previous = $this->container; + $this->container = $container; + + return $previous; + } +} + +class TestService2 extends ParentTestService2 implements ServiceSubscriberInterface +{ + use ServiceSubscriberTrait; +} diff -Nru php-symfony-contracts-2.5.2/Translation/.gitignore php-symfony-contracts-2.5.5/Translation/.gitignore --- php-symfony-contracts-2.5.2/Translation/.gitignore 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Translation/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff -Nru php-symfony-contracts-2.5.2/Translation/LICENSE php-symfony-contracts-2.5.5/Translation/LICENSE --- php-symfony-contracts-2.5.2/Translation/LICENSE 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Translation/LICENSE 2024-11-28 08:37:04.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru php-symfony-contracts-2.5.2/Translation/Test/TranslatorTest.php php-symfony-contracts-2.5.5/Translation/Test/TranslatorTest.php --- php-symfony-contracts-2.5.2/Translation/Test/TranslatorTest.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Translation/Test/TranslatorTest.php 2024-11-28 08:37:04.000000000 +0000 @@ -117,7 +117,7 @@ $this->assertEquals('en', $translator->getLocale()); } - public function getTransTests() + public static function getTransTests() { return [ ['Symfony is great!', 'Symfony is great!', []], @@ -125,7 +125,7 @@ ]; } - 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], @@ -140,7 +140,7 @@ } /** - * @dataProvider getInternal + * @dataProvider getInterval */ public function testInterval($expected, $number, $interval) { @@ -149,7 +149,7 @@ $this->assertEquals($expected, $translator->trans($interval.' foo|[1,Inf[ bar', ['%count%' => $number])); } - public function getInternal() + public static function getInterval() { return [ ['foo', 3, '{1,2, 3 ,4}'], @@ -192,7 +192,7 @@ $translator->trans($id, ['%count%' => $number]); } - public function getNonMatchingMessages() + public static function getNonMatchingMessages() { return [ ['{0} There are no apples|{1} There is one apple', 2], @@ -202,7 +202,7 @@ ]; } - 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], @@ -258,13 +258,13 @@ new-line in it. Selector = 0.|{1}This is a text with a new-line in it. Selector = 1.|[1,Inf]This is a text with a new-line in it. Selector > 1.', 5], - // with double-quotes and id split accros lines + // with double-quotes and id split across lines ['This is a text with a new-line in it. Selector = 1.', '{0}This is a text with a new-line in it. Selector = 0.|{1}This is a text with a new-line in it. Selector = 1.|[1,Inf]This is a text with a new-line in it. Selector > 1.', 1], - // with single-quotes and id split accros lines + // with single-quotes and id split across lines ['This is a text with a new-line in it. Selector > 1.', '{0}This is a text with a new-line in it. Selector = 0.|{1}This is a text with a @@ -272,9 +272,9 @@ new-line in it. Selector > 1.', 5], // with single-quotes and \n in text ['This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0], - // with double-quotes and id split accros lines + // with double-quotes and id split across lines ["This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1], - // esacape pipe + // escape pipe ['This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0], // Empty plural set (2 plural forms) from a .PO file ['', '|', 1], @@ -320,7 +320,7 @@ * * @return array */ - public function successLangcodes() + public static function successLangcodes() { return [ ['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']], @@ -339,7 +339,7 @@ * * @return array with nplural together with langcodes */ - public function failingLangcodes() + public static function failingLangcodes() { return [ ['1', ['fa']], diff -Nru php-symfony-contracts-2.5.2/Translation/TranslatableInterface.php php-symfony-contracts-2.5.5/Translation/TranslatableInterface.php --- php-symfony-contracts-2.5.2/Translation/TranslatableInterface.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Translation/TranslatableInterface.php 2024-11-28 08:37:04.000000000 +0000 @@ -16,5 +16,5 @@ */ interface TranslatableInterface { - public function trans(TranslatorInterface $translator, string $locale = null): string; + public function trans(TranslatorInterface $translator, ?string $locale = null): string; } diff -Nru php-symfony-contracts-2.5.2/Translation/TranslatorInterface.php php-symfony-contracts-2.5.5/Translation/TranslatorInterface.php --- php-symfony-contracts-2.5.2/Translation/TranslatorInterface.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Translation/TranslatorInterface.php 2024-11-28 08:37:04.000000000 +0000 @@ -63,5 +63,5 @@ * * @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); } diff -Nru php-symfony-contracts-2.5.2/Translation/TranslatorTrait.php php-symfony-contracts-2.5.5/Translation/TranslatorTrait.php --- php-symfony-contracts-2.5.2/Translation/TranslatorTrait.php 2022-06-27 16:58:25.000000000 +0000 +++ php-symfony-contracts-2.5.5/Translation/TranslatorTrait.php 2024-11-28 08:37:04.000000000 +0000 @@ -43,7 +43,7 @@ /** * {@inheritdoc} */ - public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string + public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string { if (null === $id || '' === $id) { return ''; diff -Nru php-symfony-contracts-2.5.2/debian/changelog php-symfony-contracts-2.5.5/debian/changelog --- php-symfony-contracts-2.5.2/debian/changelog 2024-02-15 21:48:06.000000000 +0000 +++ php-symfony-contracts-2.5.5/debian/changelog 2026-05-24 13:36:33.000000000 +0000 @@ -1,3 +1,16 @@ +php-symfony-contracts (2.5.5-0+deb12u1) bookworm-security; urgency=medium + + [ Fabien Potencier ] + * Update license years (last time) + + [ Nicolas Grekas ] + * Work around parse_url() bug (bis) + + [ Christian Flothmann ] + * stop all server processes after tests have run + + -- David Prévot Sun, 24 May 2026 15:36:33 +0200 + php-symfony-contracts (2.5.2-1+deb12u1) bookworm; urgency=medium * Track debian/bookworm-security