Skip to content

Commit bd6769e

Browse files
feature #26929 [Cache] Add [Taggable]CacheInterface, the easiest way to use a cache (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- [Cache] Add [Taggable]CacheInterface, the easiest way to use a cache | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #25903 | License | MIT | Doc PR | - This feature is a no-brainer, yet it provides a wonderful DX when using a cache: by type-hinting the new `CacheInterface` or `TaggableCacheInterface`, you get access to: ```php public function get(string $key, callable $callback); ``` `$callback` is called when `$key` is not found in the cache pool. It is given one arguments: a `CacheItemInterface $item` (a `CacheItem` for a `TaggableCacheInterface`), and should return the corresponding value. ```php $value = $cache->get($key, function (CacheItemInterface $item) { $item->expiresAfter(3600); return $this->computeValue(); }); ``` or for tags, on a `TaggableCacheInterface $cache`: ```php $value = $cache->get($key, function (CacheItem $item) { $item->tag('foo_tag'); return $this->computeValue(); }); ``` Plain simple, I love it, why didn't we have the idea earlier, isn't it ?! :) Commits ------- 589ff69 [Cache] Add [Taggable]CacheInterface, the easiest way to use a cache
2 parents 021531b + 589ff69 commit bd6769e

20 files changed

+341
-11
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
<argument type="service" id="cache.app" />
1616
</service>
1717

18+
<service id="cache.app.taggable" class="Symfony\Component\Cache\Adapter\TagAwareAdapter">
19+
<argument type="service" id="cache.app" />
20+
</service>
21+
1822
<service id="cache.system" parent="cache.adapter.system" public="true">
1923
<tag name="cache.pool" />
2024
</service>
@@ -122,7 +126,9 @@
122126
<service id="cache.global_clearer" parent="cache.default_clearer" public="true" />
123127
<service id="cache.app_clearer" alias="cache.default_clearer" public="true" />
124128
<service id="Psr\Cache\CacheItemPoolInterface" alias="cache.app" />
129+
<service id="Symfony\Component\Cache\TaggableCacheInterface" alias="cache.app.taggable" />
125130
<service id="Psr\SimpleCache\CacheInterface" alias="cache.app.simple" />
126131
<service id="Symfony\Component\Cache\Adapter\AdapterInterface" alias="cache.app" />
132+
<service id="Symfony\Component\Cache\CacheInterface" alias="cache.app" />
127133
</services>
128134
</container>

src/Symfony/Component/Cache/Adapter/AbstractAdapter.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@
1515
use Psr\Log\LoggerAwareInterface;
1616
use Psr\Log\LoggerInterface;
1717
use Psr\Log\NullLogger;
18+
use Symfony\Component\Cache\CacheInterface;
1819
use Symfony\Component\Cache\CacheItem;
1920
use Symfony\Component\Cache\Exception\InvalidArgumentException;
2021
use Symfony\Component\Cache\ResettableInterface;
2122
use Symfony\Component\Cache\Traits\AbstractTrait;
23+
use Symfony\Component\Cache\Traits\GetTrait;
2224

