6
6
use Http \Client \Common \Plugin \Exception \RewindStreamException ;
7
7
use Http \Client \Common \Plugin \Cache \Generator \CacheKeyGenerator ;
8
8
use Http \Client \Common \Plugin \Cache \Generator \SimpleGenerator ;
9
+ use Http \Client \Common \Plugin \Cache \Listener \CacheListener ;
9
10
use Http \Message \StreamFactory ;
10
11
use Http \Promise \FulfilledPromise ;
11
12
use Psr \Cache \CacheItemInterface ;
@@ -59,6 +60,8 @@ final class CachePlugin implements Plugin
59
60
* @var array $methods list of request methods which can be cached
60
61
* @var array $respect_response_cache_directives list of cache directives this plugin will respect while caching responses
61
62
* @var CacheKeyGenerator $cache_key_generator an object to generate the cache key. Defaults to a new instance of SimpleGenerator
63
+ * @var CacheListener[] $cache_listeners an array of objects to act on the response based on the results of the cache check.
64
+ * Defaults to an empty array
62
65
* }
63
66
*/
64
67
public function __construct (CacheItemPoolInterface $ pool , StreamFactory $ streamFactory , array $ config = [])
@@ -129,7 +132,11 @@ public function handleRequest(RequestInterface $request, callable $next, callabl
129
132
$ method = strtoupper ($ request ->getMethod ());
130
133
// if the request not is cachable, move to $next
131
134
if (!in_array ($ method , $ this ->config ['methods ' ])) {
132
- return $ next ($ request );
135
+ return $ next ($ request )->then (function (ResponseInterface $ response ) use ($ request ) {
136
+ $ response = $ this ->handleCacheListeners ($ request , $ response , false , null );
137
+
138
+ return $ response ;
139
+ });
133
140
}
134
141
135
142
// If we can cache the request
@@ -141,7 +148,10 @@ public function handleRequest(RequestInterface $request, callable $next, callabl
141
148
// The array_key_exists() is to be removed in 2.0.
142
149
if (array_key_exists ('expiresAt ' , $ data ) && (null === $ data ['expiresAt ' ] || time () < $ data ['expiresAt ' ])) {
143
150
// This item is still valid according to previous cache headers
144
- return new FulfilledPromise ($ this ->createResponseFromCacheItem ($ cacheItem ));
151
+ $ response = $ this ->createResponseFromCacheItem ($ cacheItem );
152
+ $ response = $ this ->handleCacheListeners ($ request , $ response , true , $ cacheItem );
153
+
154
+ return new FulfilledPromise ($ response );
145
155
}
146
156
147
157
// Add headers to ask the server if this cache is still valid
@@ -154,14 +164,14 @@ public function handleRequest(RequestInterface $request, callable $next, callabl
154
164
}
155
165
}
156
166
157
- return $ next ($ request )->then (function (ResponseInterface $ response ) use ($ cacheItem ) {
167
+ return $ next ($ request )->then (function (ResponseInterface $ response ) use ($ request , $ cacheItem ) {
158
168
if (304 === $ response ->getStatusCode ()) {
159
169
if (!$ cacheItem ->isHit ()) {
160
170
/*
161
171
* We do not have the item in cache. This plugin did not add If-Modified-Since
162
172
* or If-None-Match headers. Return the response from server.
163
173
*/
164
- return $ response ;
174
+ return $ this -> handleCacheListeners ( $ request , $ response, false , $ cacheItem ) ;
165
175
}
166
176
167
177
// The cached response we have is still valid
@@ -171,7 +181,7 @@ public function handleRequest(RequestInterface $request, callable $next, callabl
171
181
$ cacheItem ->set ($ data )->expiresAfter ($ this ->calculateCacheItemExpiresAfter ($ maxAge ));
172
182
$ this ->pool ->save ($ cacheItem );
173
183
174
- return $ this ->createResponseFromCacheItem ($ cacheItem );
184
+ return $ this ->handleCacheListeners ( $ request , $ this -> createResponseFromCacheItem ($ cacheItem ), true , $ cacheItem );
175
185
}
176
186
177
187
if ($ this ->isCacheable ($ response )) {
@@ -196,7 +206,7 @@ public function handleRequest(RequestInterface $request, callable $next, callabl
196
206
$ this ->pool ->save ($ cacheItem );
197
207
}
198
208
199
- return $ response ;
209
+ return $ this -> handleCacheListeners ( $ request , $ response, false , isset ( $ cacheItem ) ? $ cacheItem : null ) ;
200
210
});
201
211
}
202
212
@@ -343,6 +353,7 @@ private function configureOptions(OptionsResolver $resolver)
343
353
'methods ' => ['GET ' , 'HEAD ' ],
344
354
'respect_response_cache_directives ' => ['no-cache ' , 'private ' , 'max-age ' , 'no-store ' ],
345
355
'cache_key_generator ' => null ,
356
+ 'cache_listeners ' => [],
346
357
]);
347
358
348
359
$ resolver ->setAllowedTypes ('cache_lifetime ' , ['int ' , 'null ' ]);
@@ -357,6 +368,7 @@ private function configureOptions(OptionsResolver $resolver)
357
368
358
369
return empty ($ matches );
359
370
});
371
+ $ resolver ->setAllowedTypes ('cache_listeners ' , ['array ' ]);
360
372
361
373
$ resolver ->setNormalizer ('respect_cache_headers ' , function (Options $ options , $ value ) {
362
374
if (null !== $ value ) {
@@ -441,4 +453,23 @@ private function getETag(CacheItemInterface $cacheItem)
441
453
}
442
454
}
443
455
}
456
+
457
+ /**
458
+ * Call the cache listeners, if they are set.
459
+ *
460
+ * @param RequestInterface $request
461
+ * @param ResponseInterface $response
462
+ * @param bool $cacheHit
463
+ * @param CacheItemInterface|null $cacheItem
464
+ *
465
+ * @return ResponseInterface
466
+ */
467
+ private function handleCacheListeners (RequestInterface $ request , ResponseInterface $ response , $ cacheHit , $ cacheItem )
468
+ {
469
+ foreach ($ this ->config ['cache_listeners ' ] as $ cacheListener ) {
470
+ $ response = $ cacheListener ->onCacheResponse ($ request , $ response , $ cacheHit , $ cacheItem );
471
+ }
472
+
473
+ return $ response ;
474
+ }
444
475
}
0 commit comments