Merge branch '6.4' into 7.3

* 6.4:
  [Cache] Fix internal representation of non-static values
  [Cache] Make `TagAwareAdapter` registrable as a service
  refactor: Unify & more humane translation message
  fix Resources translations validators.pt.xlf
  [Security] Pass attributes to nested `ChainUserProviders`
  [Validator] Update translation for the Video constraint
  [Messenger] Firebird Database - incompatibility with expected lowercase columns
  SQLSRV: Change column type from TEXT to STRING
  Fix exception catch when deleting temporary table in the sameDatabaseChecker
  [Serializer] Fix serializer crash due to asymmetric visibility on `protected(set)` properties
This commit is contained in:
Nicolas Grekas
2025-09-03 13:56:52 +02:00
5 changed files with 48 additions and 31 deletions

View File

@@ -17,6 +17,7 @@ use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\CachedValueInterface;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Component\Cache\Traits\ProxyTrait;
use Symfony\Component\VarExporter\VarExporter;
@@ -96,16 +97,15 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
if ('N;' === $value) {
return null;
}
if (!$value instanceof CachedValueInterface) {
return $value;
}
try {
if ($value instanceof \Closure) {
return $value();
}
return $value->getValue();
} catch (\Throwable) {
unset($this->keys[$key]);
goto get_from_pool;
}
return $value;
}
public function getItem(mixed $key): CacheItem
@@ -125,9 +125,9 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
if ('N;' === $value) {
$value = null;
} elseif ($value instanceof \Closure) {
} elseif ($value instanceof CachedValueInterface) {
try {
$value = $value();
$value = $value->getValue();
} catch (\Throwable) {
$value = null;
$isHit = false;
@@ -306,8 +306,7 @@ EOF;
}
if (!$isStaticValue) {
$value = str_replace("\n", "\n ", $value);
$value = "static function () {\n return {$value};\n}";
$value = 'new class() implements \\'.CachedValueInterface::class." { public function getValue(): mixed { return {$value}; } }";
}
$hash = hash('xxh128', $value);
@@ -368,9 +367,9 @@ EOF;
if ('N;' === $value) {
yield $key => $f($key, null, true);
} elseif ($value instanceof \Closure) {
} elseif ($value instanceof CachedValueInterface) {
try {
yield $key => $f($key, $value(), true);
yield $key => $f($key, $value->getValue(), true);
} catch (\Throwable) {
yield $key => $f($key, null, false);
}

View File

@@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\CachedValueInterface;
use Symfony\Component\Cache\Traits\FilesystemCommonTrait;
use Symfony\Component\VarExporter\VarExporter;
@@ -113,8 +114,10 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
$values[$id] = null;
} elseif (!\is_object($value)) {
$values[$id] = $value;
} elseif ($value instanceof CachedValueInterface) {
$values[$id] = $value->getValue();
} elseif (!$value instanceof LazyValue) {
$values[$id] = $value();
$values[$id] = $value;
} elseif (false === $values[$id] = include $value->file) {
unset($values[$id], $this->values[$id]);
$missingIds[] = $id;
@@ -235,7 +238,7 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
if ($isStaticValue) {
$value = "return [{$expiry}, {$value}];";
} elseif ($this->appendOnly) {
$value = "return [{$expiry}, static fn () => {$value}];";
$value = "return [{$expiry}, new class() implements \\".CachedValueInterface::class." { public function getValue(): mixed { return {$value}; } }];";
} else {
// We cannot use a closure here because of https://bugs.php.net/76982
$value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);

View File

@@ -16,6 +16,7 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\NullAdapter;
use Symfony\Component\Cache\Adapter\ParameterNormalizer;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
@@ -153,7 +154,7 @@ class CachePoolPass implements CompilerPassInterface
),
]);
$pool->addTag('container.reversible');
} elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) {
} elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class, TagAwareAdapter::class], true)) {
$argument = $tags[0][$attr];
if ('default_lifetime' === $attr && !is_numeric($argument)) {

View File

@@ -17,6 +17,7 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\NullAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -102,15 +103,18 @@ class CachePoolPassTest extends TestCase
$this->assertSame('mVXLns1cYU', $cachePool->getArgument(0));
}
public function testNamespaceArgumentIsNotReplacedIfArrayAdapterIsUsed()
/**
* @dataProvider providerAdaptersNotNamespace
*/
public function testNamespaceArgumentIsNotReplacedIfAdapterWithoutNamespace(string $adapterClass)
{
$container = new ContainerBuilder();
$container->setParameter('kernel.container_class', 'app');
$container->setParameter('kernel.project_dir', 'foo');
$container->register('cache.adapter.array', ArrayAdapter::class)->addArgument(0);
$container->register('cache.adapter', $adapterClass)->addArgument(0);
$cachePool = new ChildDefinition('cache.adapter.array');
$cachePool = new ChildDefinition('cache.adapter');
$cachePool->addTag('cache.pool');
$container->setDefinition('app.cache_pool', $cachePool);
@@ -119,21 +123,11 @@ class CachePoolPassTest extends TestCase
$this->assertCount(0, $container->getDefinition('app.cache_pool')->getArguments());
}
public function testNamespaceArgumentIsNotReplacedIfNullAdapterIsUsed()
public static function providerAdaptersNotNamespace(): iterable
{
$container = new ContainerBuilder();
$container->setParameter('kernel.container_class', 'app');
$container->setParameter('kernel.project_dir', 'foo');
$container->register('cache.adapter.null', NullAdapter::class);
$cachePool = new ChildDefinition('cache.adapter.null');
$cachePool->addTag('cache.pool');
$container->setDefinition('app.cache_pool', $cachePool);
$this->cachePoolPass->process($container);
$this->assertCount(0, $container->getDefinition('app.cache_pool')->getArguments());
yield [ArrayAdapter::class];
yield [NullAdapter::class];
yield [TagAwareAdapter::class];
}
public function testArgsAreReplaced()

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
/**
* @internal
*/
interface CachedValueInterface
{
public function getValue(): mixed;
}