2325
/**
2426
* @author Nicolas Grekas <p@tchwork.com>
2527
*/
26-
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
28+
abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
2729
{
2830
use AbstractTrait;
31+
use GetTrait;
2932

3033
private static $apcuSupported;
3134
private static $phpFilesSupported;

src/Symfony/Component/Cache/Adapter/ArrayAdapter.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@
1313

1414
use Psr\Cache\CacheItemInterface;
1515
use Psr\Log\LoggerAwareInterface;
16+
use Symfony\Component\Cache\CacheInterface;
1617
use Symfony\Component\Cache\CacheItem;
1718
use Symfony\Component\Cache\ResettableInterface;
1819
use Symfony\Component\Cache\Traits\ArrayTrait;
20+
use Symfony\Component\Cache\Traits\GetTrait;
1921

2022
/**
2123
* @author Nicolas Grekas <p@tchwork.com>
2224
*/
23-
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
25+
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
2426
{
2527
use ArrayTrait;
28+
use GetTrait;
2629

2730
private $createCacheItem;
2831

src/Symfony/Component/Cache/Adapter/ChainAdapter.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313

1414
use Psr\Cache\CacheItemInterface;
1515
use Psr\Cache\CacheItemPoolInterface;
16+
use Symfony\Component\Cache\CacheInterface;
1617
use Symfony\Component\Cache\CacheItem;
1718
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1819
use Symfony\Component\Cache\PruneableInterface;
1920
use Symfony\Component\Cache\ResettableInterface;
21+
use Symfony\Component\Cache\Traits\GetTrait;
2022

2123
/**
2224
* Chains several adapters together.
@@ -26,8 +28,10 @@
2628
*
2729
* @author Kévin Dunglas <dunglas@gmail.com>
2830
*/
29-
class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
31+
class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
3032
{
33+
use GetTrait;
34+
3135
private $adapters = array();
3236
private $adapterCount;
3337
private $syncItem;
@@ -61,6 +65,8 @@ function ($sourceItem, $item) use ($defaultLifetime) {
6165
$item->expiry = $sourceItem->expiry;
6266
$item->isHit = $sourceItem->isHit;
6367

68+
$sourceItem->isTaggable = false;
69+
6470
if (0 < $sourceItem->defaultLifetime && $sourceItem->defaultLifetime < $defaultLifetime) {
6571
$defaultLifetime = $sourceItem->defaultLifetime;
6672
}
@@ -75,6 +81,33 @@ function ($sourceItem, $item) use ($defaultLifetime) {
7581
);
7682
}
7783

84+
/**
85+
* {@inheritdoc}
86+
*/
87+
public function get(string $key, callable $callback)
88+
{
89+
$lastItem = null;
90+
$i = 0;
91+
$wrap = function (CacheItem $item = null) use ($key, $callback, &$wrap, &$i, &$lastItem) {
92+
$adapter = $this->adapters[$i];
93+
if (isset($this->adapters[++$i])) {
94+
$callback = $wrap;
95+
}
96+
if ($adapter instanceof CacheInterface) {
97+
$value = $adapter->get($key, $callback);
98+
} else {
99+
$value = $this->doGet($adapter, $key, $callback);
100+
}
101+
if (null !== $item) {
102+
($this->syncItem)($lastItem = $lastItem ?? $item, $item);
103+
}
104+
105+
return $value;
106+
};
107+
108+
return $wrap();
109+
}
110+
78111
/**
79112
* {@inheritdoc}
80113
*/

src/Symfony/Component/Cache/Adapter/NullAdapter.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@
1212
namespace Symfony\Component\Cache\Adapter;
1313

1414
use Psr\Cache\CacheItemInterface;
15+
use Symfony\Component\Cache\CacheInterface;
1516
use Symfony\Component\Cache\CacheItem;
17+
use Symfony\Component\Cache\Traits\GetTrait;
1618

1719
/**
1820
* @author Titouan Galopin <galopintitouan@gmail.com>
1921
*/
20-
class NullAdapter implements AdapterInterface
22+
class NullAdapter implements AdapterInterface, CacheInterface
2123
{
24+
use GetTrait;
25+
2226
private $createCacheItem;
2327

2428
public function __construct()

src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313

1414
use Psr\Cache\CacheItemInterface;
1515
use Psr\Cache\CacheItemPoolInterface;
16+
use Symfony\Component\Cache\CacheInterface;
1617
use Symfony\Component\Cache\CacheItem;
1718
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1819
use Symfony\Component\Cache\PruneableInterface;
1920
use Symfony\Component\Cache\ResettableInterface;
21+
use Symfony\Component\Cache\Traits\GetTrait;
2022
use Symfony\Component\Cache\Traits\PhpArrayTrait;
2123

2224
/**
@@ -26,9 +28,10 @@
2628
* @author Titouan Galopin <galopintitouan@gmail.com>
2729
* @author Nicolas Grekas <p@tchwork.com>
2830
*/
29-
class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
31+
class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
3032
{
3133
use PhpArrayTrait;
34+
use GetTrait;
3235

3336
private $createCacheItem;
3437

@@ -77,6 +80,31 @@ public static function create($file, CacheItemPoolInterface $fallbackPool)
7780
return $fallbackPool;
7881
}
7982

83+
/**
84+
* {@inheritdoc}
85+
*/
86+
public function get(string $key, callable $callback)
87+
{
88+
if (null === $this->values) {
89+
$this->initialize();
90+
}
91+
if (null === $value = $this->values[$key] ?? null) {
92+
if ($this->pool instanceof CacheInterface) {
93+
return $this->pool->get($key, $callback);
94+
}
95+
96+
return $this->doGet($this->pool, $key, $callback);
97+
}
98+
if ('N;' === $value) {
99+
return null;
100+
}
101+
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
102+
return unserialize($value);
103+
}
104+
105+
return $value;
106+
}
107+
80108
/**
81109
* {@inheritdoc}
82110
*/

src/Symfony/Component/Cache/Adapter/ProxyAdapter.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@
1313

1414
use Psr\Cache\CacheItemInterface;
1515
use Psr\Cache\CacheItemPoolInterface;
16+
use Symfony\Component\Cache\CacheInterface;
1617
use Symfony\Component\Cache\CacheItem;
1718
use Symfony\Component\Cache\PruneableInterface;
1819
use Symfony\Component\Cache\ResettableInterface;
20+
use Symfony\Component\Cache\Traits\GetTrait;
1921
use Symfony\Component\Cache\Traits\ProxyTrait;
2022

2123
/**
2224
* @author Nicolas Grekas <p@tchwork.com>
2325
*/
24-
class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
26+
class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
2527
{
2628
use ProxyTrait;
29+
use GetTrait;
2730

2831
private $namespace;
2932
private $namespaceLen;
@@ -54,6 +57,20 @@ function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
5457
);
5558
}
5659

60+
/**
61+
* {@inheritdoc}
62+
*/
63+
public function get(string $key, callable $callback)
64+
{
65+
if (!$this->pool instanceof CacheInterface) {
66+
return $this->doGet($this->pool, $key, $callback);
67+
}
68+
69+
return $this->pool->get($this->getId($key), function ($innerItem) use ($key, $callback) {
70+
return $callback(($this->createCacheItem)($key, $innerItem));
71+
});
72+
}
73+
5774
/**
5875
* {@inheritdoc}
5976
*/

src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@
1616
use Symfony\Component\Cache\CacheItem;
1717
use Symfony\Component\Cache\PruneableInterface;
1818
use Symfony\Component\Cache\ResettableInterface;
19+
use Symfony\Component\Cache\TaggableCacheInterface;
20+
use Symfony\Component\Cache\Traits\GetTrait;
1921
use Symfony\Component\Cache\Traits\ProxyTrait;
2022

2123
/**
2224
* @author Nicolas Grekas <p@tchwork.com>
2325
*/
24-
class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface
26+
class TagAwareAdapter implements TagAwareAdapterInterface, TaggableCacheInterface, PruneableInterface, ResettableInterface
2527
{
2628
const TAGS_PREFIX = "\0tags\0";
2729

2830
use ProxyTrait;
31+
use GetTrait;
2932

3033
private $deferred = array();
3134
private $createCacheItem;
@@ -58,6 +61,7 @@ function ($key, $value, CacheItem $protoItem) {
5861
);
5962
$this->setCacheItemTags = \Closure::bind(
6063
function (CacheItem $item, $key, array &$itemTags) {
64+
$item->isTaggable = true;
6165
if (!$item->isHit) {
6266
return $item;
6367
}

src/Symfony/Component/Cache/Adapter/TraceableAdapter.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Component\Cache\Adapter;
1313

1414
use Psr\Cache\CacheItemInterface;
15+
use Symfony\Component\Cache\CacheInterface;
16+
use Symfony\Component\Cache\CacheItem;
1517
use Symfony\Component\Cache\PruneableInterface;
1618
use Symfony\Component\Cache\ResettableInterface;
1719

@@ -22,7 +24,7 @@
2224
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
2325
* @author Nicolas Grekas <p@tchwork.com>
2426
*/
25-
class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
27+
class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
2628
{
2729
protected $pool;
2830
private $calls = array();
@@ -32,6 +34,38 @@ public function __construct(AdapterInterface $pool)
3234
$this->pool = $pool;
3335
}
3436

37+
/**
38+
* {@inheritdoc}
39+
*/
40+
public function get(string $key, callable $callback)
41+
{
42+
if (!$this->pool instanceof CacheInterface) {
43+
throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_class($this->pool), CacheInterface::class));
44+
}
45+
46+
$isHit = true;
47+
$callback = function (CacheItem $item) use ($callback, &$isHit) {
48+
$isHit = $item->isHit();
49+
50+
return $callback($item);
51+
};
52+
53+
$event = $this->start(__FUNCTION__);
54+
try {
55+
$value = $this->pool->get($key, $callback);
56+
$event->result[$key] = \is_object($value) ? \get_class($value) : gettype($value);
57+
} finally {
58+
$event->end = microtime(true);
59+
}
60+
if ($isHit) {
61+
++$event->hits;
62+
} else {
63+
++$event->misses;
64+
}
65+
66+
return $value;
67+
}
68+
3569
/**
3670
* {@inheritdoc}
3771
*/

src/Symfony/Component/Cache/Adapter/TraceableTagAwareAdapter.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111

1212
namespace Symfony\Component\Cache\Adapter;
1313

14+
use Symfony\Component\Cache\TaggableCacheInterface;
15+
1416
/**
1517
* @author Robin Chalas <robin.chalas@gmail.com>
1618
*/
17-
class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface
19+
class TraceableTagAwareAdapter extends TraceableAdapter implements TaggableCacheInterface, TagAwareAdapterInterface
1820
{
1921
public function __construct(TagAwareAdapterInterface $pool)
2022
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy