feature #38253 [Cache] Allow ISO 8601 time intervals to specify default lifetime (lstrojny)

This PR was merged into the 5.2-dev branch.

Discussion
----------

[Cache] Allow ISO 8601 time intervals to specify default lifetime

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

`Psr\Cache\CacheItemInterface::expiresAfter()` takes `DateInterval` for expiration but Symfony’s cache config only takes an integer. Time intervals are a bit better to read so this adds the capability.

Commits
-------

a2508ac3e7 [Cache] Allow ISO 8601 time intervals to specify default lifetime
This commit is contained in:
Fabien Potencier 2020-10-05 19:14:35 +02:00
commit a4ceab6a14
11 changed files with 69 additions and 8 deletions

View File

@ -1040,7 +1040,10 @@ class Configuration implements ConfigurationInterface
->end()
->scalarNode('tags')->defaultNull()->end()
->booleanNode('public')->defaultFalse()->end()
->integerNode('default_lifetime')->end()
->scalarNode('default_lifetime')
->info('Default lifetime of the pool')
->example('"600" for 5 minutes expressed in seconds, "PT5M" for five minutes expressed as ISO 8601 time interval, or "5 minutes" as a date expression')
->end()
->scalarNode('provider')
->info('Overwrite the setting from the default provider for this adapter.')
->end()

View File

@ -283,7 +283,7 @@
<xsd:attribute name="adapter" type="xsd:string" />
<xsd:attribute name="tags" type="xsd:string" />
<xsd:attribute name="public" type="xsd:boolean" />
<xsd:attribute name="default-lifetime" type="xsd:integer" />
<xsd:attribute name="default-lifetime" type="xsd:string" />
<xsd:attribute name="provider" type="xsd:string" />
<xsd:attribute name="early-expiration-message-bus" type="xsd:string" />
<xsd:attribute name="clearer" type="xsd:string" />

View File

@ -22,7 +22,10 @@ $container->loadFromExtension('framework', [
'provider' => 'app.cache_pool',
],
'cache.def' => [
'default_lifetime' => 11,
'default_lifetime' => 'PT11S',
],
'cache.expr' => [
'default_lifetime' => '13 seconds',
],
'cache.chain' => [
'default_lifetime' => 12,

View File

@ -11,7 +11,8 @@
<framework:pool name="cache.bar" adapter="cache.adapter.doctrine" default-lifetime="5" provider="app.doctrine_cache_provider" />
<framework:pool name="cache.baz" adapter="cache.adapter.filesystem" default-lifetime="7" />
<framework:pool name="cache.foobar" adapter="cache.adapter.psr6" default-lifetime="10" provider="app.cache_pool" />
<framework:pool name="cache.def" default-lifetime="11" />
<framework:pool name="cache.def" default-lifetime="PT11S" />
<framework:pool name="cache.expr" default-lifetime="13 seconds" />
<framework:pool name="cache.chain" default-lifetime="12">
<framework:adapter name="cache.adapter.array" />
<framework:adapter name="cache.adapter.filesystem" />

View File

@ -16,7 +16,9 @@ framework:
default_lifetime: 10
provider: app.cache_pool
cache.def:
default_lifetime: 11
default_lifetime: PT11S
cache.expr:
default_lifetime: 13 seconds
cache.chain:
default_lifetime: 12
adapter:

View File

@ -61,10 +61,10 @@ use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
use Symfony\Component\Workflow;
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
use Symfony\Component\Workflow\WorkflowEvents;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
abstract class FrameworkExtensionTest extends TestCase
{
@ -1333,7 +1333,8 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertCachePoolServiceDefinitionIsCreated($container, 'cache.bar', 'cache.adapter.doctrine', 5);
$this->assertCachePoolServiceDefinitionIsCreated($container, 'cache.baz', 'cache.adapter.filesystem', 7);
$this->assertCachePoolServiceDefinitionIsCreated($container, 'cache.foobar', 'cache.adapter.psr6', 10);
$this->assertCachePoolServiceDefinitionIsCreated($container, 'cache.def', 'cache.app', 11);
$this->assertCachePoolServiceDefinitionIsCreated($container, 'cache.def', 'cache.app', 'PT11S');
$this->assertCachePoolServiceDefinitionIsCreated($container, 'cache.expr', 'cache.app', '13 seconds');
$chain = $container->getDefinition('cache.chain');

View File

@ -1,15 +1,21 @@
imports:
- { resource: default.yml }
parameters:
env(LIFETIME_INTERVAL): 'PT10S'
env(LIFETIME_EXPRESSION): '13 seconds'
framework:
cache:
pools:
cache.pool1:
public: true
adapter: cache.system
default_lifetime: '%env(LIFETIME_EXPRESSION)%'
cache.pool2:
public: true
adapter: cache.pool3
default_lifetime: '%env(LIFETIME_INTERVAL)%'
cache.pool3:
clearer: ~
cache.pool4:

View File

@ -0,0 +1,35 @@
<?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\Adapter;
/**
* @author Lars Strojny <lars@strojny.net>
*/
final class ParameterNormalizer
{
public static function normalizeDuration(string $duration): int
{
if (is_numeric($duration)) {
return $duration;
}
if (false !== $time = strtotime($duration, 0)) {
return $time;
}
try {
return \DateTime::createFromFormat('U', 0)->add(new \DateInterval($duration))->getTimestamp();
} catch (\Exception $e) {
throw new \InvalidArgumentException(sprintf('Cannot parse date interval "%s".', $duration), 0, $e);
}
}
}

View File

@ -5,6 +5,7 @@ CHANGELOG
-----
* added integration with Messenger to allow computing cached values in a worker
* allow ISO 8601 time intervals to specify default lifetime
5.1.0
-----

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\DependencyInjection;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\ParameterNormalizer;
use Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
@ -176,7 +177,14 @@ class CachePoolPass implements CompilerPassInterface
]);
$pool->addTag($this->reversibleTag);
} elseif ('namespace' !== $attr || ArrayAdapter::class !== $class) {
$pool->replaceArgument($i++, $tags[0][$attr]);
$argument = $tags[0][$attr];
if ('default_lifetime' === $attr && !is_numeric($argument)) {
$argument = (new Definition('int', [$argument]))
->setFactory([ParameterNormalizer::class, 'normalizeDuration']);
}
$pool->replaceArgument($i++, $argument);
}
unset($tags[0][$attr]);
}

View File

@ -45,6 +45,7 @@ final class LockRegistry
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ParameterNormalizer.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php',