13
13
14
14
use Psr \Cache \CacheItemInterface ;
15
15
use Psr \Cache \CacheItemPoolInterface ;
16
+ use Symfony \Component \Cache \CacheInterface ;
16
17
use Symfony \Component \Cache \CacheItem ;
17
18
use Symfony \Component \Cache \Exception \InvalidArgumentException ;
18
19
use Symfony \Component \Cache \PruneableInterface ;
19
20
use Symfony \Component \Cache \ResettableInterface ;
21
+ use Symfony \Component \Cache \Traits \GetTrait ;
20
22
21
23
/**
22
24
* Chains several adapters together.
26
28
*
27
29
* @author Kévin Dunglas <[email protected] >
28
30
*/
29
- class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
31
+ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
30
32
{
33
+ use GetTrait;
34
+
31
35
private $ adapters = array ();
32
36
private $ adapterCount ;
33
- private $ saveUp ;
37
+ private $ syncItem ;
34
38
35
39
/**
36
- * @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
37
- * @param int $maxLifetime The max lifetime of items propagated from lower adapters to upper ones
40
+ * @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
41
+ * @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones
38
42
*/
39
- public function __construct (array $ adapters , int $ maxLifetime = 0 )
43
+ public function __construct (array $ adapters , int $ defaultLifetime = 0 )
40
44
{
41
45
if (!$ adapters ) {
42
46
throw new InvalidArgumentException ('At least one adapter must be specified. ' );
@@ -55,16 +59,20 @@ public function __construct(array $adapters, int $maxLifetime = 0)
55
59
}
56
60
$ this ->adapterCount = count ($ this ->adapters );
57
61
58
- $ this ->saveUp = \Closure::bind (
59
- function ($ adapter , $ item ) use ($ maxLifetime ) {
60
- $ origDefaultLifetime = $ item ->defaultLifetime ;
62
+ $ this ->syncItem = \Closure::bind (
63
+ function ($ sourceItem , $ item ) use ($ defaultLifetime ) {
64
+ $ item ->value = $ sourceItem ->value ;
65
+ $ item ->expiry = $ sourceItem ->expiry ;
66
+ $ item ->isHit = $ sourceItem ->isHit ;
61
67
62
- if (0 < $ maxLifetime && ($ origDefaultLifetime <= 0 || $ maxLifetime < $ origDefaultLifetime )) {
63
- $ item ->defaultLifetime = $ maxLifetime ;
68
+ if (0 < $ sourceItem ->defaultLifetime && $ sourceItem ->defaultLifetime < $ defaultLifetime ) {
69
+ $ defaultLifetime = $ sourceItem ->defaultLifetime ;
70
+ }
71
+ if (0 < $ defaultLifetime && ($ item ->defaultLifetime <= 0 || $ defaultLifetime < $ item ->defaultLifetime )) {
72
+ $ item ->defaultLifetime = $ defaultLifetime ;
64
73
}
65
74
66
- $ adapter ->save ($ item );
67
- $ item ->defaultLifetime = $ origDefaultLifetime ;
75
+ return $ item ;
68
76
},
69
77
null ,
70
78
CacheItem::class
@@ -74,20 +82,47 @@ function ($adapter, $item) use ($maxLifetime) {
74
82
/**
75
83
* {@inheritdoc}
76
84
*/
77
- public function getItem ( $ key )
85
+ public function get ( string $ key, callable $ callback )
78
86
{
79
- $ saveUp = $ this ->saveUp ;
87
+ $ computedItem = null ;
88
+ $ i = -1 ;
89
+ $ wrap = function (CacheItem $ item = null ) use ($ key , $ callback , &$ wrap , &$ i , &$ computedItem ) {
90
+ if (!$ adapter = $ this ->adapters [++$ i ] ?? null ) {
91
+ $ value = $ callback ($ item );
92
+ $ computedItem = $ item ;
93
+ } elseif ($ adapter instanceof CacheInterface) {
94
+ $ value = $ adapter ->get ($ key , $ wrap );
95
+ } else {
96
+ $ value = $ this ->doGet ($ adapter , $ key , $ wrap );
97
+ }
98
+ if (null !== $ item ) {
99
+ ($ this ->syncItem )($ computedItem ?? $ item , $ item );
100
+ }
101
+
102
+ return $ value ;
103
+ };
80
104
105
+ return $ wrap ();
106
+ }
107
+
108
+ /**
109
+ * {@inheritdoc}
110
+ */
111
+ public function getItem ($ key )
112
+ {
113
+ $ misses = array ();
81
114
foreach ($ this ->adapters as $ i => $ adapter ) {
82
115
$ item = $ adapter ->getItem ($ key );
83
116
84
117
if ($ item ->isHit ()) {
85
118
while (0 <= --$ i ) {
86
- $ saveUp ( $ this ->adapters [$ i ], $ item );
119
+ $ this ->adapters [$ i ]-> save (( $ this -> syncItem )( $ item , $ misses [ $ i ]) );
87
120
}
88
121
89
122
return $ item ;
90
123
}
124
+
125
+ $ misses [$ i ] = $ item ;
91
126
}
92
127
93
128
return $ item ;
@@ -104,6 +139,7 @@ public function getItems(array $keys = array())
104
139
private function generateItems ($ items , $ adapterIndex )
105
140
{
106
141
$ missing = array ();
142
+ $ misses = array ();
107
143
$ nextAdapterIndex = $ adapterIndex + 1 ;
108
144
$ nextAdapter = isset ($ this ->adapters [$ nextAdapterIndex ]) ? $ this ->adapters [$ nextAdapterIndex ] : null ;
109
145
@@ -112,17 +148,17 @@ private function generateItems($items, $adapterIndex)
112
148
yield $ k => $ item ;
113
149
} else {
114
150
$ missing [] = $ k ;
151
+ $ misses [$ k ] = $ item ;
115
152
}
116
153
}
117
154
118
155
if ($ missing ) {
119
- $ saveUp = $ this ->saveUp ;
120
156
$ adapter = $ this ->adapters [$ adapterIndex ];
121
157
$ items = $ this ->generateItems ($ nextAdapter ->getItems ($ missing ), $ nextAdapterIndex );
122
158
123
159
foreach ($ items as $ k => $ item ) {
124
160
if ($ item ->isHit ()) {
125
- $ saveUp ( $ adapter , $ item );
161
+ $ adapter -> save (( $ this -> syncItem )( $ item , $ misses [ $ k ]) );
126
162
}
127
163
128
164
yield $ k => $ item ;
0 commit comments