1313
1414use Psr \Cache \CacheItemInterface ;
1515use Psr \Cache \CacheItemPoolInterface ;
16+ use Symfony \Component \Cache \CacheInterface ;
1617use Symfony \Component \Cache \CacheItem ;
1718use Symfony \Component \Cache \Exception \InvalidArgumentException ;
1819use Symfony \Component \Cache \PruneableInterface ;
1920use Symfony \Component \Cache \ResettableInterface ;
21+ use Symfony \Component \Cache \Traits \GetTrait ;
2022
2123/**
2224 * Chains several adapters together.
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 ;
33- private $ saveUp ;
37+ private $ syncItem ;
3438
3539 /**
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
3842 */
39- public function __construct (array $ adapters , int $ maxLifetime = 0 )
43+ public
9E88
function __construct (array $ adapters , int $ defaultLifetime = 0 )
4044 {
4145 if (!$ adapters ) {
4246 throw new InvalidArgumentException ('At least one adapter must be specified. ' );
@@ -55,16 +59,20 @@ public function __construct(array $adapters, int $maxLifetime = 0)
5559 }
5660 $ this ->adapterCount = count ($ this ->adapters );
5761
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 ;
6167
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 ;
6473 }
6574
66- $ adapter ->save ($ item );
67- $ item ->defaultLifetime = $ origDefaultLifetime ;
75+ return $ item ;
6876 },
6977 null ,
7078 CacheItem::class
@@ -74,20 +82,47 @@ function ($adapter, $item) use ($maxLifetime) {
7482 /**
7583 * {@inheritdoc}
7684 */
77- public function getItem ( $ key )
85+ public function get ( string $ key, callable $ callback )
7886 {
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+ };
80104
105+ return $ wrap ();
106+ }
107+
108+ /**
109+ * {@inheritdoc}
110+ */
38BA
111+ public function getItem ($ key )
112+ {
113+ $ misses = array ();
81114 foreach ($ this ->adapters as $ i => $ adapter ) {
82115 $ item = $ adapter ->getItem ($ key );
83116
84117 if ($ item ->isHit ()) {
85118 while (0 <= --$ i ) {
86- $ saveUp ( $ this ->adapters [$ i ], $ item );
119+ $ this ->adapters [$ i ]-> save (( $ this -> syncItem )( $ item , $ misses [ $ i ]) );
87120 }
88121
89122 return $ item ;
90123 }
124+
125+ $ misses [$ i ] = $ item ;
91126 }
92127
93128 return $ item ;
@@ -104,6 +139,7 @@ public function getItems(array $keys = array())
104139 private function generateItems ($ items , $ adapterIndex )
105140 {
106141 $ missing = array ();
142+ $ misses = array ();
107143 $ nextAdapterIndex = $ adapterIndex + 1 ;
108144 $ nextAdapter = isset ($ this ->adapters [$ nextAdapterIndex ]) ? $ this ->adapters [$ nextAdapterIndex ] : null ;
109145
@@ -112,17 +148,17 @@ private function generateItems($items, $adapterIndex)
112148 yield $ k => $ item ;
113149 } else {
114150 $ missing [] = $ k ;
151+ $ misses [$ k ] = $ item ;
115152 }
116153 }
117154
118155 if ($ missing ) {
119- $ saveUp = $ this ->saveUp ;
120156 $ adapter = $ this ->adapters [$ adapterIndex ];
121157 $ items = $ this ->generateItems ($ nextAdapter ->getItems ($ missing ), $ nextAdapterIndex );
122158
123159 foreach ($ items as $ k => $ item ) {
124160 if ($ item ->isHit ()) {
125- $ saveUp ( $ adapter , $ item );
161+ $ adapter -> save (( $ this -> syncItem )( $ item , $ misses [ $ k ]) );
126162 }
127163
128164 yield $ k => $ item ;
0 commit comments