{% for name, template in templates %}
{% if block('toolbar', template) is defined %}
{% with {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -342,7 +342,7 @@
$twig = $this->createMock(Environment::class);
$controller = new ProfilerController($urlGenerator, null, $twig, []);
- $controller->phpinfoAction(Request::create('/_profiler/phpinfo'));
+ $controller->phpinfoAction();
}
public function testPhpinfoAction()
@@ -355,7 +355,7 @@
$this->assertStringContainsString('PHP License', $client->getResponse()->getContent());
}
- public static function provideCspVariants()
+ public static function provideCspVariants(): array
{
return [
[true],
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/RouterControllerTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/RouterControllerTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/RouterControllerTest.php 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/RouterControllerTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\WebProfilerBundle\Tests\Controller;
+
+use Symfony\Bundle\FrameworkBundle\KernelBrowser;
+use Symfony\Bundle\FrameworkBundle\Routing\Router;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+use Symfony\Bundle\WebProfilerBundle\Tests\Functional\WebProfilerBundleKernel;
+use Symfony\Component\DomCrawler\Crawler;
+use Symfony\Component\Routing\Route;
+
+class RouterControllerTest extends WebTestCase
+{
+ public function testFalseNegativeTrace()
+ {
+ $path = '/foo/bar:123/baz';
+
+ $kernel = new WebProfilerBundleKernel();
+ $client = new KernelBrowser($kernel);
+ $client->disableReboot();
+ $client->getKernel()->boot();
+
+ /** @var Router $router */
+ $router = $client->getContainer()->get('router');
+ $router->getRouteCollection()->add('route1', new Route($path));
+
+ $client->request('GET', $path);
+
+ $crawler = $client->request('GET', '/_profiler/latest?panel=router&type=request');
+
+ $matchedRouteCell = $crawler
+ ->filter('#router-logs .status-success td')
+ ->reduce(function (Crawler $td) use ($path): bool {
+ return $td->text() === $path;
+ });
+
+ $this->assertSame(1, $matchedRouteCell->count());
+ }
+}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -46,7 +46,7 @@
}
}
- public static function provideRequestAndResponses()
+ public static function provideRequestAndResponses(): array
{
$nonce = bin2hex(random_bytes(16));
@@ -73,7 +73,7 @@
];
}
- public static function provideRequestAndResponsesForOnKernelResponse()
+ public static function provideRequestAndResponsesForOnKernelResponse(): array
{
$nonce = bin2hex(random_bytes(16));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -22,8 +22,11 @@
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\HttpKernel\KernelInterface;
+use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler;
use Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface;
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouterInterface;
class WebProfilerExtensionTest extends TestCase
@@ -58,15 +61,11 @@
$this->kernel = $this->createMock(KernelInterface::class);
- $profiler = $this->createMock(Profiler::class);
- $profilerStorage = $this->createMock(ProfilerStorageInterface::class);
- $router = $this->createMock(RouterInterface::class);
-
$this->container = new ContainerBuilder();
$this->container->register('data_collector.dump', DumpDataCollector::class)->setPublic(true);
$this->container->register('error_handler.error_renderer.html', HtmlErrorRenderer::class)->setPublic(true);
$this->container->register('event_dispatcher', EventDispatcher::class)->setPublic(true);
- $this->container->register('router', \get_class($router))->setPublic(true);
+ $this->container->register('router', Router::class)->setPublic(true);
$this->container->register('twig', 'Twig\Environment')->setPublic(true);
$this->container->register('twig_loader', 'Twig\Loader\ArrayLoader')->addArgument([])->setPublic(true);
$this->container->register('twig', 'Twig\Environment')->addArgument(new Reference('twig_loader'))->setPublic(true);
@@ -78,9 +77,9 @@
$this->container->setParameter('kernel.charset', 'UTF-8');
$this->container->setParameter('debug.file_link_format', null);
$this->container->setParameter('profiler.class', ['Symfony\\Component\\HttpKernel\\Profiler\\Profiler']);
- $this->container->register('profiler', \get_class($profiler))
+ $this->container->register('profiler', Profiler::class)
->setPublic(true)
- ->addArgument(new Definition(\get_class($profilerStorage)));
+ ->addArgument(new Definition(NullProfilerStorage::class));
$this->container->setParameter('data_collector.templates', []);
$this->container->set('kernel', $this->kernel);
$this->container->addCompilerPass(new RegisterListenersPass());
@@ -212,3 +211,54 @@
return $this->container;
}
}
+
+class Router implements RouterInterface
+{
+ private $context;
+
+ public function setContext(RequestContext $context): void
+ {
+ $this->context = $context;
+ }
+
+ public function getContext(): RequestContext
+ {
+ return $this->context;
+ }
+
+ public function getRouteCollection(): RouteCollection
+ {
+ return new RouteCollection();
+ }
+
+ public function generate(string $name, array $parameters = [], int $referenceType = self::ABSOLUTE_PATH): string
+ {
+ }
+
+ public function match(string $pathinfo): array
+ {
+ return [];
+ }
+}
+
+class NullProfilerStorage implements ProfilerStorageInterface
+{
+ public function find(?string $ip, ?string $url, ?int $limit, ?string $method, ?int $start = null, ?int $end = null): array
+ {
+ return [];
+ }
+
+ public function read(string $token): ?Profile
+ {
+ return null;
+ }
+
+ public function write(Profile $profile): bool
+ {
+ return true;
+ }
+
+ public function purge()
+ {
+ }
+}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -149,7 +149,7 @@
$this->assertEquals('', $response->getContent());
}
- public static function provideRedirects()
+ public static function provideRedirects(): array
{
return [
[301],
@@ -344,6 +344,20 @@
$this->assertEquals("\nWDT\n", $response->getContent());
}
+ public function testNullContentTypeWithNoDebugEnv()
+ {
+ $response = new Response('');
+ $response->headers->set('Content-Type', null);
+ $response->headers->set('X-Debug-Token', 'xxxxxxxx');
+
+ $event = new ResponseEvent($this->createMock(Kernel::class), new Request(), HttpKernelInterface::MAIN_REQUEST, $response);
+
+ $listener = new WebDebugToolbarListener($this->getTwigMock(), false, WebDebugToolbarListener::ENABLED, null);
+ $listener->onKernelResponse($event);
+
+ $this->expectNotToPerformAssertions();
+ }
+
protected function getTwigMock($render = 'WDT')
{
$templating = $this->createMock(Environment::class);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,7 +23,7 @@
$this->assertMatchesRegularExpression('~
~s', file_get_contents($iconFilePath), sprintf('The SVG metadata of the %s icon is different than expected (use the same as the other icons).', $iconFilePath));
}
- public static function provideIconFilePaths()
+ public static function provideIconFilePaths(): array
{
return array_map(function ($filePath) { return (array) $filePath; }, glob(__DIR__.'/../../Resources/views/Icon/*.svg'));
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -15,8 +15,7 @@
use Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Twig\Environment;
-use Twig\Extension\CoreExtension;
-use Twig\Extension\EscaperExtension;
+use Twig\Loader\ArrayLoader;
class WebProfilerExtensionTest extends TestCase
{
@@ -25,10 +24,7 @@
*/
public function testDumpHeaderIsDisplayed(string $message, array $context, bool $dump1HasHeader, bool $dump2HasHeader)
{
- class_exists(CoreExtension::class); // Load twig_convert_encoding()
- class_exists(EscaperExtension::class); // Load twig_escape_filter()
-
- $twigEnvironment = $this->mockTwigEnvironment();
+ $twigEnvironment = new Environment(new ArrayLoader());
$varCloner = new VarCloner();
$webProfilerExtension = new WebProfilerExtension();
@@ -49,13 +45,4 @@
yield ['Some message {foo}', ['foo' => 'foo', 'bar' => 'bar'], true, false];
yield ['Some message {foo}', ['bar' => 'bar'], false, true];
}
-
- private function mockTwigEnvironment()
- {
- $twigEnvironment = $this->createMock(Environment::class);
-
- $twigEnvironment->expects($this->any())->method('getCharset')->willReturn('UTF-8');
-
- return $twigEnvironment;
- }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php 2026-05-27 08:15:55.000000000 +0000
@@ -14,8 +14,10 @@
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Twig\Environment;
+use Twig\Extension\EscaperExtension;
use Twig\Extension\ProfilerExtension;
use Twig\Profiler\Profile;
+use Twig\Runtime\EscaperRuntime;
use Twig\TwigFunction;
/**
@@ -42,7 +44,7 @@
*/
private $stackLevel = 0;
- public function __construct(HtmlDumper $dumper = null)
+ public function __construct(?HtmlDumper $dumper = null)
{
$this->dumper = $dumper ?? new HtmlDumper();
$this->dumper->setOutput($this->output = fopen('php://memory', 'r+'));
@@ -60,9 +62,6 @@
}
}
- /**
- * {@inheritdoc}
- */
public function getFunctions(): array
{
return [
@@ -85,14 +84,14 @@
return str_replace("\n$1"', $message);
$replacements = [];
foreach ($context ?? [] as $k => $v) {
- $k = '{'.twig_escape_filter($env, $k).'}';
+ $k = '{'.self::escape($env, $k).'}';
if (str_contains($message, $k)) {
$replacements[$k] = $v;
}
@@ -109,11 +108,24 @@
return '
'.strtr($message, $replacements).'';
}
- /**
- * {@inheritdoc}
- */
public function getName()
{
return 'profiler';
}
+
+ private static function escape(Environment $env, string $s): string
+ {
+ // Twig 3.10 and above
+ if (class_exists(EscaperRuntime::class)) {
+ return $env->getRuntime(EscaperRuntime::class)->escape($s);
+ }
+
+ // Twig 3.9
+ if (method_exists(EscaperExtension::class, 'escape')) {
+ return EscaperExtension::escape($env, $s);
+ }
+
+ // to be removed when support for Twig 3 is dropped
+ return twig_escape_filter($env, $s);
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/composer.json symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/composer.json
--- symfony-5.4.23+dfsg/src/Symfony/Bundle/WebProfilerBundle/composer.json 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Bundle/WebProfilerBundle/composer.json 2026-05-27 08:15:55.000000000 +0000
@@ -18,7 +18,7 @@
"require": {
"php": ">=7.2.5",
"symfony/config": "^4.4|^5.0|^6.0",
- "symfony/framework-bundle": "^5.3|^6.0",
+ "symfony/framework-bundle": "^5.3|^6.0,<6.4",
"symfony/http-kernel": "^5.3|^6.0",
"symfony/polyfill-php80": "^1.16",
"symfony/routing": "^4.4|^5.0|^6.0",
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/.gitattributes symfony-5.4.53+dfsg/src/Symfony/Component/Asset/.gitattributes
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/.gitattributes 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/.gitattributes 2026-05-27 08:15:55.000000000 +0000
@@ -1,4 +1,3 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
-/.gitattributes export-ignore
-/.gitignore export-ignore
+/.git* export-ignore
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/.github/PULL_REQUEST_TEMPLATE.md symfony-5.4.53+dfsg/src/Symfony/Component/Asset/.github/PULL_REQUEST_TEMPLATE.md
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/.github/PULL_REQUEST_TEMPLATE.md 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,8 @@
+Please do not submit any Pull Requests here. They will be closed.
+---
+
+Please submit your PR here instead:
+https://github.com/symfony/symfony
+
+This repository is what we call a "subtree split": a read-only subset of that main repository.
+We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/.github/workflows/close-pull-request.yml symfony-5.4.53+dfsg/src/Symfony/Component/Asset/.github/workflows/close-pull-request.yml
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/.github/workflows/close-pull-request.yml 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/.github/workflows/close-pull-request.yml 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,20 @@
+name: Close Pull Request
+
+on:
+ pull_request_target:
+ types: [opened]
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: superbrothers/close-pull-request@v3
+ with:
+ comment: |
+ Thanks for your Pull Request! We love contributions.
+
+ However, you should instead open your PR on the main repository:
+ https://github.com/symfony/symfony
+
+ This repository is what we call a "subtree split": a read-only subset of that main repository.
+ We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php 2026-05-27 08:15:55.000000000 +0000
@@ -24,7 +24,7 @@
* @param int $code Exception code
* @param \Throwable $previous Previous exception used for the exception chaining
*/
- public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
+ public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Package.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Package.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Package.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Package.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
private $versionStrategy;
private $context;
- public function __construct(VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
+ public function __construct(VersionStrategyInterface $versionStrategy, ?ContextInterface $context = null)
{
$this->versionStrategy = $versionStrategy;
$this->context = $context ?? new NullContext();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Packages.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Packages.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Packages.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Packages.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,7 +28,7 @@
/**
* @param PackageInterface[] $packages Additional packages indexed by name
*/
- public function __construct(PackageInterface $defaultPackage = null, iterable $packages = [])
+ public function __construct(?PackageInterface $defaultPackage = null, iterable $packages = [])
{
$this->defaultPackage = $defaultPackage;
@@ -57,7 +57,7 @@
* @throws InvalidArgumentException If there is no package by that name
* @throws LogicException If no default package is defined
*/
- public function getPackage(string $name = null)
+ public function getPackage(?string $name = null)
{
if (null === $name) {
if (null === $this->defaultPackage) {
@@ -82,7 +82,7 @@
*
* @return string
*/
- public function getVersion(string $path, string $packageName = null)
+ public function getVersion(string $path, ?string $packageName = null)
{
return $this->getPackage($packageName)->getVersion($path);
}
@@ -97,7 +97,7 @@
*
* @return string A public path which takes into account the base path and URL path
*/
- public function getUrl(string $path, string $packageName = null)
+ public function getUrl(string $path, ?string $packageName = null)
{
return $this->getPackage($packageName)->getUrl($path);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/PathPackage.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/PathPackage.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/PathPackage.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/PathPackage.php 2026-05-27 08:15:55.000000000 +0000
@@ -31,7 +31,7 @@
/**
* @param string $basePath The base path to be prepended to relative paths
*/
- public function __construct(string $basePath, VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
+ public function __construct(string $basePath, VersionStrategyInterface $versionStrategy, ?ContextInterface $context = null)
{
parent::__construct($versionStrategy, $context);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Tests/UrlPackageTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Tests/UrlPackageTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/Tests/UrlPackageTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/Tests/UrlPackageTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,13 +25,13 @@
/**
* @dataProvider getConfigs
*/
- public function testGetUrl($baseUrls, $format, $path, $expected)
+ public function testGetUrl($baseUrls, string $format, string $path, string $expected)
{
$package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format));
$this->assertSame($expected, $package->getUrl($path));
}
- public static function getConfigs()
+ public static function getConfigs(): array
{
return [
['http://example.net', '', 'http://example.com/foo', 'http://example.com/foo'],
@@ -65,14 +65,14 @@
/**
* @dataProvider getContextConfigs
*/
- public function testGetUrlWithContext($secure, $baseUrls, $format, $path, $expected)
+ public function testGetUrlWithContext(bool $secure, $baseUrls, string $format, string $path, string $expected)
{
$package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format), $this->getContext($secure));
$this->assertSame($expected, $package->getUrl($path));
}
- public static function getContextConfigs()
+ public static function getContextConfigs(): array
{
return [
[false, 'http://example.com', '', 'foo', 'http://example.com/foo?v1'],
@@ -114,7 +114,7 @@
new UrlPackage($baseUrls, new EmptyVersionStrategy());
}
- public static function getWrongBaseUrlConfig()
+ public static function getWrongBaseUrlConfig(): array
{
return [
['not-a-url'],
@@ -122,7 +122,7 @@
];
}
- private function getContext($secure)
+ private function getContext($secure): ContextInterface
{
$context = $this->createMock(ContextInterface::class);
$context->expects($this->any())->method('isSecure')->willReturn($secure);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/UrlPackage.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/UrlPackage.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/UrlPackage.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/UrlPackage.php 2026-05-27 08:15:55.000000000 +0000
@@ -41,7 +41,7 @@
/**
* @param string|string[] $baseUrls Base asset URLs
*/
- public function __construct($baseUrls, VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
+ public function __construct($baseUrls, VersionStrategyInterface $versionStrategy, ?ContextInterface $context = null)
{
parent::__construct($versionStrategy, $context);
@@ -123,7 +123,7 @@
foreach ($urls as $url) {
if ('https://' === substr($url, 0, 8) || '//' === substr($url, 0, 2)) {
$sslUrls[] = $url;
- } elseif (null === parse_url($url, \PHP_URL_SCHEME)) {
+ } elseif (!parse_url($url, \PHP_URL_SCHEME)) {
throw new InvalidArgumentException(sprintf('"%s" is not a valid URL.', $url));
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php 2026-05-27 08:15:55.000000000 +0000
@@ -40,7 +40,7 @@
* @param string $manifestPath Absolute path to the manifest file
* @param bool $strictMode Throws an exception for unknown paths
*/
- public function __construct(string $manifestPath, HttpClientInterface $httpClient = null, $strictMode = false)
+ public function __construct(string $manifestPath, ?HttpClientInterface $httpClient = null, $strictMode = false)
{
$this->manifestPath = $manifestPath;
$this->httpClient = $httpClient;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php symfony-5.4.53+dfsg/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,7 +25,7 @@
* @param string $version Version number
* @param string $format Url format
*/
- public function __construct(string $version, string $format = null)
+ public function __construct(string $version, ?string $format = null)
{
$this->version = $version;
$this->format = $format ?: '%s?%s';
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/.gitattributes symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/.gitattributes
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/.gitattributes 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/.gitattributes 2026-05-27 08:15:55.000000000 +0000
@@ -1,4 +1,3 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
-/.gitattributes export-ignore
-/.gitignore export-ignore
+/.git* export-ignore
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/.github/PULL_REQUEST_TEMPLATE.md symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/.github/PULL_REQUEST_TEMPLATE.md
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/.github/PULL_REQUEST_TEMPLATE.md 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,8 @@
+Please do not submit any Pull Requests here. They will be closed.
+---
+
+Please submit your PR here instead:
+https://github.com/symfony/symfony
+
+This repository is what we call a "subtree split": a read-only subset of that main repository.
+We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/.github/workflows/close-pull-request.yml symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/.github/workflows/close-pull-request.yml
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/.github/workflows/close-pull-request.yml 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/.github/workflows/close-pull-request.yml 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,20 @@
+name: Close Pull Request
+
+on:
+ pull_request_target:
+ types: [opened]
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: superbrothers/close-pull-request@v3
+ with:
+ comment: |
+ Thanks for your Pull Request! We love contributions.
+
+ However, you should instead open your PR on the main repository:
+ https://github.com/symfony/symfony
+
+ This repository is what we call a "subtree split": a read-only subset of that main repository.
+ We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/AbstractBrowser.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/AbstractBrowser.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/AbstractBrowser.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/AbstractBrowser.php 2026-05-27 08:15:55.000000000 +0000
@@ -50,7 +50,7 @@
/**
* @param array $server The server parameters (equivalent of $_SERVER)
*/
- public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function __construct(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
$this->setServerParameters($server);
$this->history = $history ?? new History();
@@ -146,7 +146,7 @@
return $this->server[$key] ?? $default;
}
- public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler
+ public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], ?string $content = null, bool $changeHistory = true): Crawler
{
$this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
@@ -352,7 +352,7 @@
*
* @return Crawler
*/
- public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true)
+ public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], ?string $content = null, bool $changeHistory = true)
{
if ($this->isMainRequest) {
$this->redirectCount = 0;
@@ -366,11 +366,11 @@
$server = array_merge($this->server, $server);
- if (!empty($server['HTTP_HOST']) && null === parse_url($originalUri, \PHP_URL_HOST)) {
+ if (!empty($server['HTTP_HOST']) && !parse_url($originalUri, \PHP_URL_HOST)) {
$uri = preg_replace('{^(https?\://)'.preg_quote($this->extractHost($uri)).'}', '${1}'.$server['HTTP_HOST'], $uri);
}
- if (isset($server['HTTPS']) && null === parse_url($originalUri, \PHP_URL_SCHEME)) {
+ if (isset($server['HTTPS']) && !parse_url($originalUri, \PHP_URL_SCHEME)) {
$uri = preg_replace('{^'.parse_url($uri, \PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri);
}
@@ -382,7 +382,7 @@
$server['HTTP_HOST'] = $this->extractHost($uri);
}
- $server['HTTPS'] = 'https' == parse_url($uri, \PHP_URL_SCHEME);
+ $server['HTTPS'] = 'https' === parse_url($uri, \PHP_URL_SCHEME);
$this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Cookie.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Cookie.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Cookie.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Cookie.php 2026-05-27 08:15:55.000000000 +0000
@@ -55,7 +55,7 @@
* @param bool $encodedValue Whether the value is encoded or not
* @param string|null $samesite The cookie samesite attribute
*/
- public function __construct(string $name, ?string $value, string $expires = null, string $path = null, string $domain = '', bool $secure = false, bool $httponly = true, bool $encodedValue = false, string $samesite = null)
+ public function __construct(string $name, ?string $value, ?string $expires = null, ?string $path = null, string $domain = '', bool $secure = false, bool $httponly = true, bool $encodedValue = false, ?string $samesite = null)
{
if ($encodedValue) {
$this->value = urldecode($value);
@@ -125,7 +125,7 @@
*
* @throws \InvalidArgumentException
*/
- public static function fromString(string $cookie, string $url = null)
+ public static function fromString(string $cookie, ?string $url = null)
{
$parts = explode(';', $cookie);
@@ -148,7 +148,7 @@
];
if (null !== $url) {
- if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host'])) {
+ if (false === ($urlParts = parse_url($url)) || !isset($urlParts['host'])) {
throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url));
}
@@ -161,7 +161,7 @@
if ('secure' === strtolower($part)) {
// Ignore the secure flag if the original URI is not given or is not HTTPS
- if (!$url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) {
+ if (null === $url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) {
continue;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/CookieJar.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/CookieJar.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/CookieJar.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/CookieJar.php 2026-05-27 08:15:55.000000000 +0000
@@ -35,7 +35,7 @@
*
* @return Cookie|null
*/
- public function get(string $name, string $path = '/', string $domain = null)
+ public function get(string $name, string $path = '/', ?string $domain = null)
{
$this->flushExpiredCookies();
@@ -67,7 +67,7 @@
* all cookies for the given name/path expire (this behavior
* ensures a BC behavior with previous versions of Symfony).
*/
- public function expire(string $name, ?string $path = '/', string $domain = null)
+ public function expire(string $name, ?string $path = '/', ?string $domain = null)
{
if (null === $path) {
$path = '/';
@@ -107,7 +107,7 @@
*
* @param string[] $setCookies Set-Cookie headers from an HTTP response
*/
- public function updateFromSetCookie(array $setCookies, string $uri = null)
+ public function updateFromSetCookie(array $setCookies, ?string $uri = null)
{
$cookies = [];
@@ -133,7 +133,7 @@
/**
* Updates the cookie jar from a Response object.
*/
- public function updateFromResponse(Response $response, string $uri = null)
+ public function updateFromResponse(Response $response, ?string $uri = null)
{
$this->updateFromSetCookie($response->getHeader('Set-Cookie', false), $uri);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/HttpBrowser.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/HttpBrowser.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/HttpBrowser.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/HttpBrowser.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,7 +28,7 @@
{
private $client;
- public function __construct(HttpClientInterface $client = null, History $history = null, CookieJar $cookieJar = null)
+ public function __construct(?HttpClientInterface $client = null, ?History $history = null, ?CookieJar $cookieJar = null)
{
if (!$client && !class_exists(HttpClient::class)) {
throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Request.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Request.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Request.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Request.php 2026-05-27 08:15:55.000000000 +0000
@@ -33,7 +33,7 @@
* @param array $server An array of server parameters
* @param string $content The raw body data
*/
- public function __construct(string $uri, string $method, array $parameters = [], array $files = [], array $cookies = [], array $server = [], string $content = null)
+ public function __construct(string $uri, string $method, array $parameters = [], array $files = [], array $cookies = [], array $server = [], ?string $content = null)
{
$this->uri = $uri;
$this->method = $method;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php 2026-05-27 08:15:55.000000000 +0000
@@ -22,7 +22,7 @@
private $path;
private $domain;
- public function __construct(string $name, string $value, bool $raw = false, string $path = '/', string $domain = null)
+ public function __construct(string $name, string $value, bool $raw = false, string $path = '/', ?string $domain = null)
{
$this->name = $name;
$this->path = $path;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,7 +20,7 @@
private $path;
private $domain;
- public function __construct(string $name, string $path = '/', string $domain = null)
+ public function __construct(string $name, string $path = '/', ?string $domain = null)
{
$this->name = $name;
$this->path = $path;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,7 +20,7 @@
class AbstractBrowserTest extends TestCase
{
- public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function getBrowser(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
return new TestClient($server, $history, $cookieJar);
}
@@ -47,11 +47,12 @@
public function testGetRequestNull()
{
+ $client = $this->getBrowser();
+
$this->expectException(BadMethodCallException::class);
$this->expectExceptionMessage('The "request()" method must be called before "Symfony\\Component\\BrowserKit\\AbstractBrowser::getRequest()".');
- $client = $this->getBrowser();
- $this->assertNull($client->getRequest());
+ $client->getRequest();
}
public function testXmlHttpRequest()
@@ -95,20 +96,22 @@
public function testGetResponseNull()
{
+ $client = $this->getBrowser();
+
$this->expectException(BadMethodCallException::class);
$this->expectExceptionMessage('The "request()" method must be called before "Symfony\\Component\\BrowserKit\\AbstractBrowser::getResponse()".');
- $client = $this->getBrowser();
- $this->assertNull($client->getResponse());
+ $client->getResponse();
}
public function testGetInternalResponseNull()
{
+ $client = $this->getBrowser();
+
$this->expectException(BadMethodCallException::class);
$this->expectExceptionMessage('The "request()" method must be called before "Symfony\\Component\\BrowserKit\\AbstractBrowser::getInternalResponse()".');
- $client = $this->getBrowser();
- $this->assertNull($client->getInternalResponse());
+ $client->getInternalResponse();
}
public function testGetContent()
@@ -131,11 +134,12 @@
public function testGetCrawlerNull()
{
+ $client = $this->getBrowser();
+
$this->expectException(BadMethodCallException::class);
$this->expectExceptionMessage('The "request()" method must be called before "Symfony\\Component\\BrowserKit\\AbstractBrowser::getCrawler()".');
- $client = $this->getBrowser();
- $this->assertNull($client->getCrawler());
+ $client->getCrawler();
}
public function testRequestHttpHeaders()
@@ -384,7 +388,7 @@
$this->assertSame('bar', $server['PHP_AUTH_PW']);
}
- public function testSubmitPassthrewHeaders()
+ public function testSubmitPassthroughHeaders()
{
$client = $this->getBrowser();
$client->setNextResponse(new Response('
'));
@@ -623,7 +627,7 @@
$this->assertSame($expectedEndingUrl, $client->getRequest()->getUri());
}
- public static function getTestsForMetaRefresh()
+ public static function getTestsForMetaRefresh(): array
{
return [
['
', 'http://www.example.com/redirected'],
@@ -844,10 +848,11 @@
public function testInternalRequestNull()
{
+ $client = $this->getBrowser();
+
$this->expectException(BadMethodCallException::class);
$this->expectExceptionMessage('The "request()" method must be called before "Symfony\\Component\\BrowserKit\\AbstractBrowser::getInternalRequest()".');
- $client = $this->getBrowser();
- $this->assertNull($client->getInternalRequest());
+ $client->getInternalRequest();
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -19,7 +19,7 @@
class HttpBrowserTest extends AbstractBrowserTest
{
- public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function getBrowser(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
return new TestHttpClient($server, $history, $cookieJar);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,7 +23,7 @@
protected $nextResponse = null;
protected $nextScript = null;
- public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function __construct(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
$client = new MockHttpClient(function (string $method, string $url, array $options) {
if (null === $this->nextResponse) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/.gitattributes symfony-5.4.53+dfsg/src/Symfony/Component/Cache/.gitattributes
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/.gitattributes 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/.gitattributes 2026-05-27 08:15:55.000000000 +0000
@@ -1,4 +1,3 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
-/.gitattributes export-ignore
-/.gitignore export-ignore
+/.git* export-ignore
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/.github/PULL_REQUEST_TEMPLATE.md symfony-5.4.53+dfsg/src/Symfony/Component/Cache/.github/PULL_REQUEST_TEMPLATE.md
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/.github/PULL_REQUEST_TEMPLATE.md 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,8 @@
+Please do not submit any Pull Requests here. They will be closed.
+---
+
+Please submit your PR here instead:
+https://github.com/symfony/symfony
+
+This repository is what we call a "subtree split": a read-only subset of that main repository.
+We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/.github/workflows/close-pull-request.yml symfony-5.4.53+dfsg/src/Symfony/Component/Cache/.github/workflows/close-pull-request.yml
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/.github/workflows/close-pull-request.yml 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/.github/workflows/close-pull-request.yml 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,20 @@
+name: Close Pull Request
+
+on:
+ pull_request_target:
+ types: [opened]
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: superbrothers/close-pull-request@v3
+ with:
+ comment: |
+ Thanks for your Pull Request! We love contributions.
+
+ However, you should instead open your PR on the main repository:
+ https://github.com/symfony/symfony
+
+ This repository is what we call a "subtree split": a read-only subset of that main repository.
+ We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -101,7 +101,7 @@
*
* @return AdapterInterface
*/
- public static function createSystemCache(string $namespace, int $defaultLifetime, string $version, string $directory, LoggerInterface $logger = null)
+ public static function createSystemCache(string $namespace, int $defaultLifetime, string $version, string $directory, ?LoggerInterface $logger = null)
{
$opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true);
if (null !== $logger) {
@@ -140,7 +140,7 @@
return CouchbaseCollectionAdapter::createConnection($dsn, $options);
}
- throw new InvalidArgumentException(sprintf('Unsupported DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Unsupported DSN: it does not start with "redis[s]:", "memcached:" nor "couchbase:".');
}
/**
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,7 +25,7 @@
/**
* @throws CacheException if APCu is not enabled
*/
- public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null, MarshallerInterface $marshaller = null)
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $version = null, ?MarshallerInterface $marshaller = null)
{
if (!static::isSupported()) {
throw new CacheException('APCu is not enabled.');
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -73,7 +73,7 @@
/**
* {@inheritdoc}
*/
- 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)
{
$item = $this->getItem($key);
$metadata = $item->getMetadata();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ChainAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ChainAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ChainAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -92,7 +92,7 @@
/**
* {@inheritdoc}
*/
- 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)
{
$doSave = true;
$callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) {
@@ -104,7 +104,7 @@
$lastItem = null;
$i = 0;
- $wrap = function (CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$i, &$doSave, &$lastItem, &$metadata) {
+ $wrap = function (?CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$i, &$doSave, &$lastItem, &$metadata) {
$adapter = $this->adapters[$i];
if (isset($this->adapters[++$i])) {
$callback = $wrap;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,7 +39,7 @@
private $bucket;
private $marshaller;
- public function __construct(\CouchbaseBucket $bucket, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct(\CouchbaseBucket $bucket, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
if (!static::isSupported()) {
throw new CacheException('Couchbase >= 2.6.0 < 3.0.0 is required.');
@@ -83,7 +83,7 @@
foreach ($servers as $dsn) {
if (0 !== strpos($dsn, 'couchbase:')) {
- throw new InvalidArgumentException(sprintf('Invalid Couchbase DSN: "%s" does not start with "couchbase:".', $dsn));
+ throw new InvalidArgumentException('Invalid Couchbase DSN: it does not start with "couchbase:".');
}
preg_match($dsnPattern, $dsn, $matches);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -33,7 +33,7 @@
private $connection;
private $marshaller;
- public function __construct(Collection $connection, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct(Collection $connection, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
if (!static::isSupported()) {
throw new CacheException('Couchbase >= 3.0.0 < 4.0.0 is required.');
@@ -79,7 +79,7 @@
foreach ($dsn as $server) {
if (0 !== strpos($server, 'couchbase:')) {
- throw new InvalidArgumentException(sprintf('Invalid Couchbase DSN: "%s" does not start with "couchbase:".', $server));
+ throw new InvalidArgumentException('Invalid Couchbase DSN: it does not start with "couchbase:".');
}
preg_match($dsnPattern, $server, $matches);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -11,13 +11,18 @@
namespace Symfony\Component\Cache\Adapter;
+use Doctrine\DBAL\ArrayParameterType;
+use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\DBAL\ParameterType;
+use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\ServerVersionProvider;
+use Doctrine\DBAL\Tools\DsnParser;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
@@ -56,7 +61,7 @@
*
* @throws InvalidArgumentException When namespace contains invalid characters
*/
- public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
+ public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null)
{
if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
@@ -66,9 +71,30 @@
$this->conn = $connOrDsn;
} elseif (\is_string($connOrDsn)) {
if (!class_exists(DriverManager::class)) {
- throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $connOrDsn));
+ throw new InvalidArgumentException('Failed to parse DSN. Try running "composer require doctrine/dbal".');
}
- $this->conn = DriverManager::getConnection(['url' => $connOrDsn]);
+ if (class_exists(DsnParser::class)) {
+ $params = (new DsnParser([
+ 'db2' => 'ibm_db2',
+ 'mssql' => 'pdo_sqlsrv',
+ 'mysql' => 'pdo_mysql',
+ 'mysql2' => 'pdo_mysql',
+ 'postgres' => 'pdo_pgsql',
+ 'postgresql' => 'pdo_pgsql',
+ 'pgsql' => 'pdo_pgsql',
+ 'sqlite' => 'pdo_sqlite',
+ 'sqlite3' => 'pdo_sqlite',
+ ]))->parse($connOrDsn);
+ } else {
+ $params = ['url' => $connOrDsn];
+ }
+
+ $config = new Configuration();
+ if (class_exists(DefaultSchemaManagerFactory::class)) {
+ $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
+ }
+
+ $this->conn = DriverManager::getConnection($params, $config);
} else {
throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be "%s" or string, "%s" given.', __METHOD__, Connection::class, get_debug_type($connOrDsn)));
}
@@ -156,7 +182,7 @@
$ids,
], [
ParameterType::INTEGER,
- Connection::PARAM_STR_ARRAY,
+ class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY,
])->iterateNumeric();
foreach ($result as $row) {
@@ -174,7 +200,7 @@
$expired,
], [
ParameterType::INTEGER,
- Connection::PARAM_STR_ARRAY,
+ class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY,
]);
}
}
@@ -208,7 +234,8 @@
$sql = "TRUNCATE TABLE $this->table";
}
} else {
- $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'";
+ $namespace = str_replace('_', '!_', $namespace);
+ $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%' ESCAPE '!'";
}
try {
@@ -226,7 +253,7 @@
{
$sql = "DELETE FROM $this->table WHERE $this->idCol IN (?)";
try {
- $this->conn->executeStatement($sql, [array_values($ids)], [Connection::PARAM_STR_ARRAY]);
+ $this->conn->executeStatement($sql, [array_values($ids)], [class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY]);
} catch (TableNotFoundException $e) {
}
@@ -285,35 +312,42 @@
$stmt = $this->conn->prepare($sql);
}
- // $id and $data are defined later in the loop. Binding is done by reference, values are read on execution.
if ('sqlsrv' === $platformName || 'oci' === $platformName) {
- $stmt->bindParam(1, $id);
- $stmt->bindParam(2, $id);
- $stmt->bindParam(3, $data, ParameterType::LARGE_OBJECT);
+ $bind = static function ($id, $data) use ($stmt) {
+ $stmt->bindValue(1, $id);
+ $stmt->bindValue(2, $id);
+ $stmt->bindValue(3, $data, ParameterType::LARGE_OBJECT);
+ $stmt->bindValue(6, $data, ParameterType::LARGE_OBJECT);
+ };
$stmt->bindValue(4, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(5, $now, ParameterType::INTEGER);
- $stmt->bindParam(6, $data, ParameterType::LARGE_OBJECT);
$stmt->bindValue(7, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(8, $now, ParameterType::INTEGER);
} elseif (null !== $platformName) {
- $stmt->bindParam(1, $id);
- $stmt->bindParam(2, $data, ParameterType::LARGE_OBJECT);
+ $bind = static function ($id, $data) use ($stmt) {
+ $stmt->bindValue(1, $id);
+ $stmt->bindValue(2, $data, ParameterType::LARGE_OBJECT);
+ };
$stmt->bindValue(3, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(4, $now, ParameterType::INTEGER);
} else {
- $stmt->bindParam(1, $data, ParameterType::LARGE_OBJECT);
$stmt->bindValue(2, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(3, $now, ParameterType::INTEGER);
- $stmt->bindParam(4, $id);
$insertStmt = $this->conn->prepare($insertSql);
- $insertStmt->bindParam(1, $id);
- $insertStmt->bindParam(2, $data, ParameterType::LARGE_OBJECT);
$insertStmt->bindValue(3, $lifetime, ParameterType::INTEGER);
$insertStmt->bindValue(4, $now, ParameterType::INTEGER);
+
+ $bind = static function ($id, $data) use ($stmt, $insertStmt) {
+ $stmt->bindValue(1, $data, ParameterType::LARGE_OBJECT);
+ $stmt->bindValue(4, $id);
+ $insertStmt->bindValue(1, $id);
+ $insertStmt->bindValue(2, $data, ParameterType::LARGE_OBJECT);
+ };
}
foreach ($values as $id => $data) {
+ $bind($id, $data);
try {
$rowCount = $stmt->executeStatement();
} catch (TableNotFoundException $e) {
@@ -388,12 +422,14 @@
return $this->serverVersion;
}
- $conn = $this->conn->getWrappedConnection();
- if ($conn instanceof ServerInfoAwareConnection) {
- return $this->serverVersion = $conn->getServerVersion();
+ if ($this->conn instanceof ServerVersionProvider || $this->conn instanceof ServerInfoAwareConnection) {
+ return $this->serverVersion = $this->conn->getServerVersion();
}
- return $this->serverVersion = '0';
+ // The condition should be removed once support for DBAL <3.3 is dropped
+ $conn = method_exists($this->conn, 'getNativeConnection') ? $this->conn->getNativeConnection() : $this->conn->getWrappedConnection();
+
+ return $this->serverVersion = $conn->getAttribute(\PDO::ATTR_SERVER_VERSION);
}
private function addTableToSchema(Schema $schema): void
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,7 +20,7 @@
{
use FilesystemTrait;
- public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
parent::__construct('', $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -34,7 +34,7 @@
*/
private const TAG_FOLDER = 'tags';
- public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null)
{
$this->marshaller = new TagAwareMarshaller($marshaller);
parent::__construct('', $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -46,7 +46,7 @@
*
* Using a MemcachedAdapter as a pure items store is fine.
*/
- public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
if (!static::isSupported()) {
throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.');
@@ -109,17 +109,19 @@
continue;
}
if (!str_starts_with($dsn, 'memcached:')) {
- throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s" does not start with "memcached:".', $dsn));
+ throw new InvalidArgumentException('Invalid Memcached DSN: it does not start with "memcached:".');
}
$params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
if (!empty($m[2])) {
[$username, $password] = explode(':', $m[2], 2) + [1 => null];
+ $username = rawurldecode($username);
+ $password = null !== $password ? rawurldecode($password) : null;
}
return 'file:'.($m[1] ?? '');
}, $dsn);
if (false === $params = parse_url($params)) {
- throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Invalid Memcached DSN.');
}
$query = $hosts = [];
if (isset($params['query'])) {
@@ -127,7 +129,7 @@
if (isset($query['host'])) {
if (!\is_array($hosts = $query['host'])) {
- throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Invalid Memcached DSN: query parameter "host" must be an array.');
}
foreach ($hosts as $host => $weight) {
if (false === $port = strrpos($host, ':')) {
@@ -146,7 +148,7 @@
}
}
if (!isset($params['host']) && !isset($params['path'])) {
- throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Invalid Memcached DSN: missing host or path.');
}
if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) {
$params['weight'] = $m[1];
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/NullAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/NullAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/NullAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/NullAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -40,7 +40,7 @@
/**
* {@inheritdoc}
*/
- 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)
{
$save = true;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/PdoAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/PdoAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/PdoAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -34,8 +34,8 @@
private $dataCol = 'item_data';
private $lifetimeCol = 'item_lifetime';
private $timeCol = 'item_time';
- private $username = '';
- private $password = '';
+ private $username = null;
+ private $password = null;
private $connectionOptions = [];
private $namespace;
@@ -62,7 +62,7 @@
* @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
* @throws InvalidArgumentException When namespace contains invalid characters
*/
- public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
+ public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null)
{
if ($connOrDsn instanceof Connection || (\is_string($connOrDsn) && str_contains($connOrDsn, '://'))) {
trigger_deprecation('symfony/cache', '5.4', 'Usage of a DBAL Connection with "%s" is deprecated and will be removed in symfony 6.0. Use "%s" instead.', __CLASS__, DoctrineDbalAdapter::class);
@@ -176,7 +176,7 @@
/**
* {@inheritDoc}
*/
- 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)
{
if (isset($this->dbalAdapter)) {
return $this->dbalAdapter->get($key, $callback, $beta, $metadata);
@@ -432,7 +432,8 @@
$sql = "TRUNCATE TABLE $this->table";
}
} else {
- $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'";
+ $namespace = str_replace('_', '!_', $namespace);
+ $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%' ESCAPE '!'";
}
try {
@@ -507,7 +508,7 @@
try {
$stmt = $conn->prepare($sql);
} catch (\PDOException $e) {
- if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+ if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) {
$this->createTable();
}
$stmt = $conn->prepare($sql);
@@ -542,7 +543,7 @@
try {
$stmt->execute();
} catch (\PDOException $e) {
- if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+ if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) {
$this->createTable();
}
$stmt->execute();
@@ -596,4 +597,21 @@
return $this->serverVersion;
}
+
+ private function isTableMissing(\PDOException $exception): bool
+ {
+ $driver = $this->driver;
+ [$sqlState, $code] = $exception->errorInfo ?? [null, $exception->getCode()];
+
+ switch (true) {
+ case 'pgsql' === $driver && '42P01' === $sqlState:
+ case 'sqlite' === $driver && str_contains($exception->getMessage(), 'no such table:'):
+ case 'oci' === $driver && 942 === $code:
+ case 'sqlsrv' === $driver && 208 === $code:
+ case 'mysql' === $driver && 1146 === $code:
+ return true;
+ default:
+ return false;
+ }
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -83,7 +83,7 @@
/**
* {@inheritdoc}
*/
- 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)
{
if (null === $this->values) {
$this->initialize();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -43,7 +43,7 @@
*
* @throws CacheException if OPcache is not enabled
*/
- public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false)
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, bool $appendOnly = false)
{
$this->appendOnly = $appendOnly;
self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -102,7 +102,7 @@
/**
* {@inheritdoc}
*/
- 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)
{
if (!$this->pool instanceof CacheInterface) {
return $this->doGet($this, $key, $callback, $beta, $metadata);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/RedisAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/RedisAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/RedisAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/RedisAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,7 +25,7 @@
* @param string $namespace The default namespace
* @param int $defaultLifetime The default lifetime
*/
- public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
$this->init($redis, $namespace, $defaultLifetime, $marshaller);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -66,7 +66,7 @@
* @param string $namespace The default namespace
* @param int $defaultLifetime The default lifetime
*/
- public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) {
throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, get_debug_type($redis->getConnection())));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -43,7 +43,7 @@
private static $getTagsByKey;
private static $saveTags;
- public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
+ public function __construct(AdapterInterface $itemsPool, ?AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
{
$this->pool = $itemsPool;
$this->tags = $tagsPool ?: $itemsPool;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php 2026-05-27 08:15:55.000000000 +0000
@@ -38,7 +38,7 @@
/**
* {@inheritdoc}
*/
- 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)
{
if (!$this->pool instanceof CacheInterface) {
throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_debug_type($this->pool), CacheInterface::class));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,7 +39,7 @@
/**
* {@inheritdoc}
*/
- public function collect(Request $request, Response $response, \Throwable $exception = null)
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null)
{
$empty = ['calls' => [], 'config' => [], 'options' => [], 'statistics' => []];
$this->data = ['instances' => $empty, 'total' => $empty];
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php 2026-05-27 08:15:55.000000000 +0000
@@ -209,10 +209,10 @@
}
$notAliasedCacheClearerId = $this->cacheClearerId;
- while ($container->hasAlias($this->cacheClearerId)) {
- $this->cacheClearerId = (string) $container->getAlias($this->cacheClearerId);
+ while ($container->hasAlias($notAliasedCacheClearerId)) {
+ $notAliasedCacheClearerId = (string) $container->getAlias($notAliasedCacheClearerId);
}
- if ($container->hasDefinition($this->cacheClearerId)) {
+ if ($container->hasDefinition($notAliasedCacheClearerId)) {
$clearers[$notAliasedCacheClearerId] = $allPools;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/LockRegistry.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/LockRegistry.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/LockRegistry.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/LockRegistry.php 2026-05-27 08:15:55.000000000 +0000
@@ -84,7 +84,7 @@
return $previousFiles;
}
- public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null)
+ public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, ?\Closure $setMetadata = null, ?LoggerInterface $logger = null)
{
if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
// disable locking on Windows by default
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,7 +23,7 @@
private $useIgbinarySerialize = true;
private $throwOnSerializationFailure;
- public function __construct(bool $useIgbinarySerialize = null, bool $throwOnSerializationFailure = false)
+ public function __construct(?bool $useIgbinarySerialize = null, bool $throwOnSerializationFailure = false)
{
if (null === $useIgbinarySerialize) {
$useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<='));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php 2026-05-27 08:15:55.000000000 +0000
@@ -29,7 +29,7 @@
* more rotating keys can be provided to decrypt values;
* each key must be generated using sodium_crypto_box_keypair()
*/
- public function __construct(array $decryptionKeys, MarshallerInterface $marshaller = null)
+ public function __construct(array $decryptionKeys, ?MarshallerInterface $marshaller = null)
{
if (!self::isSupported()) {
throw new CacheException('The "sodium" PHP extension is not loaded.');
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,7 +20,7 @@
{
private $marshaller;
- public function __construct(MarshallerInterface $marshaller = null)
+ public function __construct(?MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,14 +27,14 @@
private $reverseContainer;
private $callbackWrapper;
- public function __construct(MessageBusInterface $bus, ReverseContainer $reverseContainer, callable $callbackWrapper = null)
+ public function __construct(MessageBusInterface $bus, ReverseContainer $reverseContainer, ?callable $callbackWrapper = null)
{
$this->bus = $bus;
$this->reverseContainer = $reverseContainer;
$this->callbackWrapper = $callbackWrapper;
}
- public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, LoggerInterface $logger = null)
+ public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger = null)
{
if (!$item->isHit() || null === $message = EarlyExpirationMessage::create($this->reverseContainer, $callback, $item, $pool)) {
// The item is stale or the callback cannot be reversed: we must compute the value now
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,7 +25,7 @@
protected static $redis;
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php 2026-05-27 08:15:55.000000000 +0000
@@ -236,7 +236,7 @@
/** @var PruneableInterface|CacheItemPoolInterface $cache */
$cache = $this->createCachePool();
- $doSet = function ($name, $value, \DateInterval $expiresAfter = null) use ($cache) {
+ $doSet = function ($name, $value, ?\DateInterval $expiresAfter = null) use ($cache) {
$item = $cache->getItem($name);
$item->set($value);
@@ -309,6 +309,51 @@
$this->assertTrue($cache->hasItem('barfoo'));
}
+ public function testClearPrefixWithUnderscore()
+ {
+ if (isset($this->skippedTests[__FUNCTION__])) {
+ $this->markTestSkipped($this->skippedTests[__FUNCTION__]);
+ }
+
+ $cache = $this->createCachePool(0, __FUNCTION__);
+ $cache->clear();
+
+ $cache->save($cache->getItem('DC2_REGION_product_region_key')->set(1));
+ $cache->save($cache->getItem('other_key')->set(2));
+
+ $this->assertTrue($cache->clear('DC2_REGION_'));
+ $this->assertFalse($cache->hasItem('DC2_REGION_product_region_key'));
+ $this->assertTrue($cache->hasItem('other_key'));
+ }
+
+ /**
+ * @dataProvider provideInvalidPrefixes
+ */
+ public function testClearWithInvalidPrefix(string $prefix)
+ {
+ if (isset($this->skippedTests[__FUNCTION__])) {
+ $this->markTestSkipped($this->skippedTests[__FUNCTION__]);
+ }
+
+ $cache = $this->createCachePool(0, __FUNCTION__);
+ $cache->clear();
+
+ $cache->save($cache->getItem('foobar')->set(1));
+
+ $this->assertFalse($cache->clear($prefix));
+ $this->assertTrue($cache->hasItem('foobar'));
+ }
+
+ public static function provideInvalidPrefixes(): iterable
+ {
+ yield 'single quote' => ["foo' OR 1=1; --"];
+ yield 'percent wildcard' => ['foo%'];
+ yield 'space' => ['foo bar'];
+ yield 'null byte' => ["foo\0bar"];
+ yield 'backslash' => ['foo\\bar'];
+ yield 'slash' => ['foo/bar'];
+ }
+
public function testWeirdDataMatchingMetadataWrappedValues()
{
if (isset($this->skippedTests[__FUNCTION__])) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -30,7 +30,7 @@
$this->markTestSkipped('APCu extension is required.');
}
if ('cli' === \PHP_SAPI && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
- if ('testWithCliSapi' !== $this->getName()) {
+ if ('testWithCliSapi' !== (method_exists($this, 'name') ? $this->name() : $this->getName())) {
$this->markTestSkipped('apc.enable_cli=1 is required.');
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,6 +23,7 @@
'testGetMetadata' => 'ArrayAdapter does not keep metadata.',
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
+ 'testClearWithInvalidPrefix' => 'ArrayAdapter does not validate the prefix.',
];
public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -30,7 +30,7 @@
*/
class ChainAdapterTest extends AdapterTestCase
{
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod) {
return new ChainAdapter([new FilesystemAdapter('a', $defaultLifetime), new FilesystemAdapter('b', $defaultLifetime)], $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,12 +28,14 @@
{
protected $skippedTests = [
'testClearPrefix' => 'Couchbase cannot clear by prefix',
+ 'testClearPrefixWithUnderscore' => 'Couchbase cannot clear by prefix',
+ 'testClearWithInvalidPrefix' => 'Couchbase cannot clear by prefix',
];
/** @var \CouchbaseBucket */
protected static $client;
- public static function setupBeforeClass(): void
+ public static function setUpBeforeClass(): void
{
if (!CouchbaseBucketAdapter::isSupported()) {
throw new SkippedTestSuiteError('Couchbase >= 2.6.0 < 3.0.0 is required.');
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,12 +28,14 @@
{
protected $skippedTests = [
'testClearPrefix' => 'Couchbase cannot clear by prefix',
+ 'testClearPrefixWithUnderscore' => 'Couchbase cannot clear by prefix',
+ 'testClearWithInvalidPrefix' => 'Couchbase cannot clear by prefix',
];
/** @var Collection */
protected static $client;
- public static function setupBeforeClass(): void
+ public static function setUpBeforeClass(): void
{
if (!CouchbaseCollectionAdapter::isSupported()) {
self::markTestSkipped('Couchbase >= 3.0.0 < 4.0.0 is required.');
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,6 +26,7 @@
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
'testClearPrefix' => 'Doctrine cannot clear by prefix',
+ 'testClearPrefixWithUnderscore' => 'Doctrine cannot clear by prefix',
];
public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -16,13 +16,15 @@
use Doctrine\DBAL\Driver\AbstractMySQLDriver;
use Doctrine\DBAL\Driver\Middleware;
use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\Schema;
-use PHPUnit\Framework\SkippedTestSuiteError;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter;
use Symfony\Component\Cache\Tests\Fixtures\DriverWrapper;
/**
+ * @requires extension pdo_sqlite
+ *
* @group time-sensitive
*/
class DoctrineDbalAdapterTest extends AdapterTestCase
@@ -31,10 +33,6 @@
public static function setUpBeforeClass(): void
{
- if (!\extension_loaded('pdo_sqlite')) {
- throw new SkippedTestSuiteError('Extension pdo_sqlite required.');
- }
-
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
}
@@ -45,12 +43,16 @@
public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface
{
- return new DoctrineDbalAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime);
+ return new DoctrineDbalAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $this->getDbalConfig()), '', $defaultLifetime);
}
public function testConfigureSchemaDecoratedDbalDriver()
{
- $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]);
+ if (file_exists(self::$dbFile)) {
+ @unlink(self::$dbFile);
+ }
+
+ $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $this->getDbalConfig());
if (!interface_exists(Middleware::class)) {
$this->markTestSkipped('doctrine/dbal v2 does not support custom drivers using middleware');
}
@@ -60,7 +62,7 @@
->method('wrap')
->willReturn(new DriverWrapper($connection->getDriver()));
- $config = new Configuration();
+ $config = $this->getDbalConfig();
$config->setMiddlewares([$middleware]);
$connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config);
@@ -75,7 +77,11 @@
public function testConfigureSchema()
{
- $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]);
+ if (file_exists(self::$dbFile)) {
+ @unlink(self::$dbFile);
+ }
+
+ $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $this->getDbalConfig());
$schema = new Schema();
$adapter = new DoctrineDbalAdapter($connection);
@@ -85,6 +91,10 @@
public function testConfigureSchemaDifferentDbalConnection()
{
+ if (file_exists(self::$dbFile)) {
+ @unlink(self::$dbFile);
+ }
+
$otherConnection = $this->createConnectionMock();
$schema = new Schema();
@@ -95,7 +105,11 @@
public function testConfigureSchemaTableExists()
{
- $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]);
+ if (file_exists(self::$dbFile)) {
+ @unlink(self::$dbFile);
+ }
+
+ $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $this->getDbalConfig());
$schema = new Schema();
$schema->createTable('cache_items');
@@ -106,13 +120,12 @@
}
/**
- * @dataProvider provideDsn
+ * @dataProvider provideDsnWithSQLite
*/
- public function testDsn(string $dsn, string $file = null)
+ public function testDsnWithSQLite(string $dsn, ?string $file = null)
{
try {
$pool = new DoctrineDbalAdapter($dsn);
- $pool->createTable();
$item = $pool->getItem('key');
$item->set('value');
@@ -124,12 +137,35 @@
}
}
- public static function provideDsn()
+ public static function provideDsnWithSQLite()
{
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
- yield ['sqlite://localhost/'.$dbFile.'1', $dbFile.'1'];
- yield ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
- yield ['sqlite://localhost/:memory:'];
+ yield 'SQLite file' => ['sqlite://localhost/'.$dbFile.'1', $dbFile.'1'];
+ yield 'SQLite3 file' => ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
+ yield 'SQLite in memory' => ['sqlite://localhost/:memory:'];
+ }
+
+ /**
+ * @requires extension pdo_pgsql
+ *
+ * @group integration
+ */
+ public function testDsnWithPostgreSQL()
+ {
+ if (!$host = getenv('POSTGRES_HOST')) {
+ $this->markTestSkipped('Missing POSTGRES_HOST env variable');
+ }
+
+ try {
+ $pool = new DoctrineDbalAdapter('pgsql://postgres:password@'.$host);
+
+ $item = $pool->getItem('key');
+ $item->set('value');
+ $this->assertTrue($pool->save($item));
+ } finally {
+ $pdo = new \PDO('pgsql:host='.$host.';user=postgres;password=password');
+ $pdo->exec('DROP TABLE IF EXISTS cache_items');
+ }
}
protected function isPruned(DoctrineDbalAdapter $cache, string $name): bool
@@ -155,4 +191,14 @@
return $connection;
}
+
+ private function getDbalConfig()
+ {
+ $config = new Configuration();
+ if (class_exists(DefaultSchemaManagerFactory::class)) {
+ $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
+ }
+
+ return $config;
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,6 +26,8 @@
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
'testClearPrefix' => 'Memcached cannot clear by prefix',
+ 'testClearPrefixWithUnderscore' => 'Memcached cannot clear by prefix',
+ 'testClearWithInvalidPrefix' => 'Memcached cannot clear by prefix',
];
protected static $client;
@@ -44,7 +46,7 @@
}
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null, string $namespace = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null, ?string $namespace = null): CacheItemPoolInterface
{
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')) : self::$client;
@@ -174,33 +176,29 @@
}
/**
- * @dataProvider provideDsnWithOptions
+ * @requires extension memcached
*/
- public function testDsnWithOptions(string $dsn, array $options, array $expectedOptions)
+ public function testOptionsFromDsnWinOverAdditionallyPassedOptions()
{
- $client = MemcachedAdapter::createConnection($dsn, $options);
+ $client = MemcachedAdapter::createConnection('memcached://localhost:11222?retry_timeout=10', [
+ \Memcached::OPT_RETRY_TIMEOUT => 8,
+ ]);
- foreach ($expectedOptions as $option => $expect) {
- $this->assertSame($expect, $client->getOption($option));
- }
+ $this->assertSame(10, $client->getOption(\Memcached::OPT_RETRY_TIMEOUT));
}
- public static function provideDsnWithOptions(): iterable
+ /**
+ * @requires extension memcached
+ */
+ public function testOptionsFromDsnAndAdditionallyPassedOptionsAreMerged()
{
- if (!class_exists(\Memcached::class)) {
- self::markTestSkipped('Extension memcached required.');
- }
+ $client = MemcachedAdapter::createConnection('memcached://localhost:11222?socket_recv_size=1&socket_send_size=2', [
+ \Memcached::OPT_RETRY_TIMEOUT => 8,
+ ]);
- yield [
- 'memcached://localhost:11222?retry_timeout=10',
- [\Memcached::OPT_RETRY_TIMEOUT => 8],
- [\Memcached::OPT_RETRY_TIMEOUT => 10],
- ];
- yield [
- 'memcached://localhost:11222?socket_recv_size=1&socket_send_size=2',
- [\Memcached::OPT_RETRY_TIMEOUT => 8],
- [\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8],
- ];
+ $this->assertSame(1, $client->getOption(\Memcached::OPT_SOCKET_RECV_SIZE));
+ $this->assertSame(2, $client->getOption(\Memcached::OPT_SOCKET_SEND_SIZE));
+ $this->assertSame(8, $client->getOption(\Memcached::OPT_RETRY_TIMEOUT));
}
public function testClear()
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -21,7 +21,7 @@
*/
class NamespacedProxyAdapterTest extends ProxyAdapterTest
{
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod) {
return new ProxyAdapter(new FilesystemAdapter(), 'foo', $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -11,11 +11,12 @@
namespace Symfony\Component\Cache\Tests\Adapter;
-use PHPUnit\Framework\SkippedTestSuiteError;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\PdoAdapter;
/**
+ * @requires extension pdo_sqlite
+ *
* @group time-sensitive
*/
class PdoAdapterTest extends AdapterTestCase
@@ -24,10 +25,6 @@
public static function setUpBeforeClass(): void
{
- if (!\extension_loaded('pdo_sqlite')) {
- throw new SkippedTestSuiteError('Extension pdo_sqlite required.');
- }
-
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
$pool = new PdoAdapter('sqlite:'.self::$dbFile);
@@ -71,13 +68,12 @@
}
/**
- * @dataProvider provideDsn
+ * @dataProvider provideDsnSQLite
*/
- public function testDsn(string $dsn, string $file = null)
+ public function testDsnWithSQLite(string $dsn, ?string $file = null)
{
try {
$pool = new PdoAdapter($dsn);
- $pool->createTable();
$item = $pool->getItem('key');
$item->set('value');
@@ -89,11 +85,36 @@
}
}
- public static function provideDsn()
+ public static function provideDsnSQLite()
{
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
- yield ['sqlite:'.$dbFile.'2', $dbFile.'2'];
- yield ['sqlite::memory:'];
+ yield 'SQLite file' => ['sqlite:'.$dbFile.'2', $dbFile.'2'];
+ yield 'SQLite in memory' => ['sqlite::memory:'];
+ }
+
+ /**
+ * @requires extension pdo_pgsql
+ *
+ * @group integration
+ */
+ public function testDsnWithPostgreSQL()
+ {
+ if (!$host = getenv('POSTGRES_HOST')) {
+ $this->markTestSkipped('Missing POSTGRES_HOST env variable');
+ }
+
+ $dsn = 'pgsql:host='.$host.';user=postgres;password=password';
+
+ try {
+ $pool = new PdoAdapter($dsn);
+
+ $item = $pool->getItem('key');
+ $item->set('value');
+ $this->assertTrue($pool->save($item));
+ } finally {
+ $pdo = new \PDO($dsn);
+ $pdo->exec('DROP TABLE IF EXISTS cache_items');
+ }
}
protected function isPruned(PdoAdapter $cache, string $name): bool
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -16,6 +16,7 @@
use Doctrine\DBAL\Driver\AbstractMySQLDriver;
use Doctrine\DBAL\Driver\Middleware;
use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\Schema;
use PHPUnit\Framework\SkippedTestSuiteError;
use Psr\Cache\CacheItemPoolInterface;
@@ -50,14 +51,16 @@
public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface
{
$this->expectDeprecation('Since symfony/cache 5.4: Usage of a DBAL Connection with "Symfony\Component\Cache\Adapter\PdoAdapter" is deprecated and will be removed in symfony 6.0. Use "Symfony\Component\Cache\Adapter\DoctrineDbalAdapter" instead.');
+ $config = $this->getDbalConfig();
- return new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime);
+ return new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config), '', $defaultLifetime);
}
public function testConfigureSchemaDecoratedDbalDriver()
{
$this->expectDeprecation('Since symfony/cache 5.4: Usage of a DBAL Connection with "Symfony\Component\Cache\Adapter\PdoAdapter" is deprecated and will be removed in symfony 6.0. Use "Symfony\Component\Cache\Adapter\DoctrineDbalAdapter" instead.');
- $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]);
+ $config = $this->getDbalConfig();
+ $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config);
if (!interface_exists(Middleware::class)) {
$this->markTestSkipped('doctrine/dbal v2 does not support custom drivers using middleware');
}
@@ -67,7 +70,6 @@
->method('wrap')
->willReturn(new DriverWrapper($connection->getDriver()));
- $config = new Configuration();
$config->setMiddlewares([$middleware]);
$connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config);
@@ -83,7 +85,8 @@
public function testConfigureSchema()
{
$this->expectDeprecation('Since symfony/cache 5.4: Usage of a DBAL Connection with "Symfony\Component\Cache\Adapter\PdoAdapter" is deprecated and will be removed in symfony 6.0. Use "Symfony\Component\Cache\Adapter\DoctrineDbalAdapter" instead.');
- $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]);
+ $config = $this->getDbalConfig();
+ $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config);
$schema = new Schema();
$adapter = new PdoAdapter($connection);
@@ -104,7 +107,8 @@
public function testConfigureSchemaTableExists()
{
$this->expectDeprecation('Since symfony/cache 5.4: Usage of a DBAL Connection with "Symfony\Component\Cache\Adapter\PdoAdapter" is deprecated and will be removed in symfony 6.0. Use "Symfony\Component\Cache\Adapter\DoctrineDbalAdapter" instead.');
- $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]);
+ $config = $this->getDbalConfig();
+ $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config);
$schema = new Schema();
$schema->createTable('cache_items');
@@ -117,7 +121,7 @@
/**
* @dataProvider provideDsn
*/
- public function testDsn(string $dsn, string $file = null)
+ public function testDsn(string $dsn, ?string $file = null)
{
$this->expectDeprecation('Since symfony/cache 5.4: Usage of a DBAL Connection with "Symfony\Component\Cache\Adapter\PdoAdapter" is deprecated and will be removed in symfony 6.0. Use "Symfony\Component\Cache\Adapter\DoctrineDbalAdapter" instead.');
try {
@@ -168,4 +172,14 @@
return $connection;
}
+
+ private function getDbalConfig(): Configuration
+ {
+ $config = new Configuration();
+ if (class_exists(DefaultSchemaManagerFactory::class)) {
+ $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
+ }
+
+ return $config;
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -57,6 +57,7 @@
'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
'testPrune' => 'PhpArrayAdapter just proxies',
+ 'testClearWithInvalidPrefix' => 'PhpArrayAdapter does not validate the prefix.',
];
protected static $file;
@@ -75,9 +76,9 @@
}
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
- if ('testGetMetadata' === $testMethod || 'testClearPrefix' === $testMethod) {
+ if ('testGetMetadata' === $testMethod || 'testClearPrefix' === $testMethod || 'testClearPrefixWithUnderscore' === $testMethod) {
return new PhpArrayAdapter(self::$file, new FilesystemAdapter());
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
$this->assertInstanceOf(\Predis\Client::class, self::$redis);
$adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
$this->assertInstanceOf(\Predis\Client::class, self::$redis);
$adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -32,7 +32,7 @@
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
}
- public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool($defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime);
}
@@ -66,6 +66,7 @@
$this->assertSame($value, $this->cache->getItem('baz')->get());
sleep(1);
+ usleep(100000);
$this->assertSame($value, $this->cache->getItem('foo')->get());
$this->assertSame($value, $this->cache->getItem('bar')->get());
$this->assertFalse($this->cache->getItem('baz')->isHit());
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,9 +27,10 @@
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
'testPrune' => 'ProxyAdapter just proxies',
+ 'testClearWithInvalidPrefix' => 'Inner ArrayAdapter does not validate the prefix.',
];
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod) {
return new ProxyAdapter(new FilesystemAdapter(), '', $defaultLifetime);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/Psr16AdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/Psr16AdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/Psr16AdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/Psr16AdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,6 +25,7 @@
protected $skippedTests = [
'testPrune' => 'Psr16adapter just proxies',
'testClearPrefix' => 'SimpleCache cannot clear by prefix',
+ 'testClearPrefixWithUnderscore' => 'SimpleCache cannot clear by prefix',
];
public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -33,13 +33,13 @@
throw new SkippedTestSuiteError('REDIS_SENTINEL_SERVICE env var is not defined.');
}
- self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['redis_sentinel' => $service, 'prefix' => 'prefix_']);
+ self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']&timeout=0&retry_interval=0&read_timeout=0', ['redis_sentinel' => $service, 'prefix' => 'prefix_']);
}
public function testInvalidDSNHasBothClusterAndSentinel()
{
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('Cannot use both "redis_cluster" and "redis_sentinel" at the same time:');
+ $this->expectExceptionMessage('Cannot use both "redis_cluster" and "redis_sentinel" at the same time.');
$dsn = 'redis:?host[redis1]&host[redis2]&host[redis3]&redis_cluster=1&redis_sentinel=mymaster';
RedisAdapter::createConnection($dsn);
}
@@ -48,8 +48,8 @@
{
$hosts = getenv('REDIS_SENTINEL_HOSTS');
$dsn = 'redis:?host['.str_replace(' ', ']&host[', $hosts).']';
- $this->expectException(\Symfony\Component\Cache\Exception\InvalidArgumentException::class);
- $this->expectExceptionMessage('Failed to retrieve master information from sentinel "invalid-masterset-name" and dsn "'.$dsn.'".');
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Failed to retrieve master information from sentinel "invalid-masterset-name".');
AbstractAdapter::createConnection($dsn, ['redis_sentinel' => 'invalid-masterset-name']);
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,7 +28,7 @@
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), ['lazy' => true]);
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,7 +20,7 @@
{
public static function setUpBeforeClass(): void
{
- parent::setupBeforeClass();
+ parent::setUpBeforeClass();
if (!class_exists(\RedisArray::class)) {
throw new SkippedTestSuiteError('The RedisArray class is required.');
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -36,7 +36,7 @@
self::$redis->setOption(\Redis::OPT_PREFIX, 'prefix_');
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,7 +28,7 @@
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -28,7 +28,7 @@
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,8 +20,10 @@
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
class CachePoolPassTest extends TestCase
{
@@ -232,4 +234,33 @@
$this->assertInstanceOf(ChildDefinition::class, $doctrineCachePool);
$this->assertSame('cache.app', $doctrineCachePool->getParent());
}
+
+ public function testGlobalClearerAlias()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.container_class', 'app');
+ $container->setParameter('kernel.project_dir', 'foo');
+
+ $container->register('cache.default_clearer', Psr6CacheClearer::class);
+
+ $container->setDefinition('cache.system_clearer', new ChildDefinition('cache.default_clearer'));
+
+ $container->setDefinition('cache.foo_bar_clearer', new ChildDefinition('cache.default_clearer'));
+ $container->setAlias('cache.global_clearer', 'cache.foo_bar_clearer');
+
+ $container->register('cache.adapter.array', ArrayAdapter::class)
+ ->setAbstract(true)
+ ->addTag('cache.pool');
+
+ $cachePool = new ChildDefinition('cache.adapter.array');
+ $cachePool->addTag('cache.pool', ['clearer' => 'cache.system_clearer']);
+ $container->setDefinition('app.cache_pool', $cachePool);
+
+ $this->cachePoolPass->process($container);
+
+ $definition = $container->getDefinition('cache.foo_bar_clearer');
+
+ $this->assertTrue($definition->hasTag('cache.pool.clearer'));
+ $this->assertEquals(['app.cache_pool' => new Reference('app.cache_pool', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)], $definition->getArgument(0));
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php 2026-05-27 08:15:55.000000000 +0000
@@ -15,6 +15,7 @@
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use Doctrine\DBAL\ServerVersionProvider;
class DriverWrapper implements Driver
{
@@ -31,9 +32,9 @@
return $this->driver->connect($params, $username, $password, $driverOptions);
}
- public function getDatabasePlatform(): AbstractPlatform
+ public function getDatabasePlatform(?ServerVersionProvider $versionProvider = null): AbstractPlatform
{
- return $this->driver->getDatabasePlatform();
+ return $this->driver->getDatabasePlatform($versionProvider);
}
public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/LockRegistryTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/LockRegistryTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/LockRegistryTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/LockRegistryTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,7 +23,7 @@
}
$lockFiles = LockRegistry::setFiles([]);
LockRegistry::setFiles($lockFiles);
- $expected = array_map('realpath', glob(__DIR__.'/../Adapter/*'));
+ $expected = array_map('realpath', glob(__DIR__.'/../Adapter/*.php'));
$this->assertSame($expected, $lockFiles);
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Traits/RedisTraitTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Traits/RedisTraitTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Tests/Traits/RedisTraitTest.php 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Tests/Traits/RedisTraitTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,211 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Traits;
+
+use PHPUnit\Framework\SkippedTestSuiteError;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Traits\RedisTrait;
+
+/**
+ * @requires extension redis
+ */
+class RedisTraitTest extends TestCase
+{
+ /**
+ * @dataProvider provideCreateConnection
+ */
+ public function testCreateConnection(string $dsn, string $expectedClass)
+ {
+ if (!class_exists($expectedClass)) {
+ throw new SkippedTestSuiteError(sprintf('The "%s" class is required.', $expectedClass));
+ }
+ if (!getenv('REDIS_CLUSTER_HOSTS')) {
+ throw new SkippedTestSuiteError('REDIS_CLUSTER_HOSTS env var is not defined.');
+ }
+
+ $mock = new class () {
+ use RedisTrait;
+ };
+ $connection = $mock::createConnection($dsn);
+
+ self::assertInstanceOf($expectedClass, $connection);
+ }
+
+ public function testUrlDecodeParameters()
+ {
+ if (!getenv('REDIS_AUTHENTICATED_HOST')) {
+ self::markTestSkipped('REDIS_AUTHENTICATED_HOST env var is not defined.');
+ }
+
+ $mock = new class () {
+ use RedisTrait;
+ };
+ $connection = $mock::createConnection('redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST'));
+
+ self::assertInstanceOf(\Redis::class, $connection);
+ self::assertSame('p@ssword', $connection->getAuth());
+ }
+
+ public static function provideCreateConnection(): array
+ {
+ $hosts = array_map(function ($host) { return sprintf('host[%s]', $host); }, explode(' ', getenv('REDIS_CLUSTER_HOSTS')));
+
+ return [
+ [
+ sprintf('redis:?%s&redis_cluster=1', $hosts[0]),
+ 'RedisCluster',
+ ],
+ [
+ sprintf('redis:?%s&redis_cluster=true', $hosts[0]),
+ 'RedisCluster',
+ ],
+ [
+ sprintf('redis:?%s', $hosts[0]),
+ 'Redis',
+ ],
+ [
+ sprintf('redis:?%s', implode('&', \array_slice($hosts, 0, 2))),
+ 'RedisArray',
+ ],
+ ];
+ }
+
+ /**
+ * Due to a bug in phpredis, the persistent connection will keep its last selected database. So when re-using
+ * a persistent connection, the database has to be re-selected, too.
+ *
+ * @see https://github.com/phpredis/phpredis/issues/1920
+ *
+ * @group integration
+ */
+ public function testPconnectSelectsCorrectDatabase()
+ {
+ if (!class_exists(\Redis::class)) {
+ throw new SkippedTestSuiteError('The "Redis" class is required.');
+ }
+ if (!getenv('REDIS_HOST')) {
+ throw new SkippedTestSuiteError('REDIS_HOST env var is not defined.');
+ }
+ if (!\ini_get('redis.pconnect.pooling_enabled')) {
+ throw new SkippedTestSuiteError('The bug only occurs when pooling is enabled.');
+ }
+
+ // Limit the connection pool size to 1:
+ if (false === $prevPoolSize = ini_set('redis.pconnect.connection_limit', 1)) {
+ throw new SkippedTestSuiteError('Unable to set pool size');
+ }
+
+ try {
+ $mock = new class () {
+ use RedisTrait;
+ };
+
+ $dsn = 'redis://'.getenv('REDIS_HOST');
+
+ $cacheKey = 'testPconnectSelectsCorrectDatabase';
+ $cacheValueOnDb1 = 'I should only be on database 1';
+
+ // First connect to database 1 and set a value there so we can identify this database:
+ $db1 = $mock::createConnection($dsn, ['dbindex' => 1, 'persistent' => 1]);
+ self::assertInstanceOf(\Redis::class, $db1);
+ self::assertSame(1, $db1->getDbNum());
+ $db1->set($cacheKey, $cacheValueOnDb1);
+ self::assertSame($cacheValueOnDb1, $db1->get($cacheKey));
+
+ // Unset the connection - do not use `close()` or we will lose the persistent connection:
+ unset($db1);
+
+ // Now connect to database 0 and see that we do not actually ended up on database 1 by checking the value:
+ $db0 = $mock::createConnection($dsn, ['dbindex' => 0, 'persistent' => 1]);
+ self::assertInstanceOf(\Redis::class, $db0);
+ self::assertSame(0, $db0->getDbNum()); // Redis is lying here! We could actually be on any database!
+ self::assertNotSame($cacheValueOnDb1, $db0->get($cacheKey)); // This value should not exist if we are actually on db 0
+ } finally {
+ ini_set('redis.pconnect.connection_limit', $prevPoolSize);
+ }
+ }
+
+ /**
+ * @dataProvider provideDbIndexDsnParameter
+ */
+ public function testDbIndexDsnParameter(string $dsn, int $expectedDb)
+ {
+ if (!getenv('REDIS_AUTHENTICATED_HOST')) {
+ self::markTestSkipped('REDIS_AUTHENTICATED_HOST env var is not defined.');
+ }
+
+ $mock = new class () {
+ use RedisTrait;
+ };
+ $connection = $mock::createConnection($dsn);
+ self::assertSame($expectedDb, $connection->getDbNum());
+ }
+
+ public static function provideDbIndexDsnParameter(): array
+ {
+ return [
+ [
+ 'redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST'),
+ 0,
+ ],
+ [
+ 'redis:?host['.getenv('REDIS_HOST').']',
+ 0,
+ ],
+ [
+ 'redis:?host['.getenv('REDIS_HOST').']&dbindex=1',
+ 1,
+ ],
+ [
+ 'redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST').'?dbindex=2',
+ 2,
+ ],
+ [
+ 'redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST').'/4',
+ 4,
+ ],
+ [
+ 'redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST').'/?dbindex=5',
+ 5,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideInvalidDbIndexDsnParameter
+ */
+ public function testInvalidDbIndexDsnParameter(string $dsn)
+ {
+ if (!getenv('REDIS_AUTHENTICATED_HOST')) {
+ self::markTestSkipped('REDIS_AUTHENTICATED_HOST env var is not defined.');
+ }
+ $this->expectException(InvalidArgumentException::class);
+
+ $mock = new class () {
+ use RedisTrait;
+ };
+ $mock::createConnection($dsn);
+ }
+
+ public static function provideInvalidDbIndexDsnParameter(): array
+ {
+ return [
+ [
+ 'redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST').'/abc'
+ ],
+ [
+ 'redis://:p%40ssword@'.getenv('REDIS_AUTHENTICATED_HOST').'/3?dbindex=6'
+ ]
+ ];
+ }
+}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php 2026-05-27 08:15:55.000000000 +0000
@@ -143,6 +143,10 @@
$this->namespaceVersion = $namespaceVersion;
$this->ids = [];
}
+ } elseif (preg_match('#[^-+.:_A-Za-z0-9]#', $prefix)) {
+ CacheItem::log($this->logger, 'Failed to clear the cache: Namespace-prefix contains invalid characters.', ['cache-adapter' => get_debug_type($this)]);
+
+ return false;
} else {
$namespaceToClear = $this->namespace.$prefix;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/ContractsTrait.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/ContractsTrait.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/ContractsTrait.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/ContractsTrait.php 2026-05-27 08:15:55.000000000 +0000
@@ -57,7 +57,7 @@
return $previousWrapper;
}
- private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null)
+ private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null)
{
if (0 > $beta = $beta ?? 1.0) {
throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php 2026-05-27 08:15:55.000000000 +0000
@@ -88,8 +88,9 @@
return @unlink($file);
}
- private function write(string $file, string $data, int $expiresAt = null)
+ private function write(string $file, string $data, ?int $expiresAt = null)
{
+ $unlink = false;
set_error_handler(__CLASS__.'::throwError');
try {
if (null === $this->tmp) {
@@ -107,18 +108,31 @@
}
fwrite($h, $data);
fclose($h);
+ $unlink = true;
if (null !== $expiresAt) {
touch($this->tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds
}
- return rename($this->tmp, $file);
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $success = copy($this->tmp, $file);
+ $unlink = true;
+ } else {
+ $success = rename($this->tmp, $file);
+ $unlink = !$success;
+ }
+
+ return $success;
} finally {
restore_error_handler();
+
+ if ($unlink) {
+ @unlink($this->tmp);
+ }
}
}
- private function getFile(string $id, bool $mkdir = false, string $directory = null)
+ private function getFile(string $id, bool $mkdir = false, ?string $directory = null)
{
// Use MD5 to favor speed over security, which is not an issue here
$hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true)));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/RedisTrait.php symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/RedisTrait.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/Traits/RedisTrait.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/Traits/RedisTrait.php 2026-05-27 08:15:55.000000000 +0000
@@ -15,6 +15,8 @@
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\RedisCluster;
use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Connection\Cluster\ClusterInterface as Predis2ClusterInterface;
+use Predis\Connection\Cluster\RedisCluster as Predis2RedisCluster;
use Predis\Response\ErrorInterface;
use Predis\Response\Status;
use Symfony\Component\Cache\Exception\CacheException;
@@ -96,16 +98,16 @@
} elseif (str_starts_with($dsn, 'rediss:')) {
$scheme = 'rediss';
} else {
- throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s" does not start with "redis:" or "rediss".', $dsn));
+ throw new InvalidArgumentException('Invalid Redis DSN: it does not start with "redis[s]:".');
}
if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
- throw new CacheException(sprintf('Cannot find the "redis" extension nor the "predis/predis" package: "%s".', $dsn));
+ throw new CacheException('Cannot find the "redis" extension nor the "predis/predis" package.');
}
$params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) {
if (isset($m[2])) {
- $auth = $m[2];
+ $auth = rawurldecode($m[2]);
if ('' === $auth) {
$auth = null;
@@ -116,7 +118,7 @@
}, $dsn);
if (false === $params = parse_url($params)) {
- throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Invalid Redis DSN.');
}
$query = $hosts = [];
@@ -129,7 +131,7 @@
if (isset($query['host'])) {
if (!\is_array($hosts = $query['host'])) {
- throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Invalid Redis DSN: query parameter "host" must be an array.');
}
foreach ($hosts as $host => $parameters) {
if (\is_string($parameters)) {
@@ -150,10 +152,10 @@
if (isset($params['host']) || isset($params['path'])) {
if (!isset($params['dbindex']) && isset($params['path'])) {
if (preg_match('#/(\d+)?$#', $params['path'], $m)) {
- $params['dbindex'] = $m[1] ?? '0';
+ $params['dbindex'] = $m[1] ?? $query['dbindex'] ?? '0';
$params['path'] = substr($params['path'], 0, -\strlen($m[0]));
} elseif (isset($params['host'])) {
- throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s", the "dbindex" parameter must be a number.', $dsn));
+ throw new InvalidArgumentException('Invalid Redis DSN: parameter "dbindex" must be a number.');
}
}
@@ -165,17 +167,26 @@
}
if (!$hosts) {
- throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
+ throw new InvalidArgumentException('Invalid Redis DSN: missing host.');
+ }
+
+ if (isset($params['dbindex'], $query['dbindex']) && $params['dbindex'] !== $query['dbindex']) {
+ throw new InvalidArgumentException('Invalid Redis DSN: path and query "dbindex" parameters mismatch.');
}
$params += $query + $options + self::$defaultConnectionOptions;
if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class) && !class_exists(\RedisSentinel::class)) {
- throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package or the "redis" extension v5.2 or higher: "%s".', $dsn));
+ throw new CacheException('Redis Sentinel support requires the "predis/predis" package or the "redis" extension v5.2 or higher.');
+ }
+
+ if (isset($params['lazy'])) {
+ $params['lazy'] = filter_var($params['lazy'], \FILTER_VALIDATE_BOOLEAN);
}
+ $params['redis_cluster'] = filter_var($params['redis_cluster'], \FILTER_VALIDATE_BOOLEAN);
if ($params['redis_cluster'] && isset($params['redis_sentinel'])) {
- throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn));
+ throw new InvalidArgumentException('Cannot use both "redis_cluster" and "redis_sentinel" at the same time.');
}
if (null === $params['class'] && \extension_loaded('redis')) {
@@ -184,7 +195,7 @@
$class = $params['class'] ?? \Predis\Client::class;
if (isset($params['redis_sentinel']) && !is_a($class, \Predis\Client::class, true) && !class_exists(\RedisSentinel::class)) {
- throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client" and ext-redis >= 5.2 not found: "%s".', $class, $dsn));
+ throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client" and ext-redis >= 5.2 not found.', $class));
}
}
@@ -192,11 +203,12 @@
$connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect';
$redis = new $class();
- $initializer = static function ($redis) use ($connect, $params, $dsn, $auth, $hosts, $tls) {
+ $initializer = static function ($redis) use ($connect, $params, $auth, $hosts, $tls) {
$hostIndex = 0;
do {
$host = $hosts[$hostIndex]['host'] ?? $hosts[$hostIndex]['path'];
$port = $hosts[$hostIndex]['port'] ?? 0;
+ $passAuth = \defined('Redis::OPT_NULL_MULTIBULK_AS_NULL') && isset($params['auth']);
$address = false;
if (isset($hosts[$hostIndex]['host']) && $tls) {
@@ -206,25 +218,60 @@
if (!isset($params['redis_sentinel'])) {
break;
}
- $extra = [];
- if (\defined('Redis::OPT_NULL_MULTIBULK_AS_NULL') && isset($params['auth'])) {
- $extra = [$params['auth']];
+
+ if (version_compare(phpversion('redis'), '6.0.0', '>=')) {
+ $options = [
+ 'host' => $host,
+ 'port' => $port,
+ 'connectTimeout' => (float) $params['timeout'],
+ 'persistent' => $params['persistent_id'],
+ 'retryInterval' => (int) $params['retry_interval'],
+ 'readTimeout' => (float) $params['read_timeout'],
+ ];
+
+ if ($passAuth) {
+ $options['auth'] = $params['auth'];
+ }
+
+ $sentinel = new \RedisSentinel($options);
+ } else {
+ $extra = $passAuth ? [$params['auth']] : [];
+
+ $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra);
}
- $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra);
- if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) {
- [$host, $port] = $address;
+ try {
+ if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) {
+ [$host, $port] = $address;
+ }
+ } catch (\RedisException $e) {
}
} while (++$hostIndex < \count($hosts) && !$address);
if (isset($params['redis_sentinel']) && !$address) {
- throw new InvalidArgumentException(sprintf('Failed to retrieve master information from sentinel "%s" and dsn "%s".', $params['redis_sentinel'], $dsn));
+ throw new InvalidArgumentException(sprintf('Failed to retrieve master information from sentinel "%s".', $params['redis_sentinel']));
}
try {
$extra = [
'stream' => $params['ssl'] ?? null,
];
+ $booleanStreamOptions = [
+ 'allow_self_signed',
+ 'capture_peer_cert',
+ 'capture_peer_cert_chain',
+ 'disable_compression',
+ 'SNI_enabled',
+ 'verify_peer',
+ 'verify_peer_name',
+ ];
+
+ foreach ($extra['stream'] ?? [] as $streamOption => $value) {
+ if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) {
+ $extra['stream'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL);
+ }
+ }
+
if (isset($params['auth'])) {
$extra['auth'] = $params['auth'];
}
@@ -237,22 +284,25 @@
restore_error_handler();
}
if (!$isConnected) {
- $error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? '', $error) ? sprintf(' (%s)', $error[1]) : '';
- throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$error.'.');
+ $error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? $redis->getLastError() ?? '', $error) ? sprintf(' (%s)', $error[1]) : '';
+ throw new InvalidArgumentException('Redis connection failed: '.$error.'.');
}
if ((null !== $auth && !$redis->auth($auth))
- || ($params['dbindex'] && !$redis->select($params['dbindex']))
+ // Due to a bug in phpredis we must always select the dbindex if persistent pooling is enabled
+ // @see https://github.com/phpredis/phpredis/issues/1920
+ // @see https://github.com/symfony/symfony/issues/51578
+ || (($params['dbindex'] || ('pconnect' === $connect && '0' !== \ini_get('redis.pconnect.pooling_enabled'))) && !$redis->select($params['dbindex']))
) {
$e = preg_replace('/^ERR /', '', $redis->getLastError());
- throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e.'.');
+ throw new InvalidArgumentException('Redis connection failed: '.$e.'.');
}
if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
$redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
}
} catch (\RedisException $e) {
- throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
+ throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
}
return true;
@@ -277,14 +327,14 @@
try {
$redis = new $class($hosts, $params);
} catch (\RedisClusterException $e) {
- throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
+ throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
}
if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
$redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
}
} elseif (is_a($class, \RedisCluster::class, true)) {
- $initializer = static function () use ($class, $params, $dsn, $hosts) {
+ $initializer = static function () use ($class, $params, $hosts) {
foreach ($hosts as $i => $host) {
switch ($host['scheme']) {
case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break;
@@ -296,7 +346,7 @@
try {
$redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', ...\defined('Redis::SCAN_PREFIX') ? [$params['ssl'] ?? null] : []);
} catch (\RedisClusterException $e) {
- throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
+ throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
}
if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
@@ -362,9 +412,6 @@
return $redis;
}
- /**
- * {@inheritdoc}
- */
protected function doFetch(array $ids)
{
if (!$ids) {
@@ -373,7 +420,7 @@
$result = [];
- if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) {
+ if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) {
$values = $this->pipeline(function () use ($ids) {
foreach ($ids as $id) {
yield 'get' => [$id];
@@ -398,17 +445,11 @@
return $result;
}
- /**
- * {@inheritdoc}
- */
protected function doHave(string $id)
{
return (bool) $this->redis->exists($id);
}
- /**
- * {@inheritdoc}
- */
protected function doClear(string $namespace)
{
if ($this->redis instanceof \Predis\ClientInterface) {
@@ -451,7 +492,7 @@
$cursor = null;
do {
- $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000);
+ $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor ?? 0, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000);
if (isset($keys[1]) && \is_array($keys[1])) {
$cursor = $keys[0];
$keys = $keys[1];
@@ -464,22 +505,19 @@
}
$this->doDelete($keys);
}
- } while ($cursor = (int) $cursor);
+ } while ($cursor);
}
return $cleared;
}
- /**
- * {@inheritdoc}
- */
protected function doDelete(array $ids)
{
if (!$ids) {
return true;
}
- if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) {
+ if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) {
static $del;
$del = $del ?? (class_exists(UNLINK::class) ? 'unlink' : 'del');
@@ -507,9 +545,6 @@
return true;
}
- /**
- * {@inheritdoc}
- */
protected function doSave(array $values, int $lifetime)
{
if (!$values = $this->marshaller->marshall($values, $failed)) {
@@ -535,12 +570,12 @@
return $failed;
}
- private function pipeline(\Closure $generator, object $redis = null): \Generator
+ private function pipeline(\Closure $generator, ?object $redis = null): \Generator
{
$ids = [];
$redis = $redis ?? $this->redis;
- if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof RedisCluster)) {
+ if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && ($redis->getConnection() instanceof RedisCluster || $redis->getConnection() instanceof Predis2RedisCluster))) {
// phpredis & predis don't support pipelining with RedisCluster
// see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
// see https://github.com/nrk/predis/issues/267#issuecomment-123781423
@@ -602,7 +637,7 @@
$hosts = [$this->redis];
if ($this->redis instanceof \Predis\ClientInterface) {
$connection = $this->redis->getConnection();
- if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) {
+ if (($connection instanceof ClusterInterface || $connection instanceof Predis2ClusterInterface) && $connection instanceof \Traversable) {
$hosts = [];
foreach ($connection as $c) {
$hosts[] = new \Predis\Client($c);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Cache/composer.json symfony-5.4.53+dfsg/src/Symfony/Component/Cache/composer.json
--- symfony-5.4.23+dfsg/src/Symfony/Component/Cache/composer.json 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Cache/composer.json 2026-05-27 08:15:55.000000000 +0000
@@ -34,8 +34,8 @@
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "^1.6|^2.0",
- "doctrine/dbal": "^2.13.1|^3.0",
- "predis/predis": "^1.1",
+ "doctrine/dbal": "^2.13.1|^3|^4",
+ "predis/predis": "^1.1|^2.0",
"psr/simple-cache": "^1.0|^2.0",
"symfony/config": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/.gitattributes symfony-5.4.53+dfsg/src/Symfony/Component/Config/.gitattributes
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/.gitattributes 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/.gitattributes 2026-05-27 08:15:55.000000000 +0000
@@ -1,4 +1,3 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
-/.gitattributes export-ignore
-/.gitignore export-ignore
+/.git* export-ignore
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/.github/PULL_REQUEST_TEMPLATE.md symfony-5.4.53+dfsg/src/Symfony/Component/Config/.github/PULL_REQUEST_TEMPLATE.md
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/.github/PULL_REQUEST_TEMPLATE.md 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,8 @@
+Please do not submit any Pull Requests here. They will be closed.
+---
+
+Please submit your PR here instead:
+https://github.com/symfony/symfony
+
+This repository is what we call a "subtree split": a read-only subset of that main repository.
+We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/.github/workflows/close-pull-request.yml symfony-5.4.53+dfsg/src/Symfony/Component/Config/.github/workflows/close-pull-request.yml
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/.github/workflows/close-pull-request.yml 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/.github/workflows/close-pull-request.yml 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,20 @@
+name: Close Pull Request
+
+on:
+ pull_request_target:
+ types: [opened]
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: superbrothers/close-pull-request@v3
+ with:
+ comment: |
+ Thanks for your Pull Request! We love contributions.
+
+ However, you should instead open your PR on the main repository:
+ https://github.com/symfony/symfony
+
+ This repository is what we call a "subtree split": a read-only subset of that main repository.
+ We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Builder/ClassBuilder.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Builder/ClassBuilder.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Builder/ClassBuilder.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Builder/ClassBuilder.php 2026-05-27 08:15:55.000000000 +0000
@@ -122,7 +122,7 @@
$this->methods[] = new Method(strtr($body, ['NAME' => $this->camelCase($name)] + $params));
}
- public function addProperty(string $name, string $classType = null, string $defaultValue = null): Property
+ public function addProperty(string $name, ?string $classType = null, ?string $defaultValue = null): Property
{
$property = new Property($name, '_' !== $name[0] ? $this->camelCase($name) : $name);
if (null !== $classType) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/ConfigCacheInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/ConfigCacheInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/ConfigCacheInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/ConfigCacheInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -45,5 +45,5 @@
*
* @throws \RuntimeException When the cache file cannot be written
*/
- public function write(string $content, array $metadata = null);
+ public function write(string $content, ?array $metadata = null);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/BaseNode.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/BaseNode.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/BaseNode.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/BaseNode.php 2026-05-27 08:15:55.000000000 +0000
@@ -45,7 +45,7 @@
/**
* @throws \InvalidArgumentException if the name contains a period
*/
- public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR)
+ public function __construct(?string $name, ?NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR)
{
if (str_contains($name = (string) $name, $pathSeparator)) {
throw new \InvalidArgumentException('The name must not contain ".'.$pathSeparator.'".');
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,7 +39,7 @@
/**
* {@inheritdoc}
*/
- public function __construct(?string $name, NodeParentInterface $parent = null)
+ public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
@@ -197,7 +197,7 @@
*
* @return $this
*/
- public function fixXmlConfig(string $singular, string $plural = null)
+ public function fixXmlConfig(string $singular, ?string $plural = null)
{
$this->normalization()->remap($singular, $plural);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php 2026-05-27 08:15:55.000000000 +0000
@@ -24,7 +24,7 @@
/**
* {@inheritdoc}
*/
- public function __construct(?string $name, NodeParentInterface $parent = null)
+ public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php 2026-05-27 08:15:55.000000000 +0000
@@ -35,7 +35,7 @@
*
* @return $this
*/
- public function always(\Closure $then = null)
+ public function always(?\Closure $then = null)
{
$this->ifPart = function () { return true; };
@@ -53,7 +53,7 @@
*
* @return $this
*/
- public function ifTrue(\Closure $closure = null)
+ public function ifTrue(?\Closure $closure = null)
{
if (null === $closure) {
$closure = function ($v) { return true === $v; };
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,7 +39,7 @@
*
* @return $this
*/
- public function setParent(ParentNodeDefinitionInterface $parent = null)
+ public function setParent(?ParentNodeDefinitionInterface $parent = null)
{
$this->parent = $parent;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php 2026-05-27 08:15:55.000000000 +0000
@@ -38,7 +38,7 @@
protected $parent;
protected $attributes = [];
- public function __construct(?string $name, NodeParentInterface $parent = null)
+ public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
$this->parent = $parent;
$this->name = $name;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php 2026-05-27 08:15:55.000000000 +0000
@@ -35,7 +35,7 @@
*
* @return $this
*/
- public function remap(string $key, string $plural = null)
+ public function remap(string $key, ?string $plural = null)
{
$this->remappings[] = [$key, null === $plural ? $key.'s' : $plural];
@@ -47,7 +47,7 @@
*
* @return ExprBuilder|$this
*/
- public function before(\Closure $closure = null)
+ public function before(?\Closure $closure = null)
{
if (null !== $closure) {
$this->before[] = $closure;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,7 +23,7 @@
protected $tree;
protected $root;
- public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null)
+ public function __construct(string $name, string $type = 'array', ?NodeBuilder $builder = null)
{
$builder = $builder ?? new NodeBuilder();
$this->root = $builder->node($name, $type)->setParent($this);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php 2026-05-27 08:15:55.000000000 +0000
@@ -31,7 +31,7 @@
*
* @return ExprBuilder|$this
*/
- public function rule(\Closure $closure = null)
+ public function rule(?\Closure $closure = null)
{
if (null !== $closure) {
$this->rules[] = $closure;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,12 +27,12 @@
{
private $reference;
- public function dump(ConfigurationInterface $configuration, string $namespace = null)
+ public function dump(ConfigurationInterface $configuration, ?string $namespace = null)
{
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
}
- public function dumpNode(NodeInterface $node, string $namespace = null)
+ public function dumpNode(NodeInterface $node, ?string $namespace = null)
{
$this->reference = '';
$this->writeNode($node, 0, true, $namespace);
@@ -42,7 +42,7 @@
return $ref;
}
- private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null)
+ private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, ?string $namespace = null)
{
$rootName = ($root ? 'config' : $node->getName());
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php 2026-05-27 08:15:55.000000000 +0000
@@ -18,7 +18,6 @@
use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\Config\Definition\ScalarNode;
-use Symfony\Component\Config\Definition\VariableNode;
use Symfony\Component\Yaml\Inline;
/**
@@ -71,7 +70,7 @@
return $ref;
}
- private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false)
+ private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false)
{
$comments = [];
$default = '';
@@ -90,19 +89,12 @@
$children = $this->getPrototypeChildren($node);
}
- if (!$children) {
- if ($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue())) {
- $default = '';
- } elseif (!\is_array($example)) {
- $default = '[]';
- }
+ if (!$children && !($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue()))) {
+ $default = '[]';
}
} elseif ($node instanceof EnumNode) {
$comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
$default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~';
- } elseif (VariableNode::class === \get_class($node) && \is_array($example)) {
- // If there is an array example, we are sure we dont need to print a default value
- $default = '';
} else {
$default = '~';
@@ -170,7 +162,7 @@
$this->writeLine('# '.$message.':', $depth * 4 + 4);
- $this->writeArray(array_map([Inline::class, 'dump'], $example), $depth + 1);
+ $this->writeArray(array_map([Inline::class, 'dump'], $example), $depth + 1, true);
}
if ($children) {
@@ -191,7 +183,7 @@
$this->reference .= sprintf($format, $text)."\n";
}
- private function writeArray(array $array, int $depth)
+ private function writeArray(array $array, int $depth, bool $asComment = false)
{
$isIndexed = array_values($array) === $array;
@@ -202,14 +194,16 @@
$val = $value;
}
+ $prefix = $asComment ? '# ' : '';
+
if ($isIndexed) {
- $this->writeLine('- '.$val, $depth * 4);
+ $this->writeLine($prefix.'- '.$val, $depth * 4);
} else {
- $this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
+ $this->writeLine(sprintf('%s%-20s %s', $prefix, $key.':', $val), $depth * 4);
}
if (\is_array($value)) {
- $this->writeArray($value, $depth + 1);
+ $this->writeArray($value, $depth + 1, $asComment);
}
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/EnumNode.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/EnumNode.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/EnumNode.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/EnumNode.php 2026-05-27 08:15:55.000000000 +0000
@@ -22,7 +22,7 @@
{
private $values;
- public function __construct(?string $name, NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
+ public function __construct(?string $name, ?NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
$values = array_unique($values);
if (empty($values)) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/NumericNode.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/NumericNode.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/NumericNode.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/NumericNode.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
* @param int|float|null $min
* @param int|float|null $max
*/
- public function __construct(?string $name, NodeInterface $parent = null, $min = null, $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
+ public function __construct(?string $name, ?NodeInterface $parent = null, $min = null, $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
parent::__construct($name, $parent, $pathSeparator);
$this->min = $min;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Processor.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Processor.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Definition/Processor.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Definition/Processor.php 2026-05-27 08:15:55.000000000 +0000
@@ -67,7 +67,7 @@
* @param string $key The key to normalize
* @param string|null $plural The plural form of the key if it is irregular
*/
- public static function normalizeConfig(array $config, string $key, string $plural = null): array
+ public static function normalizeConfig(array $config, string $key, ?string $plural = null): array
{
if (null === $plural) {
$plural = $key.'s';
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php 2026-05-27 08:15:55.000000000 +0000
@@ -18,7 +18,7 @@
*/
class FileLoaderImportCircularReferenceException extends LoaderLoadException
{
- public function __construct(array $resources, ?int $code = 0, \Throwable $previous = null)
+ public function __construct(array $resources, ?int $code = 0, ?\Throwable $previous = null)
{
if (null === $code) {
trigger_deprecation('symfony/config', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php 2026-05-27 08:15:55.000000000 +0000
@@ -20,7 +20,7 @@
{
private $paths;
- public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, array $paths = [])
+ public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, array $paths = [])
{
parent::__construct($message, $code, $previous);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Exception/LoaderLoadException.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Exception/LoaderLoadException.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Exception/LoaderLoadException.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Exception/LoaderLoadException.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,7 +25,7 @@
* @param \Throwable|null $previous A previous exception
* @param string|null $type The type of resource
*/
- public function __construct(string $resource, string $sourceResource = null, ?int $code = 0, \Throwable $previous = null, string $type = null)
+ public function __construct(string $resource, ?string $sourceResource = null, ?int $code = 0, ?\Throwable $previous = null, ?string $type = null)
{
if (null === $code) {
trigger_deprecation('symfony/config', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/FileLocator.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/FileLocator.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/FileLocator.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/FileLocator.php 2026-05-27 08:15:55.000000000 +0000
@@ -33,7 +33,7 @@
/**
* {@inheritdoc}
*/
- public function locate(string $name, string $currentPath = null, bool $first = true)
+ public function locate(string $name, ?string $currentPath = null, bool $first = true)
{
if ('' === $name) {
throw new \InvalidArgumentException('An empty file name is not valid to be located.');
@@ -84,7 +84,8 @@
&& ':' === $file[1]
&& ('\\' === $file[2] || '/' === $file[2])
)
- || null !== parse_url($file, \PHP_URL_SCHEME)
+ || parse_url($file, \PHP_URL_SCHEME)
+ || str_starts_with($file, 'phar:///') // "parse_url()" doesn't handle absolute phar path, despite being valid
) {
return true;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/FileLocatorInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/FileLocatorInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/FileLocatorInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/FileLocatorInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -30,5 +30,5 @@
* @throws \InvalidArgumentException If $name is empty
* @throws FileLocatorFileNotFoundException If a file is not found
*/
- public function locate(string $name, string $currentPath = null, bool $first = true);
+ public function locate(string $name, ?string $currentPath = null, bool $first = true);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/DelegatingLoader.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/DelegatingLoader.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/DelegatingLoader.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/DelegatingLoader.php 2026-05-27 08:15:55.000000000 +0000
@@ -31,7 +31,7 @@
/**
* {@inheritdoc}
*/
- public function load($resource, string $type = null)
+ public function load($resource, ?string $type = null)
{
if (false === $loader = $this->resolver->resolve($resource, $type)) {
throw new LoaderLoadException($resource, null, 0, null, $type);
@@ -43,7 +43,7 @@
/**
* {@inheritdoc}
*/
- public function supports($resource, string $type = null)
+ public function supports($resource, ?string $type = null)
{
return false !== $this->resolver->resolve($resource, $type);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/FileLoader.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/FileLoader.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/FileLoader.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/FileLoader.php 2026-05-27 08:15:55.000000000 +0000
@@ -31,7 +31,7 @@
private $currentDir;
- public function __construct(FileLocatorInterface $locator, string $env = null)
+ public function __construct(FileLocatorInterface $locator, ?string $env = null)
{
$this->locator = $locator;
parent::__construct($env);
@@ -70,7 +70,7 @@
* @throws FileLoaderImportCircularReferenceException
* @throws FileLocatorFileNotFoundException
*/
- public function import($resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null, $exclude = null)
+ public function import($resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null, $exclude = null)
{
if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) {
$excluded = [];
@@ -133,7 +133,7 @@
yield from $resource;
}
- private function doImport($resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null)
+ private function doImport($resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null)
{
try {
$loader = $this->resolve($resource, $type);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/GlobFileLoader.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/GlobFileLoader.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/GlobFileLoader.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/GlobFileLoader.php 2026-05-27 08:15:55.000000000 +0000
@@ -21,7 +21,7 @@
/**
* {@inheritdoc}
*/
- public function load($resource, string $type = null)
+ public function load($resource, ?string $type = null)
{
return $this->import($resource);
}
@@ -29,7 +29,7 @@
/**
* {@inheritdoc}
*/
- public function supports($resource, string $type = null)
+ public function supports($resource, ?string $type = null)
{
return 'glob' === $type;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/Loader.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/Loader.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/Loader.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/Loader.php 2026-05-27 08:15:55.000000000 +0000
@@ -23,7 +23,7 @@
protected $resolver;
protected $env;
- public function __construct(string $env = null)
+ public function __construct(?string $env = null)
{
$this->env = $env;
}
@@ -52,7 +52,7 @@
*
* @return mixed
*/
- public function import($resource, string $type = null)
+ public function import($resource, ?string $type = null)
{
return $this->resolve($resource, $type)->load($resource, $type);
}
@@ -67,7 +67,7 @@
*
* @throws LoaderLoadException If no loader is found
*/
- public function resolve($resource, string $type = null)
+ public function resolve($resource, ?string $type = null)
{
if ($this->supports($resource, $type)) {
return $this;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/LoaderInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/LoaderInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/LoaderInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/LoaderInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
*
* @throws \Exception If something went wrong
*/
- public function load($resource, string $type = null);
+ public function load($resource, ?string $type = null);
/**
* Returns whether this class supports the given resource.
@@ -36,7 +36,7 @@
*
* @return bool
*/
- public function supports($resource, string $type = null);
+ public function supports($resource, ?string $type = null);
/**
* Gets the loader resolver.
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/LoaderResolver.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/LoaderResolver.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/LoaderResolver.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/LoaderResolver.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,7 +39,7 @@
/**
* {@inheritdoc}
*/
- public function resolve($resource, string $type = null)
+ public function resolve($resource, ?string $type = null)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource, $type)) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,5 +26,5 @@
*
* @return LoaderInterface|false
*/
- public function resolve($resource, string $type = null);
+ public function resolve($resource, ?string $type = null);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Resource/ClassExistenceResource.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Resource/ClassExistenceResource.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Resource/ClassExistenceResource.php 2026-05-27 08:15:55.000000000 +0000
@@ -34,7 +34,7 @@
* @param string $resource The fully-qualified class name
* @param bool|null $exists Boolean when the existence check has already been done
*/
- public function __construct(string $resource, bool $exists = null)
+ public function __construct(string $resource, ?bool $exists = null)
{
$this->resource = $resource;
if (null !== $exists) {
@@ -143,7 +143,7 @@
*
* @internal
*/
- public static function throwOnRequiredClass(string $class, \Exception $previous = null)
+ public static function throwOnRequiredClass(string $class, ?\Exception $previous = null)
{
// If the passed class is the resource being checked, we shouldn't throw.
if (null === $previous && self::$autoloadedClass === $class) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Resource/DirectoryResource.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Resource/DirectoryResource.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Resource/DirectoryResource.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Resource/DirectoryResource.php 2026-05-27 08:15:55.000000000 +0000
@@ -29,7 +29,7 @@
*
* @throws \InvalidArgumentException
*/
- public function __construct(string $resource, string $pattern = null)
+ public function __construct(string $resource, ?string $pattern = null)
{
$this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
$this->pattern = $pattern;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Resource/FileExistenceResource.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Resource/FileExistenceResource.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Resource/FileExistenceResource.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Resource/FileExistenceResource.php 2026-05-27 08:15:55.000000000 +0000
@@ -38,7 +38,7 @@
public function __toString(): string
{
- return $this->resource;
+ return 'existence.'.$this->resource;
}
public function getResource(): string
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/ResourceCheckerConfigCache.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/ResourceCheckerConfigCache.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/ResourceCheckerConfigCache.php 2026-05-27 08:15:55.000000000 +0000
@@ -115,7 +115,7 @@
*
* @throws \RuntimeException When cache file can't be written
*/
- public function write(string $content, array $metadata = null)
+ public function write(string $content, ?array $metadata = null)
{
$mode = 0666;
$umask = umask();
@@ -156,7 +156,7 @@
$signalingException = new \UnexpectedValueException();
$prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) {
- if (__FILE__ === $file) {
+ if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) {
throw $signalingException;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -160,7 +160,7 @@
/**
* Generate the ConfigBuilder or return an already generated instance.
*/
- private function generateConfigBuilder(string $configurationClass, string $outputDir = null)
+ private function generateConfigBuilder(string $configurationClass, ?string $outputDir = null)
{
$outputDir ?? $outputDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true);
if (!str_contains($outputDir, __DIR__)) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/ConfigCacheTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/ConfigCacheTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/ConfigCacheTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/ConfigCacheTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -72,7 +72,7 @@
{
$p = (new \ReflectionClass(SelfCheckingResourceChecker::class))->getProperty('cache');
$p->setAccessible(true);
- $p->setValue(SelfCheckingResourceChecker::class, []);
+ $p->setValue(null, []);
$freshResource = new ResourceStub();
$freshResource->setFresh(true);
@@ -87,7 +87,7 @@
{
$p = (new \ReflectionClass(SelfCheckingResourceChecker::class))->getProperty('cache');
$p->setAccessible(true);
- $p->setValue(SelfCheckingResourceChecker::class, []);
+ $p->setValue(null, []);
$staleResource = new ResourceStub();
$staleResource->setFresh(false);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/BaseNodeTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/BaseNodeTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/BaseNodeTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/BaseNodeTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -36,7 +36,36 @@
}
}
- $node = $this->getMockForAbstractClass(BaseNode::class, $constructorArgs);
+ $node = new class(...$constructorArgs) extends BaseNode {
+ protected function validateType($value): void
+ {
+ }
+
+ protected function normalizeValue($value)
+ {
+ return null;
+ }
+
+ protected function mergeValues($leftSide, $rightSide)
+ {
+ return null;
+ }
+
+ protected function finalizeValue($value)
+ {
+ return null;
+ }
+
+ public function hasDefaultValue(): bool
+ {
+ return true;
+ }
+
+ public function getDefaultValue()
+ {
+ return null;
+ }
+ };
$this->assertSame($expected, $node->getPath());
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -223,7 +223,7 @@
* @param array|null $config The config you want to use for the finalization, if nothing provided
* a simple ['key'=>'value'] will be used
*/
- protected function finalizeTestBuilder(NodeDefinition $nodeDefinition, array $config = null): array
+ protected function finalizeTestBuilder(NodeDefinition $nodeDefinition, ?array $config = null): array
{
return $nodeDefinition
->end()
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -109,6 +109,8 @@
+
+
EOL
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -114,11 +114,11 @@
# which should be indented
child3: ~ # Example: 'example setting'
scalar_prototyped: []
- variable:
+ variable: ~
# Examples:
- - foo
- - bar
+ # - foo
+ # - bar
parameters:
# Prototype: Parameter name
@@ -142,6 +142,11 @@
# Prototype
name: []
+ array_with_array_example_and_no_default_value: []
+
+ # Examples:
+ # - foo
+ # - bar
custom_node: true
EOL;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/FileLocatorTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/FileLocatorTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/FileLocatorTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/FileLocatorTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,6 +39,7 @@
['\\server\\foo.xml'],
['https://server/foo.xml'],
['phar://server/foo.xml'],
+ ['phar:///server/foo.xml'],
];
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php 2026-05-27 08:15:55.000000000 +0000
@@ -96,6 +96,9 @@
->end()
->end()
->end()
+ ->arrayNode('array_with_array_example_and_no_default_value')
+ ->example(['foo', 'bar'])
+ ->end()
->append(new CustomNodeDefinition('acme'))
->end()
;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,13 +25,15 @@
$locatorMock = $this->createMock(FileLocatorInterface::class);
$locatorMockForAdditionalLoader = $this->createMock(FileLocatorInterface::class);
- $locatorMockForAdditionalLoader->expects($this->any())->method('locate')->will($this->onConsecutiveCalls(
- ['path/to/file1'], // Default
- ['path/to/file1', 'path/to/file2'], // First is imported
- ['path/to/file1', 'path/to/file2'], // Second is imported
- ['path/to/file1'], // Exception
- ['path/to/file1', 'path/to/file2'] // Exception
- ));
+ $locatorMockForAdditionalLoader->expects($this->any())
+ ->method('locate')
+ ->willReturn(
+ ['path/to/file1'],
+ ['path/to/file1', 'path/to/file2'],
+ ['path/to/file1', 'path/to/file2'],
+ ['path/to/file1'],
+ ['path/to/file1', 'path/to/file2']
+ );
$fileLoader = new TestFileLoader($locatorMock);
$fileLoader->setSupports(false);
@@ -155,12 +157,12 @@
{
private $supports = true;
- public function load($resource, string $type = null)
+ public function load($resource, ?string $type = null)
{
return $resource;
}
- public function supports($resource, string $type = null): bool
+ public function supports($resource, ?string $type = null): bool
{
return $this->supports;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -104,11 +104,11 @@
class ProjectLoader1 extends Loader
{
- public function load($resource, string $type = null)
+ public function load($resource, ?string $type = null)
{
}
- public function supports($resource, string $type = null): bool
+ public function supports($resource, ?string $type = null): bool
{
return \is_string($resource) && 'foo' === pathinfo($resource, \PATHINFO_EXTENSION);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Resource/FileExistenceResourceTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Resource/FileExistenceResourceTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Resource/FileExistenceResourceTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Resource/FileExistenceResourceTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -36,7 +36,7 @@
public function testToString()
{
- $this->assertSame($this->file, (string) $this->resource);
+ $this->assertSame('existence.'.$this->file, (string) $this->resource);
}
public function testGetResource()
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -64,7 +64,7 @@
/**
* @dataProvider provideHashedSignature
*/
- public function testHashedSignature(bool $changeExpected, int $changedLine, ?string $changedCode, \Closure $setContext = null)
+ public function testHashedSignature(bool $changeExpected, int $changedLine, ?string $changedCode, ?\Closure $setContext = null)
{
if ($setContext) {
$setContext();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -76,7 +76,8 @@
}
$mock = $this->createMock(Validator::class);
- $mock->expects($this->exactly(2))->method('validate')->will($this->onConsecutiveCalls(false, true));
+ $mock->expects($this->exactly(2))->method('validate')
+ ->willReturn(false, true);
try {
XmlUtils::loadFile($fixtures.'valid.xml', [$mock, 'validate']);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/.gitattributes symfony-5.4.53+dfsg/src/Symfony/Component/Console/.gitattributes
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/.gitattributes 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/.gitattributes 2026-05-27 08:15:55.000000000 +0000
@@ -1,4 +1,3 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
-/.gitattributes export-ignore
-/.gitignore export-ignore
+/.git* export-ignore
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/.github/PULL_REQUEST_TEMPLATE.md symfony-5.4.53+dfsg/src/Symfony/Component/Console/.github/PULL_REQUEST_TEMPLATE.md
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/.github/PULL_REQUEST_TEMPLATE.md 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,8 @@
+Please do not submit any Pull Requests here. They will be closed.
+---
+
+Please submit your PR here instead:
+https://github.com/symfony/symfony
+
+This repository is what we call a "subtree split": a read-only subset of that main repository.
+We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/.github/workflows/close-pull-request.yml symfony-5.4.53+dfsg/src/Symfony/Component/Console/.github/workflows/close-pull-request.yml
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/.github/workflows/close-pull-request.yml 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/.github/workflows/close-pull-request.yml 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,20 @@
+name: Close Pull Request
+
+on:
+ pull_request_target:
+ types: [opened]
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: superbrothers/close-pull-request@v3
+ with:
+ comment: |
+ Thanks for your Pull Request! We love contributions.
+
+ However, you should instead open your PR on the main repository:
+ https://github.com/symfony/symfony
+
+ This repository is what we call a "subtree split": a read-only subset of that main repository.
+ We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Application.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Application.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Application.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Application.php 2026-05-27 08:15:55.000000000 +0000
@@ -134,7 +134,7 @@
*
* @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}.
*/
- public function run(InputInterface $input = null, OutputInterface $output = null)
+ public function run(?InputInterface $input = null, ?OutputInterface $output = null)
{
if (\function_exists('putenv')) {
@putenv('LINES='.$this->terminal->getHeight());
@@ -165,9 +165,9 @@
}
}
- $this->configureIO($input, $output);
-
try {
+ $this->configureIO($input, $output);
+
$exitCode = $this->doRun($input, $output);
} catch (\Exception $e) {
if (!$this->catchExceptions) {
@@ -778,7 +778,7 @@
*
* @return Command[]
*/
- public function all(string $namespace = null)
+ public function all(?string $namespace = null)
{
$this->init();
@@ -858,7 +858,7 @@
}
if (str_contains($message, "@anonymous\0")) {
- $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
+ $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $message);
}
@@ -1147,7 +1147,7 @@
*
* @return string
*/
- public function extractNamespace(string $name, int $limit = null)
+ public function extractNamespace(string $name, ?int $limit = null)
{
$parts = explode(':', $name, -1);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/CI/GithubActionReporter.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/CI/GithubActionReporter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/CI/GithubActionReporter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/CI/GithubActionReporter.php 2026-05-27 08:15:55.000000000 +0000
@@ -57,7 +57,7 @@
*
* @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
*/
- public function error(string $message, string $file = null, int $line = null, int $col = null): void
+ public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
$this->log('error', $message, $file, $line, $col);
}
@@ -67,7 +67,7 @@
*
* @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
*/
- public function warning(string $message, string $file = null, int $line = null, int $col = null): void
+ public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
$this->log('warning', $message, $file, $line, $col);
}
@@ -77,12 +77,12 @@
*
* @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message
*/
- public function debug(string $message, string $file = null, int $line = null, int $col = null): void
+ public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
$this->log('debug', $message, $file, $line, $col);
}
- private function log(string $type, string $message, string $file = null, int $line = null, int $col = null): void
+ private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
// Some values must be encoded.
$message = strtr($message, self::ESCAPED_DATA);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/Command.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/Command.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/Command.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/Command.php 2026-05-27 08:15:55.000000000 +0000
@@ -96,7 +96,7 @@
*
* @throws LogicException When the command name is empty
*/
- public function __construct(string $name = null)
+ public function __construct(?string $name = null)
{
$this->definition = new InputDefinition();
@@ -132,7 +132,7 @@
$this->ignoreValidationErrors = true;
}
- public function setApplication(Application $application = null)
+ public function setApplication(?Application $application = null)
{
$this->application = $application;
if ($application) {
@@ -433,7 +433,7 @@
*
* @throws InvalidArgumentException When argument mode is not valid
*/
- public function addArgument(string $name, int $mode = null, string $description = '', $default = null)
+ public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null)
{
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
if (null !== $this->fullDefinition) {
@@ -454,7 +454,7 @@
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
- public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
+ public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)
{
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
if (null !== $this->fullDefinition) {
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/CompleteCommand.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/CompleteCommand.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/CompleteCommand.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/CompleteCommand.php 2026-05-27 08:15:55.000000000 +0000
@@ -155,10 +155,10 @@
throw $e;
}
- return self::FAILURE;
+ return 2;
}
- return self::SUCCESS;
+ return 0;
}
private function createCompletionInput(InputInterface $input): CompletionInput
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/DumpCompletionCommand.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/DumpCompletionCommand.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/DumpCompletionCommand.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/DumpCompletionCommand.php 2026-05-27 08:15:55.000000000 +0000
@@ -85,7 +85,7 @@
if ($input->getOption('debug')) {
$this->tailDebugLog($commandName, $output);
- return self::SUCCESS;
+ return 0;
}
$shell = $input->getArgument('shell') ?? self::guessShell();
@@ -102,12 +102,12 @@
$output->writeln(sprintf('
Shell not detected, Symfony shell completion only supports "%s").>', implode('", "', $supportedShells)));
}
- return self::INVALID;
+ return 2;
}
$output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], file_get_contents($completionFile)));
- return self::SUCCESS;
+ return 0;
}
private static function guessShell(): string
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/LazyCommand.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/LazyCommand.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/LazyCommand.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/LazyCommand.php 2026-05-27 08:15:55.000000000 +0000
@@ -43,7 +43,7 @@
$this->getCommand()->ignoreValidationErrors();
}
- public function setApplication(Application $application = null): void
+ public function setApplication(?Application $application = null): void
{
if ($this->command instanceof parent) {
$this->command->setApplication($application);
@@ -117,7 +117,7 @@
/**
* @return $this
*/
- public function addArgument(string $name, int $mode = null, string $description = '', $default = null): self
+ public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null): self
{
$this->getCommand()->addArgument($name, $mode, $description, $default);
@@ -127,7 +127,7 @@
/**
* @return $this
*/
- public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null): self
+ public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null): self
{
$this->getCommand()->addOption($name, $shortcut, $mode, $description, $default);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/LockableTrait.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/LockableTrait.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Command/LockableTrait.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Command/LockableTrait.php 2026-05-27 08:15:55.000000000 +0000
@@ -30,7 +30,7 @@
/**
* Locks a command.
*/
- private function lock(string $name = null, bool $blocking = false): bool
+ private function lock(?string $name = null, bool $blocking = false): bool
{
if (!class_exists(SemaphoreStore::class)) {
throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Completion/CompletionInput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Completion/CompletionInput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Completion/CompletionInput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Completion/CompletionInput.php 2026-05-27 08:15:55.000000000 +0000
@@ -53,7 +53,7 @@
* Create an input based on an COMP_WORDS token list.
*
* @param string[] $tokens the set of split tokens (e.g. COMP_WORDS or argv)
- * @param $currentIndex the index of the cursor (e.g. COMP_CWORD)
+ * @param int $currentIndex the index of the cursor (e.g. COMP_CWORD)
*/
public static function fromTokens(array $tokens, int $currentIndex): self
{
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php 2026-05-27 08:15:55.000000000 +0000
@@ -43,7 +43,7 @@
*/
private $aliases;
- public function __construct(Application $application, string $namespace = null, bool $showHidden = false)
+ public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false)
{
$this->application = $application;
$this->namespace = $namespace;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php 2026-05-27 08:15:55.000000000 +0000
@@ -79,7 +79,7 @@
return $dom;
}
- public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument
+ public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($rootXml = $dom->createElement('symfony'));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Event/ConsoleCommandEvent.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Event/ConsoleCommandEvent.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Event/ConsoleCommandEvent.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Event/ConsoleCommandEvent.php 2026-05-27 08:15:55.000000000 +0000
@@ -12,7 +12,10 @@
namespace Symfony\Component\Console\Event;
/**
- * Allows to do things before the command is executed, like skipping the command or changing the input.
+ * Allows to do things before the command is executed, like skipping the command or executing code before the command is
+ * going to be executed.
+ *
+ * Changing the input arguments will have no effect.
*
* @author Fabien Potencier
*/
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php 2026-05-27 08:15:55.000000000 +0000
@@ -25,7 +25,7 @@
private $error;
private $exitCode;
- public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null)
+ public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null)
{
parent::__construct($command, $input, $output);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/EventListener/ErrorListener.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/EventListener/ErrorListener.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/EventListener/ErrorListener.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/EventListener/ErrorListener.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
{
private $logger;
- public function __construct(LoggerInterface $logger = null)
+ public function __construct(?LoggerInterface $logger = null)
{
$this->logger = $logger;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Exception/CommandNotFoundException.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Exception/CommandNotFoundException.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Exception/CommandNotFoundException.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Exception/CommandNotFoundException.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
* @param int $code Exception code
* @param \Throwable|null $previous Previous exception used for the exception chaining
*/
- public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
+ public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/NullOutputFormatterStyle.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/NullOutputFormatterStyle.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/NullOutputFormatterStyle.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/NullOutputFormatterStyle.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
/**
* {@inheritdoc}
*/
- public function setBackground(string $color = null): void
+ public function setBackground(?string $color = null): void
{
// do nothing
}
@@ -35,7 +35,7 @@
/**
* {@inheritdoc}
*/
- public function setForeground(string $color = null): void
+ public function setForeground(?string $color = null): void
{
// do nothing
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatter.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatter.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatter.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatter.php 2026-05-27 08:15:55.000000000 +0000
@@ -13,6 +13,8 @@
use Symfony\Component\Console\Exception\InvalidArgumentException;
+use function Symfony\Component\String\b;
+
/**
* Formatter class for console output.
*
@@ -258,7 +260,7 @@
}
preg_match('~(\\n)$~', $text, $matches);
- $text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text);
+ $text = $prefix.$this->addLineBreaks($text, $width);
$text = rtrim($text, "\n").($matches[1] ?? '');
if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) {
@@ -282,4 +284,11 @@
return implode("\n", $lines);
}
+
+ private function addLineBreaks(string $text, int $width): string
+ {
+ $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';
+
+ return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php 2026-05-27 08:15:55.000000000 +0000
@@ -33,7 +33,7 @@
* @param string|null $foreground The style foreground color name
* @param string|null $background The style background color name
*/
- public function __construct(string $foreground = null, string $background = null, array $options = [])
+ public function __construct(?string $foreground = null, ?string $background = null, array $options = [])
{
$this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);
}
@@ -41,7 +41,7 @@
/**
* {@inheritdoc}
*/
- public function setForeground(string $color = null)
+ public function setForeground(?string $color = null)
{
$this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);
}
@@ -49,7 +49,7 @@
/**
* {@inheritdoc}
*/
- public function setBackground(string $color = null)
+ public function setBackground(?string $color = null)
{
$this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -21,12 +21,12 @@
/**
* Sets style foreground color.
*/
- public function setForeground(string $color = null);
+ public function setForeground(?string $color = null);
/**
* Sets style background color.
*/
- public function setBackground(string $color = null);
+ public function setBackground(?string $color = null);
/**
* Sets some specific style option.
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
private $emptyStyle;
- public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
+ public function __construct(?OutputFormatterStyleInterface $emptyStyle = null)
{
$this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
$this->reset();
@@ -55,7 +55,7 @@
*
* @throws InvalidArgumentException When style tags incorrectly nested
*/
- public function pop(OutputFormatterStyleInterface $style = null)
+ public function pop(?OutputFormatterStyleInterface $style = null)
{
if (empty($this->styles)) {
return $this->emptyStyle;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/Dumper.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/Dumper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/Dumper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/Dumper.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
private $cloner;
private $handler;
- public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null)
+ public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null)
{
$this->output = $output;
$this->dumper = $dumper;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/Helper.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/Helper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/Helper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/Helper.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
/**
* {@inheritdoc}
*/
- public function setHelperSet(HelperSet $helperSet = null)
+ public function setHelperSet(?HelperSet $helperSet = null)
{
$this->helperSet = $helperSet;
}
@@ -96,7 +96,7 @@
*
* @return string
*/
- public static function substr(?string $string, int $from, int $length = null)
+ public static function substr(?string $string, int $from, ?int $length = null)
{
$string ?? $string = '';
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/HelperInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/HelperInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/HelperInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/HelperInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -21,7 +21,7 @@
/**
* Sets the helper set associated with this helper.
*/
- public function setHelperSet(HelperSet $helperSet = null);
+ public function setHelperSet(?HelperSet $helperSet = null);
/**
* Gets the helper set associated with this helper.
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/HelperSet.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/HelperSet.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/HelperSet.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/HelperSet.php 2026-05-27 08:15:55.000000000 +0000
@@ -37,7 +37,7 @@
}
}
- public function set(HelperInterface $helper, string $alias = null)
+ public function set(HelperInterface $helper, ?string $alias = null)
{
$this->helpers[$helper->getName()] = $helper;
if (null !== $alias) {
@@ -76,7 +76,7 @@
/**
* @deprecated since Symfony 5.4
*/
- public function setCommand(Command $command = null)
+ public function setCommand(?Command $command = null)
{
trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/ProcessHelper.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/ProcessHelper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/ProcessHelper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/ProcessHelper.php 2026-05-27 08:15:55.000000000 +0000
@@ -32,7 +32,7 @@
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*/
- public function run(OutputInterface $output, $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
+ public function run(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
{
if (!class_exists(Process::class)) {
throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
@@ -98,7 +98,7 @@
*
* @see run()
*/
- public function mustRun(OutputInterface $output, $cmd, string $error = null, callable $callback = null): Process
+ public function mustRun(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null): Process
{
$process = $this->run($output, $cmd, $error, $callback);
@@ -112,7 +112,7 @@
/**
* Wraps a Process callback to add debugging output.
*/
- public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null): callable
+ public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/ProgressBar.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/ProgressBar.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/ProgressBar.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/ProgressBar.php 2026-05-27 08:15:55.000000000 +0000
@@ -169,9 +169,12 @@
$this->messages[$name] = $message;
}
+ /**
+ * @return string|null
+ */
public function getMessage(string $name = 'message')
{
- return $this->messages[$name];
+ return $this->messages[$name] ?? null;
}
public function getStartTime(): int
@@ -293,7 +296,7 @@
*
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
*/
- public function iterate(iterable $iterable, int $max = null): iterable
+ public function iterate(iterable $iterable, ?int $max = null): iterable
{
$this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));
@@ -311,7 +314,7 @@
*
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
*/
- public function start(int $max = null)
+ public function start(?int $max = null)
{
$this->startTime = time();
$this->step = 0;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/ProgressIndicator.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/ProgressIndicator.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/ProgressIndicator.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/ProgressIndicator.php 2026-05-27 08:15:55.000000000 +0000
@@ -50,7 +50,7 @@
* @param int $indicatorChangeInterval Change interval in milliseconds
* @param array|null $indicatorValues Animated indicator characters
*/
- public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
+ public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null)
{
$this->output = $output;
@@ -129,8 +129,6 @@
/**
* Finish the indicator with message.
- *
- * @param $message
*/
public function finish(string $message)
{
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/QuestionHelper.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/QuestionHelper.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/QuestionHelper.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/QuestionHelper.php 2026-05-27 08:15:55.000000000 +0000
@@ -128,7 +128,18 @@
}
if (false === $ret) {
+ $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true;
+
+ if (!$isBlocked) {
+ stream_set_blocking($inputStream, true);
+ }
+
$ret = $this->readInput($inputStream, $question);
+
+ if (!$isBlocked) {
+ stream_set_blocking($inputStream, false);
+ }
+
if (false === $ret) {
throw new MissingInputException('Aborted.');
}
@@ -492,21 +503,7 @@
return self::$stdinIsInteractive;
}
- if (\function_exists('stream_isatty')) {
- return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r'));
- }
-
- if (\function_exists('posix_isatty')) {
- return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r'));
- }
-
- if (!\function_exists('exec')) {
- return self::$stdinIsInteractive = true;
- }
-
- exec('stty 2> /dev/null', $output, $status);
-
- return self::$stdinIsInteractive = 1 !== $status;
+ return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r'));
}
/**
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/Table.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/Table.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/Table.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/Table.php 2026-05-27 08:15:55.000000000 +0000
@@ -451,7 +451,7 @@
*
* +-----+-----------+-------+
*/
- private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null)
+ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null)
{
if (0 === $count = $this->numberOfColumns) {
return;
@@ -516,7 +516,7 @@
*
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
*/
- private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null)
+ private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null)
{
$rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
$columns = $this->getRowColumns($row);
@@ -621,9 +621,10 @@
if (!strstr($cell ?? '', "\n")) {
continue;
}
- $escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell)));
+ $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n";
+ $escaped = implode($eol, array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode($eol, $cell)));
$cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
- $lines = explode("\n", str_replace("\n", ">\n", $cell));
+ $lines = explode($eol, str_replace($eol, '>'.$eol, $cell));
foreach ($lines as $lineKey => $line) {
if ($colspan > 1) {
$line = new TableCell($line, ['colspan' => $colspan]);
@@ -685,8 +686,9 @@
$nbLines = $cell->getRowspan() - 1;
$lines = [$cell];
if (strstr($cell, "\n")) {
- $lines = explode("\n", str_replace("\n", "\n>", $cell));
- $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
+ $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n";
+ $lines = explode($eol, str_replace($eol, ''.$eol.'>', $cell));
+ $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines;
$rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
unset($lines[0]);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/TableStyle.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/TableStyle.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Helper/TableStyle.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Helper/TableStyle.php 2026-05-27 08:15:55.000000000 +0000
@@ -90,7 +90,7 @@
*
* @return $this
*/
- public function setHorizontalBorderChars(string $outside, string $inside = null): self
+ public function setHorizontalBorderChars(string $outside, ?string $inside = null): self
{
$this->horizontalOutsideBorderChar = $outside;
$this->horizontalInsideBorderChar = $inside ?? $outside;
@@ -115,7 +115,7 @@
*
* @return $this
*/
- public function setVerticalBorderChars(string $outside, string $inside = null): self
+ public function setVerticalBorderChars(string $outside, ?string $inside = null): self
{
$this->verticalOutsideBorderChar = $outside;
$this->verticalInsideBorderChar = $inside ?? $outside;
@@ -169,7 +169,7 @@
*
* @return $this
*/
- public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): self
+ public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): self
{
$this->crossingChar = $cross;
$this->crossingTopLeftChar = $topLeft;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/ArgvInput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/ArgvInput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/ArgvInput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/ArgvInput.php 2026-05-27 08:15:55.000000000 +0000
@@ -43,7 +43,7 @@
private $tokens;
private $parsed;
- public function __construct(array $argv = null, InputDefinition $definition = null)
+ public function __construct(?array $argv = null, ?InputDefinition $definition = null)
{
$argv = $argv ?? $_SERVER['argv'] ?? [];
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/ArrayInput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/ArrayInput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/ArrayInput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/ArrayInput.php 2026-05-27 08:15:55.000000000 +0000
@@ -27,7 +27,7 @@
{
private $parameters;
- public function __construct(array $parameters, InputDefinition $definition = null)
+ public function __construct(array $parameters, ?InputDefinition $definition = null)
{
$this->parameters = $parameters;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/Input.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/Input.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/Input.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/Input.php 2026-05-27 08:15:55.000000000 +0000
@@ -33,7 +33,7 @@
protected $arguments = [];
protected $interactive = true;
- public function __construct(InputDefinition $definition = null)
+ public function __construct(?InputDefinition $definition = null)
{
if (null === $definition) {
$this->definition = new InputDefinition();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/InputArgument.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/InputArgument.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/InputArgument.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/InputArgument.php 2026-05-27 08:15:55.000000000 +0000
@@ -32,13 +32,13 @@
/**
* @param string $name The argument name
- * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL
+ * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY
* @param string $description A description text
* @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only)
*
* @throws InvalidArgumentException When argument mode is not valid
*/
- public function __construct(string $name, int $mode = null, string $description = '', $default = null)
+ public function __construct(string $name, ?int $mode = null, string $description = '', $default = null)
{
if (null === $mode) {
$mode = self::OPTIONAL;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/InputOption.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/InputOption.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Input/InputOption.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Input/InputOption.php 2026-05-27 08:15:55.000000000 +0000
@@ -59,7 +59,7 @@
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
- public function __construct(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
+ public function __construct(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)
{
if (str_starts_with($name, '--')) {
$name = substr($name, 2);
@@ -69,7 +69,7 @@
throw new InvalidArgumentException('An option name cannot be empty.');
}
- if (empty($shortcut)) {
+ if ('' === $shortcut || [] === $shortcut || false === $shortcut) {
$shortcut = null;
}
@@ -78,10 +78,10 @@
$shortcut = implode('|', $shortcut);
}
$shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
- $shortcuts = array_filter($shortcuts);
+ $shortcuts = array_filter($shortcuts, 'strlen');
$shortcut = implode('|', $shortcuts);
- if (empty($shortcut)) {
+ if ('' === $shortcut) {
throw new InvalidArgumentException('An option shortcut cannot be empty.');
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/ConsoleOutput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/ConsoleOutput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/ConsoleOutput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/ConsoleOutput.php 2026-05-27 08:15:55.000000000 +0000
@@ -37,7 +37,7 @@
* @param bool|null $decorated Whether to decorate messages (null for auto-guessing)
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
*/
- public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
+ public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
{
parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php 2026-05-27 08:15:55.000000000 +0000
@@ -43,7 +43,7 @@
*
* @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared
*/
- public function clear(int $lines = null)
+ public function clear(?int $lines = null)
{
if (empty($this->content) || !$this->isDecorated()) {
return;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/Output.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/Output.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/Output.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/Output.php 2026-05-27 08:15:55.000000000 +0000
@@ -37,7 +37,7 @@
* @param bool $decorated Whether to decorate messages
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
*/
- public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
+ public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
{
$this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL;
$this->formatter = $formatter ?? new OutputFormatter();
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/StreamOutput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/StreamOutput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/StreamOutput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/StreamOutput.php 2026-05-27 08:15:55.000000000 +0000
@@ -39,7 +39,7 @@
*
* @throws InvalidArgumentException When first argument is not a real stream
*/
- public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
+ public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
{
if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
@@ -64,9 +64,6 @@
return $this->stream;
}
- /**
- * {@inheritdoc}
- */
protected function doWrite(string $message, bool $newline)
{
if ($newline) {
@@ -94,22 +91,33 @@
protected function hasColorSupport()
{
// Follow https://no-color.org/
- if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) {
+ if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) {
+ return false;
+ }
+
+ // Detect msysgit/mingw and assume this is a tty because detection
+ // does not work correctly, see https://github.com/composer/composer/issues/9690
+ if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) {
return false;
}
- if ('Hyper' === getenv('TERM_PROGRAM')) {
+ if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) {
return true;
}
- if (\DIRECTORY_SEPARATOR === '\\') {
- return (\function_exists('sapi_windows_vt100_support')
- && @sapi_windows_vt100_support($this->stream))
- || false !== getenv('ANSICON')
- || 'ON' === getenv('ConEmuANSI')
- || 'xterm' === getenv('TERM');
+ if ('Hyper' === getenv('TERM_PROGRAM')
+ || false !== getenv('COLORTERM')
+ || false !== getenv('ANSICON')
+ || 'ON' === getenv('ConEmuANSI')
+ ) {
+ return true;
+ }
+
+ if ('dumb' === $term = (string) getenv('TERM')) {
+ return false;
}
- return stream_isatty($this->stream);
+ // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157
+ return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term);
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php 2026-05-27 08:15:55.000000000 +0000
@@ -24,7 +24,7 @@
private $maxLength;
private $buffer = '';
- public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
+ public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
{
if ($maxLength <= 0) {
throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Question/Question.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Question/Question.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Question/Question.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Question/Question.php 2026-05-27 08:15:55.000000000 +0000
@@ -186,7 +186,7 @@
*
* @return $this
*/
- public function setAutocompleterCallback(callable $callback = null): self
+ public function setAutocompleterCallback(?callable $callback = null): self
{
if ($this->hidden && null !== $callback) {
throw new LogicException('A hidden question cannot use the autocompleter.');
@@ -202,7 +202,7 @@
*
* @return $this
*/
- public function setValidator(callable $validator = null)
+ public function setValidator(?callable $validator = null)
{
$this->validator = $validator;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Resources/completion.bash symfony-5.4.53+dfsg/src/Symfony/Component/Console/Resources/completion.bash
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Resources/completion.bash 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Resources/completion.bash 2026-05-27 08:15:55.000000000 +0000
@@ -7,7 +7,7 @@
_sf_{{ COMMAND_NAME }}() {
# Use newline as only separator to allow space in completion values
- IFS=$'\n'
+ local IFS=$'\n'
local sf_cmd="${COMP_WORDS[0]}"
# for an alias, get the real script behind it
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/SingleCommandApplication.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/SingleCommandApplication.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/SingleCommandApplication.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/SingleCommandApplication.php 2026-05-27 08:15:55.000000000 +0000
@@ -46,7 +46,7 @@
return $this;
}
- public function run(InputInterface $input = null, OutputInterface $output = null): int
+ public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
{
if ($this->running) {
return parent::run($input, $output);
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Style/StyleInterface.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Style/StyleInterface.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Style/StyleInterface.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Style/StyleInterface.php 2026-05-27 08:15:55.000000000 +0000
@@ -85,14 +85,14 @@
*
* @return mixed
*/
- public function ask(string $question, string $default = null, callable $validator = null);
+ public function ask(string $question, ?string $default = null, ?callable $validator = null);
/**
* Asks a question with the user input hidden.
*
* @return mixed
*/
- public function askHidden(string $question, callable $validator = null);
+ public function askHidden(string $question, ?callable $validator = null);
/**
* Asks for confirmation.
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Style/SymfonyStyle.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Style/SymfonyStyle.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Style/SymfonyStyle.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Style/SymfonyStyle.php 2026-05-27 08:15:55.000000000 +0000
@@ -61,7 +61,7 @@
*
* @param string|array $messages The message to write in the block
*/
- public function block($messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
+ public function block($messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
{
$messages = \is_array($messages) ? array_values($messages) : [$messages];
@@ -250,7 +250,7 @@
/**
* {@inheritdoc}
*/
- public function ask(string $question, string $default = null, callable $validator = null)
+ public function ask(string $question, ?string $default = null, ?callable $validator = null)
{
$question = new Question($question, $default);
$question->setValidator($validator);
@@ -261,7 +261,7 @@
/**
* {@inheritdoc}
*/
- public function askHidden(string $question, callable $validator = null)
+ public function askHidden(string $question, ?callable $validator = null)
{
$question = new Question($question);
@@ -338,7 +338,7 @@
/**
* @see ProgressBar::iterate()
*/
- public function progressIterate(iterable $iterable, int $max = null): iterable
+ public function progressIterate(iterable $iterable, ?int $max = null): iterable
{
yield from $this->createProgressBar()->iterate($iterable, $max);
@@ -463,7 +463,7 @@
$this->bufferedOutput->write($message, $newLine, $type);
}
- private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
+ private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
{
$indentLength = 0;
$prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix));
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Terminal.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Terminal.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Terminal.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Terminal.php 2026-05-27 08:15:55.000000000 +0000
@@ -64,14 +64,12 @@
return self::$stty;
}
- // skip check if exec function is disabled
- if (!\function_exists('exec')) {
+ // skip check if shell_exec function is disabled
+ if (!\function_exists('shell_exec')) {
return false;
}
- exec('stty 2>&1', $output, $exitcode);
-
- return self::$stty = 0 === $exitcode;
+ return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
}
private static function initDimensions()
@@ -160,8 +158,7 @@
$cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0;
- $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
- if (!\is_resource($process)) {
+ if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) {
return null;
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/ApplicationTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/ApplicationTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/ApplicationTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/ApplicationTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -41,6 +41,7 @@
use Symfony\Component\Console\SignalRegistry\SignalRegistry;
use Symfony\Component\Console\Terminal;
use Symfony\Component\Console\Tester\ApplicationTester;
+use Symfony\Component\Console\Tests\Fixtures\MockableAppliationWithTerminalWidth;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -876,7 +877,9 @@
public function testRenderExceptionLineBreaks()
{
- $application = $this->getMockBuilder(Application::class)->addMethods(['getTerminalWidth'])->getMock();
+ $application = $this->getMockBuilder(MockableAppliationWithTerminalWidth::class)
+ ->onlyMethods(['getTerminalWidth'])
+ ->getMock();
$application->setAutoExit(false);
$application->expects($this->any())
->method('getTerminalWidth')
@@ -1536,7 +1539,7 @@
$tester = new ApplicationTester($application);
$tester->run(['command' => 'dym']);
- $this->assertStringContainsString('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events');
+ $this->assertStringContainsString('before.dym.error.after.', $tester->getDisplay(), 'The PHP error did not dispatch events');
}
public function testRunDispatchesAllEventsWithError()
@@ -1553,7 +1556,7 @@
$tester = new ApplicationTester($application);
$tester->run(['command' => 'dym']);
- $this->assertStringContainsString('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events');
+ $this->assertStringContainsString('before.dym.error.after.', $tester->getDisplay(), 'The PHP error did not dispatch events');
}
public function testRunWithErrorFailingStatusCode()
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/CI/GithubActionReporterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/CI/GithubActionReporterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/CI/GithubActionReporterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/CI/GithubActionReporterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -34,7 +34,7 @@
/**
* @dataProvider annotationsFormatProvider
*/
- public function testAnnotationsFormat(string $type, string $message, string $file = null, int $line = null, int $col = null, string $expected)
+ public function testAnnotationsFormat(string $type, string $message, ?string $file, ?int $line, ?int $col, string $expected)
{
$reporter = new GithubActionReporter($buffer = new BufferedOutput());
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -133,4 +133,19 @@
yield ['bin/console cache:clear "multi word string"', ['bin/console', 'cache:clear', '"multi word string"']];
yield ['bin/console cache:clear \'multi word string\'', ['bin/console', 'cache:clear', '\'multi word string\'']];
}
+
+ public function testToString()
+ {
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 0);
+ $this->assertSame('foo| bar baz', (string) $input);
+
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 1);
+ $this->assertSame('foo bar| baz', (string) $input);
+
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 2);
+ $this->assertSame('foo bar baz|', (string) $input);
+
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 11);
+ $this->assertSame('foo bar baz |', (string) $input);
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Fixtures/MockableAppliationWithTerminalWidth.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Fixtures/MockableAppliationWithTerminalWidth.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Fixtures/MockableAppliationWithTerminalWidth.php 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Fixtures/MockableAppliationWithTerminalWidth.php 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Tests\Fixtures;
+
+use Symfony\Component\Console\Application;
+
+class MockableAppliationWithTerminalWidth extends Application
+{
+ public function getTerminalWidth(): int
+ {
+ return 0;
+ }
+}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -162,7 +162,7 @@
/**
* @dataProvider provideInlineStyleOptionsCases
*/
- public function testInlineStyleOptions(string $tag, string $expected = null, string $input = null, bool $truecolor = false)
+ public function testInlineStyleOptions(string $tag, ?string $expected = null, ?string $input = null, bool $truecolor = false)
{
if ($truecolor && 'truecolor' !== getenv('COLORTERM')) {
$this->markTestSkipped('The terminal does not support true colors.');
@@ -200,7 +200,7 @@
];
}
- public function provideInlineStyleTagsWithUnknownOptions()
+ public static function provideInlineStyleTagsWithUnknownOptions()
{
return [
['', 'abc'],
@@ -367,10 +367,10 @@
$formatter = new OutputFormatter(true);
$this->assertSame("fo\no\e[37;41mb\e[39;49m\n\e[37;41mar\e[39;49m\nba\nz", $formatter->formatAndWrap('foobar baz', 2));
- $this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2));
+ $this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo\e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr\e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2));
$this->assertSame("pre\e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m\npos\nt", $formatter->formatAndWrap('pre foo bar baz post', 3));
- $this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo \e[39;49m\n\e[37;41mbar \e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre foo bar baz post', 4));
- $this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo ba\e[39;49m\n\e[37;41mr baz\e[39;49m\npost", $formatter->formatAndWrap('pre foo bar baz post', 5));
+ $this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre foo bar baz post', 4));
+ $this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m p\nost", $formatter->formatAndWrap('pre foo bar baz post', 5));
$this->assertSame("Lore\nm \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m \ndolo\nr \e[32msi\e[39m\n\e[32mt\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 4));
$this->assertSame("Lorem \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m dolo\nr \e[32msit\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 8));
$this->assertSame("Lorem \e[37;41mipsum\e[39;49m dolor \e[32m\e[39m\n\e[32msit\e[39m, \e[37;41mamet\e[39;49m et \e[32mlauda\e[39m\n\e[32mntium\e[39m architecto", $formatter->formatAndWrap('Lorem ipsum dolor sit, amet et laudantium architecto', 18));
@@ -378,10 +378,12 @@
$formatter = new OutputFormatter();
$this->assertSame("fo\nob\nar\nba\nz", $formatter->formatAndWrap('foobar baz', 2));
- $this->assertSame("pr\ne \nfo\no \nba\nr \nba\nz \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2));
+ $this->assertSame("pr\ne \nfo\no\nba\nr\nba\nz \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2));
$this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre foo bar baz post', 3));
- $this->assertSame("pre \nfoo \nbar \nbaz \npost", $formatter->formatAndWrap('pre foo bar baz post', 4));
- $this->assertSame("pre f\noo ba\nr baz\npost", $formatter->formatAndWrap('pre foo bar baz post', 5));
+ $this->assertSame("pre \nfoo\nbar\nbaz \npost", $formatter->formatAndWrap('pre foo bar baz post', 4));
+ $this->assertSame("pre f\noo\nbar\nbaz p\nost", $formatter->formatAndWrap('pre foo bar baz post', 5));
+ $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\nlÃnès", $formatter->formatAndWrap('Â rèälly löng tîtlè thät cöüld nèêd múltîplê lÃnès', 10));
+ $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\n lÃnès", $formatter->formatAndWrap("Â rèälly löng tîtlè thät cöüld nèêd múltîplê\n lÃnès", 10));
$this->assertSame('', $formatter->formatAndWrap(null, 5));
}
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -117,7 +117,7 @@
}
}
- private function getGenericMockHelper($name, HelperSet $helperset = null)
+ private function getGenericMockHelper($name, ?HelperSet $helperset = null)
{
$mock_helper = $this->createMock(HelperInterface::class);
$mock_helper->expects($this->any())
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -1173,4 +1173,11 @@
stream_get_contents($output->getStream())
);
}
+
+ public function testGetNotSetMessage()
+ {
+ $progressBar = new ProgressBar($this->getOutputStream());
+
+ $this->assertNull($progressBar->getMessage());
+ }
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -430,7 +430,7 @@
$this->assertEquals('8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("8AM\n")), $this->createOutputInterface(), $question));
}
- public function testAskHiddenResponseTrimmed()
+ public function testAskHiddenResponseNotTrimmed()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('This test is not supported on Windows');
@@ -442,7 +442,7 @@
$question->setHidden(true);
$question->setTrimmable(false);
- $this->assertEquals(' 8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream(' 8AM')), $this->createOutputInterface(), $question));
+ $this->assertEquals(' 8AM'.\PHP_EOL, $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream(' 8AM'.\PHP_EOL)), $this->createOutputInterface(), $question));
}
public function testAskMultilineResponseWithEOF()
@@ -914,6 +914,10 @@
public function testAutocompleteMoveCursorBackwards()
{
+ if (!Terminal::hasSttyAvailable()) {
+ $this->markTestSkipped('`stty` is required to test autocomplete functionality');
+ }
+
// F
$inputStream = $this->getInputStream("F\t\177\177\177");
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/TableTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/TableTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Helper/TableTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Helper/TableTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -102,7 +102,7 @@
['ISBN', 'Title', 'Author'],
$books,
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+--------------------------+------------------+
| ISBN | Title | Author |
+---------------+--------------------------+------------------+
@@ -118,30 +118,30 @@
['ISBN', 'Title', 'Author'],
$books,
'compact',
-<<<'TABLE'
-ISBN Title Author
-99921-58-10-7 Divine Comedy Dante Alighieri
-9971-5-0210-0 A Tale of Two Cities Charles Dickens
-960-425-059-0 The Lord of the Rings J. R. R. Tolkien
-80-902734-1-6 And Then There Were None Agatha Christie
-
-TABLE
+ implode("\n", [
+ 'ISBN Title Author ',
+ '99921-58-10-7 Divine Comedy Dante Alighieri ',
+ '9971-5-0210-0 A Tale of Two Cities Charles Dickens ',
+ '960-425-059-0 The Lord of the Rings J. R. R. Tolkien ',
+ '80-902734-1-6 And Then There Were None Agatha Christie ',
+ '',
+ ]),
],
[
['ISBN', 'Title', 'Author'],
$books,
'borderless',
-<<<'TABLE'
- =============== ========================== ==================
- ISBN Title Author
- =============== ========================== ==================
- 99921-58-10-7 Divine Comedy Dante Alighieri
- 9971-5-0210-0 A Tale of Two Cities Charles Dickens
- 960-425-059-0 The Lord of the Rings J. R. R. Tolkien
- 80-902734-1-6 And Then There Were None Agatha Christie
- =============== ========================== ==================
-
-TABLE
+ implode("\n", [
+ ' =============== ========================== ================== ',
+ ' ISBN Title Author ',
+ ' =============== ========================== ================== ',
+ ' 99921-58-10-7 Divine Comedy Dante Alighieri ',
+ ' 9971-5-0210-0 A Tale of Two Cities Charles Dickens ',
+ ' 960-425-059-0 The Lord of the Rings J. R. R. Tolkien ',
+ ' 80-902734-1-6 And Then There Were None Agatha Christie ',
+ ' =============== ========================== ================== ',
+ '',
+ ]),
],
[
['ISBN', 'Title', 'Author'],
@@ -191,7 +191,7 @@
['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+--------------------------+------------------+
| ISBN | Title | |
+---------------+--------------------------+------------------+
@@ -212,7 +212,7 @@
['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
| 9971-5-0210-0 | | |
@@ -231,7 +231,7 @@
['960-425-059-0', 'The Lord of the Rings', "J. R. R.\nTolkien"],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+----------------------------+-----------------+
| ISBN | Title | Author |
+---------------+----------------------------+-----------------+
@@ -251,7 +251,7 @@
['ISBN', 'Title'],
[],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+------+-------+
| ISBN | Title |
+------+-------+
@@ -271,7 +271,7 @@
['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens>'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+----------------------+-----------------+
| ISBN | Title | Author |
+---------------+----------------------+-----------------+
@@ -288,7 +288,7 @@
['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+----------------------------------+----------------------+-----------------+
| ISBN | Title | Author |
+----------------------------------+----------------------+-----------------+
@@ -320,7 +320,7 @@
],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+-------------------------------+-------------------------------+-----------------------------+
| ISBN | Title | Author |
+-------------------------------+-------------------------------+-----------------------------+
@@ -347,7 +347,7 @@
],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+-----+-----+-----+
| Foo | Bar | Baz |
+-----+-----+-----+
@@ -366,7 +366,7 @@
],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+-----+-----+------+
| Foo | Bar | Baz |
+-----+-----+------+
@@ -392,7 +392,7 @@
['80-902734-1-7', 'Test'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+---------------+-----------------+
| ISBN | Title | Author |
+---------------+---------------+-----------------+
@@ -425,7 +425,7 @@
['J. R. R'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+------------------+---------+-----------------+
| ISBN | Title | Author |
+------------------+---------+-----------------+
@@ -460,7 +460,7 @@
],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+-----------------+-------+-----------------+
| ISBN | Title | Author |
+-----------------+-------+-----------------+
@@ -497,7 +497,7 @@
['Charles Dickens'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+-----------------+-------+-----------------+
| ISBN | Title | Author |
+-----------------+-------+-----------------+
@@ -524,7 +524,7 @@
['Charles Dickens'],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+-----------------+
| ISBN | Author |
+---------------+-----------------+
@@ -542,7 +542,7 @@
],
[],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+------+-------+--------+
| Main title |
+------+-------+--------+
@@ -560,9 +560,9 @@
new TableCell('3', ['colspan' => 2]),
new TableCell('4', ['colspan' => 2]),
],
- ],
+ ],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---+--+--+---+--+---+--+---+--+
| 1 | 2 | 3 | 4 |
+---+--+--+---+--+---+--+---+--+
@@ -595,7 +595,7 @@
+-----------------+------------------+---------+
TABLE
- ,
+ ,
true,
],
'Row with formatted cells containing a newline' => [
@@ -607,7 +607,7 @@
new TableSeparator(),
[
'foo',
- new TableCell('Dont break'."\n".'here', ['rowspan' => 2]),
+ new TableCell('Dont break'."\n".'here', ['rowspan' => 2]),
],
[
'bar',
@@ -624,77 +624,77 @@
+-------+------------+
TABLE
- ,
+ ,
true,
],
'TabeCellStyle with align. Also with rowspan and colspan > 1' => [
- [
- new TableCell(
- 'ISBN',
- [
- 'style' => new TableCellStyle([
- 'align' => 'right',
- ]),
- ]
- ),
- 'Title',
- new TableCell(
- 'Author',
- [
- 'style' => new TableCellStyle([
- 'align' => 'center',
- ]),
- ]
- ),
- ],
- [
- [
- new TableCell(
- '978>',
- [
- 'style' => new TableCellStyle([
- 'align' => 'center',
- ]),
- ]
- ),
- 'De Monarchia',
- new TableCell(
- "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows",
- [
- 'rowspan' => 2,
- 'style' => new TableCellStyle([
- 'align' => 'center',
- ]),
- ]
- ),
- ],
- [
- '99921-58-10-7',
- 'Divine Comedy',
- ],
- new TableSeparator(),
- [
- new TableCell(
- 'test',
- [
- 'colspan' => 2,
- 'style' => new TableCellStyle([
- 'align' => 'center',
- ]),
- ]
- ),
- new TableCell(
- 'tttt',
- [
- 'style' => new TableCellStyle([
- 'align' => 'right',
- ]),
- ]
- ),
- ],
- ],
- 'default',
-<<<'TABLE'
+ [
+ new TableCell(
+ 'ISBN',
+ [
+ 'style' => new TableCellStyle([
+ 'align' => 'right',
+ ]),
+ ]
+ ),
+ 'Title',
+ new TableCell(
+ 'Author',
+ [
+ 'style' => new TableCellStyle([
+ 'align' => 'center',
+ ]),
+ ]
+ ),
+ ],
+ [
+ [
+ new TableCell(
+ '978>',
+ [
+ 'style' => new TableCellStyle([
+ 'align' => 'center',
+ ]),
+ ]
+ ),
+ 'De Monarchia',
+ new TableCell(
+ "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows",
+ [
+ 'rowspan' => 2,
+ 'style' => new TableCellStyle([
+ 'align' => 'center',
+ ]),
+ ]
+ ),
+ ],
+ [
+ '99921-58-10-7',
+ 'Divine Comedy',
+ ],
+ new TableSeparator(),
+ [
+ new TableCell(
+ 'test',
+ [
+ 'colspan' => 2,
+ 'style' => new TableCellStyle([
+ 'align' => 'center',
+ ]),
+ ]
+ ),
+ new TableCell(
+ 'tttt',
+ [
+ 'style' => new TableCellStyle([
+ 'align' => 'right',
+ ]),
+ ]
+ ),
+ ],
+ ],
+ 'default',
+ <<<'TABLE'
+---------------+---------------+-------------------------------------------+
| ISBN | Title | Author |
+---------------+---------------+-------------------------------------------+
@@ -706,66 +706,66 @@
+---------------+---------------+-------------------------------------------+
TABLE
- ,
- ],
+ ,
+ ],
'TabeCellStyle with fg,bg. Also with rowspan and colspan > 1' => [
[],
[
- [
- new TableCell(
- '978>',
- [
- 'style' => new TableCellStyle([
- 'fg' => 'black',
- 'bg' => 'green',
- ]),
- ]
- ),
- 'De Monarchia',
- new TableCell(
- "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows",
- [
- 'rowspan' => 2,
- 'style' => new TableCellStyle([
- 'fg' => 'red',
- 'bg' => 'green',
- 'align' => 'center',
- ]),
- ]
- ),
- ],
-
- [
- '99921-58-10-7',
- 'Divine Comedy',
- ],
- new TableSeparator(),
- [
- new TableCell(
- 'test',
- [
- 'colspan' => 2,
- 'style' => new TableCellStyle([
- 'fg' => 'red',
- 'bg' => 'green',
- 'align' => 'center',
- ]),
- ]
- ),
- new TableCell(
- 'tttt',
- [
- 'style' => new TableCellStyle([
- 'fg' => 'red',
- 'bg' => 'green',
- 'align' => 'right',
- ]),
- ]
- ),
- ],
+ [
+ new TableCell(
+ '978>',
+ [
+ 'style' => new TableCellStyle([
+ 'fg' => 'black',
+ 'bg' => 'green',
+ ]),
+ ]
+ ),
+ 'De Monarchia',
+ new TableCell(
+ "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows",
+ [
+ 'rowspan' => 2,
+ 'style' => new TableCellStyle([
+ 'fg' => 'red',
+ 'bg' => 'green',
+ 'align' => 'center',
+ ]),
+ ]
+ ),
+ ],
+
+ [
+ '99921-58-10-7',
+ 'Divine Comedy',
+ ],
+ new TableSeparator(),
+ [
+ new TableCell(
+ 'test',
+ [
+ 'colspan' => 2,
+ 'style' => new TableCellStyle([
+ 'fg' => 'red',
+ 'bg' => 'green',
+ 'align' => 'center',
+ ]),
+ ]
+ ),
+ new TableCell(
+ 'tttt',
+ [
+ 'style' => new TableCellStyle([
+ 'fg' => 'red',
+ 'bg' => 'green',
+ 'align' => 'right',
+ ]),
+ ]
+ ),
+ ],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+---------------+---------------+-------------------------------------------+
[39;49m| [39;49m[31m978[39m[39;49m | De Monarchia |[39;49m[31;42m Dante Alighieri [39;49m[39;49m|[39;49m
[39;49m| [39;49m[32m99921-58-10-7[39m[39;49m | Divine Comedy |[39;49m[31;42m spans multiple rows rows Dante Alighieri [39;49m[39;49m|[39;49m
@@ -775,9 +775,9 @@
+---------------+---------------+-------------------------------------------+
TABLE
- ,
- true,
- ],
+ ,
+ true,
+ ],
'TabeCellStyle with cellFormat. Also with rowspan and colspan > 1' => [
[
new TableCell(
@@ -820,7 +820,7 @@
],
],
'default',
-<<<'TABLE'
+ <<<'TABLE'
+----------------+---------------+---------------------+
|[30;46m ISBN [39;49m|[32m Title [39m|[32m Author [39m|
+----------------+---------------+---------------------+
@@ -832,7 +832,7 @@
TABLE
,
true,
- ],
+ ],
];
}
@@ -1017,15 +1017,16 @@
public function testThrowsWhenTheCellInAnArray()
{
- $this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('A cell must be a TableCell, a scalar or an object implementing "__toString()", "array" given.');
- $table = new Table($output = $this->getOutputStream());
+ $table = new Table($this->getOutputStream());
$table
->setHeaders(['ISBN', 'Title', 'Author', 'Price'])
->setRows([
['99921-58-10-7', [], 'Dante Alighieri', '9.95'],
]);
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('A cell must be a TableCell, a scalar or an object implementing "__toString()", "array" given.');
+
$table->render();
}
@@ -1288,7 +1289,7 @@
TABLE
,
true,
- ],
+ ],
'header contains multiple lines' => [
'Multiline'."\n".'header'."\n".'here',
'footer',
@@ -1378,12 +1379,14 @@
$expected =
<<setColumnMaxWidth(1, 15);
$table->setColumnMaxWidth(2, 15);
$table->setRows([
- [new TableCell('Lorem ipsum dolor sit amet, consectetur> adipiscing elit, sed> do eiusmod> tempor', ['colspan' => 3])],
- new TableSeparator(),
- [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])],
- new TableSeparator(),
- [new TableCell('Lorem ipsum dolor> sit amet, consectetur ', ['colspan' => 2]), 'hello world'],
- new TableSeparator(),
- ['hello world>', new TableCell('Lorem ipsum dolor sit amet, consectetur> adipiscing elit', ['colspan' => 2])],
- new TableSeparator(),
- ['hello ', new TableCell('world', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'],
- new TableSeparator(),
- ['Symfony ', new TableCell('Test', ['colspan' => 1]), 'Lorem ipsum> dolor sit amet, consectetur'],
- ])
+ [new TableCell('Lorem ipsum dolor sit amet, consectetur> adipiscing elit, sed> do eiusmod> tempor', ['colspan' => 3])],
+ new TableSeparator(),
+ [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])],
+ new TableSeparator(),
+ [new TableCell('Lorem ipsum dolor> sit amet, consectetur ', ['colspan' => 2]), 'hello world'],
+ new TableSeparator(),
+ ['hello world>', new TableCell('Lorem ipsum dolor sit amet, consectetur> adipiscing elit', ['colspan' => 2])],
+ new TableSeparator(),
+ ['hello ', new TableCell('world', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'],
+ new TableSeparator(),
+ ['Symfony ', new TableCell('Test', ['colspan' => 1]), 'Lorem ipsum> dolor sit amet, consectetur'],
+ ])
;
$table->render();
@@ -1577,8 +1580,8 @@
| Lorem ipsum dolor sit amet, consectetur adipi |
| scing elit, sed do eiusmod tempor |
+-----------------+-----------------+-----------------+
-| Lorem ipsum dolor sit amet, consectetur adipi |
-| scing elit, sed do eiusmod tempor |
+| Lorem ipsum dolor sit amet, consectetur |
+| adipiscing elit, sed do eiusmod tempor |
+-----------------+-----------------+-----------------+
| Lorem ipsum dolor sit amet, co | hello world |
| nsectetur | |
@@ -1586,13 +1589,13 @@
| hello world | Lorem ipsum dolor sit amet, co |
| | nsectetur adipiscing elit |
+-----------------+-----------------+-----------------+
-| hello | world | Lorem ipsum dol |
-| | | or sit amet, co |
-| | | nsectetur |
+| hello | world | Lorem ipsum |
+| | | dolor sit amet, |
+| | | consectetur |
+-----------------+-----------------+-----------------+
| Symfony | Test | Lorem ipsum dol |
-| | | or sit amet, co |
-| | | nsectetur |
+| | | or sit amet, |
+| | | consectetur |
+-----------------+-----------------+-----------------+
TABLE;
@@ -1614,8 +1617,9 @@
$expected =
<<assertEquals('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts');
$option = new InputOption('foo');
$this->assertNull($option->getShortcut(), '__construct() makes the shortcut null by default');
+ $option = new InputOption('foo', '');
+ $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given an empty string');
+ $option = new InputOption('foo', []);
+ $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given an empty array');
+ $option = new InputOption('foo', ['f', '', 'fff']);
+ $this->assertEquals('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts');
+ $option = new InputOption('foo', 'f||fff');
+ $this->assertEquals('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts');
+ $option = new InputOption('foo', '0');
+ $this->assertEquals('0', $option->getShortcut(), '-0 is an acceptable shortcut value');
+ $option = new InputOption('foo', ['0', 'z']);
+ $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in an array');
+ $option = new InputOption('foo', '0|z');
+ $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in a string-list');
+ $option = new InputOption('foo', false);
+ $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given a false as value');
}
public function testModes()
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Question/QuestionTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Question/QuestionTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/Question/QuestionTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/Question/QuestionTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -157,7 +157,7 @@
public function testSetAutocompleterValuesWithTraversable()
{
$question1 = new Question('Test question 1');
- $iterator1 = $this->getMockForAbstractClass(\IteratorAggregate::class);
+ $iterator1 = $this->createMock(\IteratorAggregate::class);
$iterator1
->expects($this->once())
->method('getIterator')
@@ -165,7 +165,7 @@
$question1->setAutocompleterValues($iterator1);
$question2 = new Question('Test question 2');
- $iterator2 = $this->getMockForAbstractClass(\IteratorAggregate::class);
+ $iterator2 = $this->createMock(\IteratorAggregate::class);
$iterator2
->expects($this->once())
->method('getIterator')
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/TerminalTest.php symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/TerminalTest.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/Console/Tests/TerminalTest.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/Console/Tests/TerminalTest.php 2026-05-27 08:15:55.000000000 +0000
@@ -41,7 +41,7 @@
foreach (['height', 'width', 'stty'] as $name) {
$property = new \ReflectionProperty(Terminal::class, $name);
$property->setAccessible(true);
- $property->setValue(null);
+ $property->setValue(null, null);
}
}
@@ -77,8 +77,8 @@
$this->markTestSkipped('Must be on windows');
}
- $sttyString = exec('(stty -a | grep columns) 2>&1', $output, $exitcode);
- if (0 !== $exitcode) {
+ $sttyString = shell_exec('(stty -a | grep columns) 2> NUL');
+ if (!$sttyString) {
$this->markTestSkipped('Must have stty support');
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/.gitattributes symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/.gitattributes
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/.gitattributes 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/.gitattributes 2026-05-27 08:15:55.000000000 +0000
@@ -1,4 +1,3 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
-/.gitattributes export-ignore
-/.gitignore export-ignore
+/.git* export-ignore
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/.github/PULL_REQUEST_TEMPLATE.md symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/.github/PULL_REQUEST_TEMPLATE.md
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/.github/PULL_REQUEST_TEMPLATE.md 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,8 @@
+Please do not submit any Pull Requests here. They will be closed.
+---
+
+Please submit your PR here instead:
+https://github.com/symfony/symfony
+
+This repository is what we call a "subtree split": a read-only subset of that main repository.
+We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/.github/workflows/close-pull-request.yml symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/.github/workflows/close-pull-request.yml
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/.github/workflows/close-pull-request.yml 1970-01-01 00:00:00.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/.github/workflows/close-pull-request.yml 2026-05-27 08:15:55.000000000 +0000
@@ -0,0 +1,20 @@
+name: Close Pull Request
+
+on:
+ pull_request_target:
+ types: [opened]
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: superbrothers/close-pull-request@v3
+ with:
+ comment: |
+ Thanks for your Pull Request! We love contributions.
+
+ However, you should instead open your PR on the main repository:
+ https://github.com/symfony/symfony
+
+ This repository is what we call a "subtree split": a read-only subset of that main repository.
+ We're looking forward to your PR there!
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Node/ElementNode.php symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Node/ElementNode.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Node/ElementNode.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Node/ElementNode.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
private $namespace;
private $element;
- public function __construct(string $namespace = null, string $element = null)
+ public function __construct(?string $namespace = null, ?string $element = null)
{
$this->namespace = $namespace;
$this->element = $element;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Node/SelectorNode.php symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Node/SelectorNode.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Node/SelectorNode.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Node/SelectorNode.php 2026-05-27 08:15:55.000000000 +0000
@@ -26,7 +26,7 @@
private $tree;
private $pseudoElement;
- public function __construct(NodeInterface $tree, string $pseudoElement = null)
+ public function __construct(NodeInterface $tree, ?string $pseudoElement = null)
{
$this->tree = $tree;
$this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Parser/Parser.php symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Parser/Parser.php
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Parser/Parser.php 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Parser/Parser.php 2026-05-27 08:15:55.000000000 +0000
@@ -29,7 +29,7 @@
{
private $tokenizer;
- public function __construct(Tokenizer $tokenizer = null)
+ public function __construct(?Tokenizer $tokenizer = null)
{
$this->tokenizer = $tokenizer ?? new Tokenizer();
}
diff -Nru symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
--- symfony-5.4.23+dfsg/src/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html 2023-04-28 13:30:08.000000000 +0000
+++ symfony-5.4.53+dfsg/src/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html 2026-05-27 08:15:55.000000000 +0000
@@ -45,4 +45,8 @@
-