Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitba82917

Browse files
[Cache] Enable namespace-based invalidation by prefixing keys with backend-native namespace separators
1 parentca6f399 commitba82917

25 files changed

+476
-44
lines changed

‎composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"psr/http-message":"^1.0|^2.0",
4848
"psr/link":"^1.1|^2.0",
4949
"psr/log":"^1|^2|^3",
50-
"symfony/contracts":"^3.5",
50+
"symfony/contracts":"^3.6",
5151
"symfony/polyfill-ctype":"~1.8",
5252
"symfony/polyfill-intl-grapheme":"~1.0",
5353
"symfony/polyfill-intl-icu":"~1.0",
@@ -217,7 +217,7 @@
217217
"url":"src/Symfony/Contracts",
218218
"options": {
219219
"versions": {
220-
"symfony/contracts":"3.5.x-dev"
220+
"symfony/contracts":"3.6.x-dev"
221221
}
222222
}
223223
},

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@
207207
useSymfony\Component\Yaml\Yaml;
208208
useSymfony\Contracts\Cache\CacheInterface;
209209
useSymfony\Contracts\Cache\CallbackInterface;
210+
useSymfony\Contracts\Cache\NamespacedPoolInterface;
210211
useSymfony\Contracts\Cache\TagAwareCacheInterface;
211212
useSymfony\Contracts\EventDispatcher\EventDispatcherInterface;
212213
useSymfony\Contracts\HttpClient\HttpClientInterface;
@@ -2568,6 +2569,10 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
25682569
$container->registerAliasForArgument($tagAwareId, TagAwareCacheInterface::class,$pool['name'] ??$name);
25692570
$container->registerAliasForArgument($name, CacheInterface::class,$pool['name'] ??$name);
25702571
$container->registerAliasForArgument($name, CacheItemPoolInterface::class,$pool['name'] ??$name);
2572+
2573+
if (interface_exists(NamespacedPoolInterface::class)) {
2574+
$container->registerAliasForArgument($name, NamespacedPoolInterface::class,$pool['name'] ??$name);
2575+
}
25712576
}
25722577

25732578
$definition->setPublic($pool['public']);

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
useSymfony\Component\Cache\Traits\AbstractAdapterTrait;
2020
useSymfony\Component\Cache\Traits\ContractsTrait;
2121
useSymfony\Contracts\Cache\CacheInterface;
22+
useSymfony\Contracts\Cache\NamespacedPoolInterface;
2223

