8000 [Cache] Fix double fetch in ProxyAdapter · symfony/symfony@040f53d · GitHub
[go: up one dir, main page]

Skip to content

Commit 040f53d

Browse files
[Cache] Fix double fetch in ProxyAdapter
1 parent c87c175 commit 040f53d

File tree

6 files changed

+69
-28
lines changed

6 files changed

+69
-28
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function ($key, $value, $isHit) use ($defaultLifetime) {
4242

4343
return $item;
4444
},
45-
$this,
45+
null,
4646
CacheItem::class
4747
);
4848
$this->mergeByLifetime = \Closure::bind(
@@ -63,7 +63,7 @@ function ($deferred, $namespace, &$expiredIds) {
6363

6464
return $byLifetime;
6565
},
66-
$this,
66+
null,
6767
CacheItem::class
6868
);
6969
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ function ($key, $value, $isHit) use ($defaultLifetime) {
4545

4646
return $item;
4747
},
48-
$this,
48+
null,
4949
CacheItem::class
5050
);
5151
}
@@ -132,9 +132,9 @@ public function save(CacheItemInterface $item)
132132
return false;
133133
}
134134
$item = (array) $item;
135-
$key = $item[CacheItem::CAST_PREFIX.'key'];
136-
$value = $item[CacheItem::CAST_PREFIX.'value'];
137-
$expiry = $item[CacheItem::CAST_PREFIX.'expiry'];
135+
$key = $item["\0*\0key"];
136+
$value = $item["\0*\0value"];
137+
$expiry = $item["\0*\0expiry"];
138138

139139
if (null !== $expiry && $expiry <= time()) {
140140
$this->deleteItem($key);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function ($adapter, $item) use ($maxLifetime) {
6262
$adapter->save($item);
6363
$item->defaultLifetime = $origDefaultLifetime;
6464
},
65-
$this,
65+
null,
6666
CacheItem::class
6767
);
6868
}

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

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,28 @@ class ProxyAdapter implements AdapterInterface
2424
private $namespace;
2525
private $namespaceLen;
2626
private $createCacheItem;
27+
private $poolHash;
2728

2829
public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0)
2930
{
3031
$this->pool = $pool;
32+
$this->poolHash = $poolHash = spl_object_hash($pool);
3133
$this->namespace = '' === $namespace ? '' : $this->getId($namespace);
3234
$this->namespaceLen = strlen($namespace);
3335
$this->createCacheItem = \Closure::bind(
34-
function ($key, $value, $isHit) use ($defaultLifetime) {
36+
function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
3537
$item = new CacheItem();
3638
$item->key = $key;
37-
$item->value = $value;
38-
$item->isHit = $isHit;
39+
$item->value = $innerItem->get();
40+
$item->isHit = $innerItem->isHit();
3941
$item->defaultLifetime = $defaultLifetime;
42+
$item->innerItem = $innerItem;
43+
$item->poolHash = $poolHash;
44+
$innerItem->set(null);
4045

4146
return $item;
4247
},
43-
$this,
48+
null,
4449
CacheItem::class
4550
);
4651
}
@@ -53,7 +58,7 @@ public function getItem($key)
5358
$f = $this->createCacheItem;
5459
$item = $this->pool->getItem($this->getId($key));
5560

56-
return $f($key, $item->get(), $item->isHit());
61+
return $f($key, $item);
5762
}
5863

5964
/**
@@ -138,12 +143,12 @@ private function doSave(CacheItemInterface $item, $method)
138143
return false;
139144
}
140145
$item = (array) $item;
141-
$expiry = $item[CacheItem::CAST_PREFIX.'expiry'];
142-
$poolItem = $this->pool->getItem($this->namespace.$item[CacheItem::CAST_PREFIX.'key']);
143-
$poolItem->set($item[CacheItem::CAST_PREFIX.'value']);
144-
$poolItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null);
146+
$expiry = $item["\0*\0expiry"];
147+
$innerItem = $item["\0*\0poolHash"] === $this->poolHash ? $item["\0*\0innerItem"] : $this->pool->getItem($this->namespace.$item["\0*\0key"]);
148+
$innerItem->set($item["\0*\0value"]);
149+
$innerItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null);
145150

146-
return $this->pool->$method($poolItem);
151+
return $this->pool->$method($innerItem);
147152
}
148153

149154
private function generateItems($items)
@@ -155,7 +160,7 @@ private function generateItems($items)
155160
$key = substr($key, $this->namespaceLen);
156161
}
157162

158-
yield $key => $f($key, $item->get(), $item->isHit());
163+
yield $key => $f($key, $item);
159164
}
160165
}
161166

src/Symfony/Component/Cache/CacheItem.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,13 @@
2020
*/
2121
final class CacheItem implements CacheItemInterface
2222
{
23-
/**
24-
* @internal
25-
*/
26-
const CAST_PREFIX = "\0Symfony\Component\Cache\CacheItem\0";
27-
28-
private $key;
29-
private $value;
30-
private $isHit;
31-
private $expiry;
32-
private $defaultLifetime;
23+
protected $key;
24+
protected $value;
25+
protected $isHit;
26+
protected $expiry;
27+
protected $defaultLifetime;
28+
protected $innerItem;
29+
protected $poolHash;
3330

3431
/**
3532
* {@inheritdoc}

src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

1414
use Cache\IntegrationTests\CachePoolTest;
15+
use Psr\Cache\CacheItemInterface;
1516
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1617
use Symfony\Component\Cache\Adapter\ProxyAdapter;
18+
use Symfony\Component\Cache\CacheItem;
1719

1820
/**
1921
* @group time-sensitive
@@ -29,4 +31,41 @@ public function createCachePool()
2931
{
3032
return new ProxyAdapter(new ArrayAdapter());
3133
}
34+
35+
/**
36+
* @expectedException Exception
37+
* @expectedExceptionMessage OK bar
38+
*/
39+
public function testProxyfiedItem()
40+
{
41+
$item = new CacheItem();
42+
$pool = new ProxyAdapter(new TestingArrayAdapter($item));
43+
44+
$proxyItem = $pool->getItem('foo');
45+
46+
$this->assertFalse($proxyItem === $item);
47+
$pool->save($proxyItem->set('bar'));
48+
}
49+
}
50+
51+
class TestingArrayAdapter extends ArrayAdapter
52+
{
53+
private $item;
54+
55+
public function __construct(CacheItemInterface $item)
56+
{
57+
$this->item = $item;
58+
}
59+
60+
public function getItem($key)
61+
{
62+
return $this->item;
63+
}
64+
65+
public function save(CacheItemInterface $item)
66+
{
67+
if ($item === $this->item) {
68+
throw new \Exception('OK '.$item->get());
69+
}
70+
}
3271
}

0 commit comments

Comments
 (0)
0