2324
/**
2425
* @author Nicolas Grekas <p@tchwork.com>
2526
*/
26-
abstractclass AbstractAdapterimplements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
27+
abstractclass AbstractAdapterimplements AdapterInterface, CacheInterface,NamespacedPoolInterface,LoggerAwareInterface, ResettableInterface
2728
{
2829
use AbstractAdapterTrait;
2930
use ContractsTrait;
@@ -37,7 +38,17 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
3738

3839
protectedfunction__construct(string$namespace ='',int$defaultLifetime =0)
3940
{
40-
$this->namespace ='' ===$namespace ?'' : CacheItem::validateKey($namespace).static::NS_SEPARATOR;
41+
if ('' !==$namespace) {
42+
if (str_contains($namespace,static::NS_SEPARATOR)) {
43+
if (str_contains($namespace,static::NS_SEPARATOR.static::NS_SEPARATOR)) {
44+
thrownewInvalidArgumentException(\sprintf('Cache namespace "%s" contains empty sub-namespace.',$namespace));
45+
}
46+
$namespace =str_replace(static::NS_SEPARATOR,'',$namespace);
47+
}
48+
$this->namespace = CacheItem::validateKey($namespace).static::NS_SEPARATOR;
49+
}
50+
$this->rootNamespace =$namespace;
51+
4152
$this->defaultLifetime =$defaultLifetime;
4253
if (null !==$this->maxIdLength &&\strlen($namespace) >$this->maxIdLength -24) {
4354
thrownewInvalidArgumentException(\sprintf('Namespace must be %d chars max, %d given ("%s").',$this->maxIdLength -24,\strlen($namespace),$namespace));
@@ -159,7 +170,7 @@ public function commit(): bool
159170
$v =$values[$id];
160171
$type =get_debug_type($v);
161172
$message =\sprintf('Failed to save key "{key}" of type %s%s',$type,$einstanceof \Exception ?':'.$e->getMessage() :'.');
162-
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->namespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
173+
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->rootNamespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
163174
}
164175
}else {
165176
foreach ($valuesas$id =>$v) {
@@ -182,7 +193,7 @@ public function commit(): bool
182193
$ok =false;
183194
$type =get_debug_type($v);
184195
$message =\sprintf('Failed to save key "{key}" of type %s%s',$type,$einstanceof \Exception ?':'.$e->getMessage() :'.');
185-
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->namespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
196+
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->rootNamespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
186197
}
187198
}
188199

‎src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
useSymfony\Component\Cache\ResettableInterface;
1818
useSymfony\Component\Cache\Traits\AbstractAdapterTrait;
1919
useSymfony\Component\Cache\Traits\ContractsTrait;
20+
useSymfony\Contracts\Cache\NamespacedPoolInterface;
2021
useSymfony\Contracts\Cache\TagAwareCacheInterface;
2122

2223
/**
@@ -30,16 +31,31 @@
3031
*
3132
* @internal
3233
*/
33-
abstractclass AbstractTagAwareAdapterimplements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface
34+
abstractclass AbstractTagAwareAdapterimplements TagAwareAdapterInterface, TagAwareCacheInterface,AdapterInterface, NamespacedPoolInterface,LoggerAwareInterface, ResettableInterface
3435
{
3536
use AbstractAdapterTrait;
3637
use ContractsTrait;
3738

39+
/**
40+
* @internal
41+
*/
42+
protectedconstNS_SEPARATOR =':';
43+
3844
privateconstTAGS_PREFIX ="\1tags\1";
3945

4046
protectedfunction__construct(string$namespace ='',int$defaultLifetime =0)
4147
{
42-
$this->namespace ='' ===$namespace ?'' : CacheItem::validateKey($namespace).':';
48+
if ('' !==$namespace) {
49+
if (str_contains($namespace,static::NS_SEPARATOR)) {
50+
if (str_contains($namespace,static::NS_SEPARATOR.static::NS_SEPARATOR)) {
51+
thrownewInvalidArgumentException(\sprintf('Cache namespace "%s" contains empty sub-namespace.',$namespace));
52+
}
53+
$namespace =str_replace(static::NS_SEPARATOR,'',$namespace);
54+
}
55+
$this->namespace = CacheItem::validateKey($namespace).static::NS_SEPARATOR;
56+
}
57+
$this->rootNamespace =$this->namespace;
58+
4359
$this->defaultLifetime =$defaultLifetime;
4460
if (null !==$this->maxIdLength &&\strlen($namespace) >$this->maxIdLength -24) {
4561
thrownewInvalidArgumentException(\sprintf('Namespace must be %d chars max, %d given ("%s").',$this->maxIdLength -24,\strlen($namespace),$namespace));
@@ -70,7 +86,7 @@ static function ($key, $value, $isHit) {
7086
CacheItem::class
7187
);
7288
self::$mergeByLifetime ??= \Closure::bind(
73-
staticfunction ($deferred, &$expiredIds,$getId,$tagPrefix,$defaultLifetime) {
89+
staticfunction ($deferred, &$expiredIds,$getId,$tagPrefix,$defaultLifetime,$rootNamespace) {
7490
$byLifetime = [];
7591
$now =microtime(true);
7692
$expiredIds = [];
@@ -102,10 +118,10 @@ static function ($deferred, &$expiredIds, $getId, $tagPrefix, $defaultLifetime)
102118
$value['tag-operations'] = ['add' => [],'remove' => []];
103119
$oldTags =$item->metadata[CacheItem::METADATA_TAGS] ?? [];
104120
foreach (array_diff_key($value['tags'],$oldTags)as$addedTag) {
105-
$value['tag-operations']['add'][] =$getId($tagPrefix.$addedTag);
121+
$value['tag-operations']['add'][] =$getId($tagPrefix.$addedTag,$rootNamespace);
106122
}
107123
foreach (array_diff_key($oldTags,$value['tags'])as$removedTag) {
108-
$value['tag-operations']['remove'][] =$getId($tagPrefix.$removedTag);
124+
$value['tag-operations']['remove'][] =$getId($tagPrefix.$removedTag,$rootNamespace);
109125
}
110126
$value['tags'] =array_keys($value['tags']);
111127

@@ -168,7 +184,7 @@ protected function doDeleteYieldTags(array $ids): iterable
168184
publicfunctioncommit():bool
169185
{
170186
$ok =true;
171-
$byLifetime = (self::$mergeByLifetime)($this->deferred,$expiredIds,$this->getId(...),self::TAGS_PREFIX,$this->defaultLifetime);
187+
$byLifetime = (self::$mergeByLifetime)($this->deferred,$expiredIds,$this->getId(...),self::TAGS_PREFIX,$this->defaultLifetime,$this->rootNamespace);
172188
$retry =$this->deferred = [];
173189

174190
if ($expiredIds) {
@@ -195,7 +211,7 @@ public function commit(): bool
195211
$v =$values[$id];
196212
$type =get_debug_type($v);
197213
$message =\sprintf('Failed to save key "{key}" of type %s%s',$type,$einstanceof \Exception ?':'.$e->getMessage() :'.');
198-
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->namespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
214+
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->rootNamespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
199215
}
200216
}else {
201217
foreach ($valuesas$id =>$v) {
@@ -219,7 +235,7 @@ public function commit(): bool
219235
$ok =false;
220236
$type =get_debug_type($v);
221237
$message =\sprintf('Failed to save key "{key}" of type %s%s',$type,$einstanceof \Exception ?':'.$e->getMessage() :'.');
222-
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->namespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
238+
CacheItem::log($this->logger,$message, ['key' =>substr($id,\strlen($this->rootNamespace)),'exception' =>$einstanceof \Exception ?$e :null,'cache-adapter' =>get_debug_type($this)]);
223239
}
224240
}
225241

@@ -244,7 +260,7 @@ public function deleteItems(array $keys): bool
244260
try {
245261
foreach ($this->doDeleteYieldTags(array_values($ids))as$id =>$tags) {
246262
foreach ($tagsas$tag) {
247-
$tagData[$this->getId(self::TAGS_PREFIX.$tag)][] =$id;
263+
$tagData[$this->getId(self::TAGS_PREFIX.$tag,$this->rootNamespace)][] =$id;
248264
}
249265
}
250266
}catch (\Exception) {
@@ -283,7 +299,7 @@ public function invalidateTags(array $tags): bool
283299

284300
$tagIds = [];
285301
foreach (array_unique($tags)as$tag) {
286-
$tagIds[] =$this->getId(self::TAGS_PREFIX.$tag);
302+
$tagIds[] =$this->getId(self::TAGS_PREFIX.$tag,$this->rootNamespace);
287303
}
288304

289305
try {

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
useSymfony\Component\Cache\CacheItem;
1919
useSymfony\Component\Cache\Exception\InvalidArgumentException;
2020
useSymfony\Component\Cache\ResettableInterface;
21+
useSymfony\Component\Cache\Traits\NamespacedPoolTrait;
2122
useSymfony\Contracts\Cache\CacheInterface;
23+
useSymfony\Contracts\Cache\NamespacedPoolInterface;
2224

2325
/**
2426
* An in-memory cache storage.
@@ -27,13 +29,23 @@
2729
*
2830
* @author Nicolas Grekas <p@tchwork.com>
2931
*/
30-
class ArrayAdapterimplements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
32+
class ArrayAdapterimplements AdapterInterface, CacheInterface,NamespacedPoolInterface,LoggerAwareInterface, ResettableInterface
3133
{
3234
use LoggerAwareTrait;
35+
use NamespacedPoolTrait {
36+
pushNamespaceasprivate doPushNamespace;
37+
popNamespaceasprivate doPopNamespace;
38+
}
39+
40+
/**
41+
* @internal
42+
*/
43+
protectedconstNS_SEPARATOR =":";
3344

3445
privatearray$values = [];
3546
privatearray$tags = [];
3647
privatearray$expiries = [];
48+
privatearray$stack = [];
3749

3850
privatestatic\Closure$createCacheItem;
3951

@@ -231,11 +243,45 @@ public function clear(string $prefix = ''): bool
231243
}
232244
}
233245

246+
$stack =$this->stack;
247+
$this->stack = [];
248+
foreach ($stackas$ns =>$pool) {
249+
if (str_starts_with($ns,$this->namespace)) {
250+
unset($stack[$ns]);
251+
$pool->clear($prefix);
252+
}
253+
}
254+
$this->stack =$stack ?: [];
255+
234256
$this->values =$this->tags =$this->expiries = [];
235257

236258
returntrue;
237259
}
238260

261+
publicfunctionpushNamespace(string$namespace):static
262+
{
263+
$stack = &$this->stack;
264+
$clone =$this->doPushNamespace($namespace);
265+
266+
if (isset($stack[$clone->namespace])) {
267+
return$stack[$clone->namespace];
268+
}
269+
270+
$stack[''] ??=$this;
271+
$clone->clear();
272+
273+
return$stack[$clone->namespace] =$clone;
274+
}
275+
276+
publicfunctionpopNamespace(?string &$namespace =null):static
277+
{
278+
$stack = &$this->stack;
279+
$stack[''] ??=$this;
280+
$clone =$this->doPopNamespace($namespace);
281+
282+
return$stack[$clone->namespace];
283+
}
284+
239285
/**
240286
* Returns all cached values, with cache miss as null.
241287
*/

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

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
usePsr\Cache\CacheItemPoolInterface;
1616
useSymfony\Component\Cache\CacheItem;
1717
useSymfony\Component\Cache\Exception\InvalidArgumentException;
18+
useSymfony\Component\Cache\Exception\LogicException;
1819
useSymfony\Component\Cache\PruneableInterface;
1920
useSymfony\Component\Cache\ResettableInterface;
2021
useSymfony\Component\Cache\Traits\ContractsTrait;
2122
useSymfony\Contracts\Cache\CacheInterface;
23+
useSymfony\Contracts\Cache\NamespacedPoolInterface;
2224
useSymfony\Contracts\Service\ResetInterface;
2325

2426
/**
@@ -29,7 +31,7 @@
2931
*
3032
* @author Kévin Dunglas <dunglas@gmail.com>
3133
*/
32-
class ChainAdapterimplements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
34+
class ChainAdapterimplements AdapterInterface, CacheInterface,NamespacedPoolInterface,PruneableInterface, ResettableInterface
3335
{
3436
use ContractsTrait;
3537

@@ -280,6 +282,44 @@ public function prune(): bool
280282
return$pruned;
281283
}
282284

285+
publicfunctionpushNamespace(string$namespace):static
286+
{
287+
$clone =clone$this;
288+
$adapters = [];
289+
290+
foreach ($this->adaptersas$adapter) {
291+
if (!$adapterinstanceof NamespacedPoolInterface) {
292+
thrownewLogicException('All adapters must implement NamespacedPoolInterface to support namespaces.');
293+
}
294+
295+
$adapters[] =$adapter->pushNamespace($namespace);
296+
}
297+
$clone->adapters =$adapters;
298+
299+
return$clone;
300+
}
301+
302+
publicfunctionpopNamespace(?string &$namespace =null):static
303+
{
304+
$clone =clone$this;
305+
$namespace =null;
306+
307+
foreach ($this->adaptersas$adapter) {
308+
if (!$adapterinstanceof NamespacedPoolInterface) {
309+
thrownewLogicException('All adapters should implement NamespacedPoolInterface to support namespaces.');
310+
}
311+
312+
$adapters[] =$adapter->popNamespace($ns);
313+
314+
if ($ns !== ($namespace ??=$ns)) {
315+
thrownewLogicException('All adapters should pop the same namespace.');
316+
}
317+
}
318+
$clone->adapters =$adapters;
319+
320+
return$clone;
321+
}
322+
283323
publicfunctionreset():void
284324
{
285325
foreach ($this->adaptersas$adapter) {

‎src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,17 +335,17 @@ protected function doSave(array $values, int $lifetime): array|bool
335335
/**
336336
* @internal
337337
*/
338-
protectedfunctiongetId(mixed$key):string
338+
protectedfunctiongetId(mixed$key, ?string$namespace =null):string
339339
{
340340
if ('pgsql' !==$this->platformName ??=$this->getPlatformName()) {
341-
returnparent::getId($key);
341+
returnparent::getId($key,$namespace);
342342
}
343343

344344
if (str_contains($key,"\0") ||str_contains($key,'%') || !preg_match('//u',$key)) {
345345
$key =rawurlencode($key);
346346
}
347347

348-
returnparent::getId($key);
348+
returnparent::getId($key,$namespace);
349349
}
350350

351351
privatefunctiongetPlatformName():string

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
usePsr\Cache\CacheItemInterface;
1515
useSymfony\Component\Cache\CacheItem;
1616
useSymfony\Contracts\Cache\CacheInterface;
17+
useSymfony\Contracts\Cache\NamespacedPoolInterface;
1718

1819
/**
1920
* @author Titouan Galopin <galopintitouan@gmail.com>
2021
*/
21-
class NullAdapterimplements AdapterInterface, CacheInterface
22+
class NullAdapterimplements AdapterInterface, CacheInterface, NamespacedPoolInterface
2223
{
2324
privatestatic\Closure$createCacheItem;
2425

@@ -94,6 +95,18 @@ public function delete(string $key): bool
9495
return$this->deleteItem($key);
9596
}
9697

98+
publicfunctionpushNamespace(string$namespace):static
99+
{
100+
return$this;
101+
}
102+
103+
publicfunctionpopNamespace(?string &$namespace =null):static
104+
{
105+
$namespace ='';
106+
107+
return$this;
108+
}
109+
97110
privatefunctiongenerateItems(array$keys):\Generator
98111
{
99112
$f =self::$createCacheItem;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp