-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCache_Middleware.php
More file actions
141 lines (118 loc) · 4.15 KB
/
Copy pathCache_Middleware.php
File metadata and controls
141 lines (118 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php
/**
* Cache_Middleware class
*
* @package Mantle
*/
namespace Mantle\Http_Client;
use Closure;
use DateTimeInterface;
use Mantle\Cache\SWR_Storage;
use function Mantle\Support\Helpers\normalize_cache_ttl;
/**
* Cache Middleware for Http Client.
*
* Allows for simple caching of HTTP requests.
*/
class Cache_Middleware {
/**
* Cache group.
*/
public const CACHE_GROUP = 'httpclient';
/**
* Constructor.
*
* @param int|DateTimeInterface|Closure $ttl Time to live for the cache.
* @param string|null $key Cache key to use.
*/
public function __construct( protected int|DateTimeInterface|Closure $ttl, public readonly ?string $key = null ) {}
/**
* Invoke the middleware.
*
* @param Pending_Request $request Request to process.
* @param Closure $next Next middleware in the stack.
* @return Response Response from the request.
*/
public function __invoke( Pending_Request $request, Closure $next ): Response {
$cache_key = $this->get_cache_key( $request );
$cache = wp_cache_get( $cache_key, self::CACHE_GROUP );
// If the cache is a SWR_Storage instance, get the response value.
if ( $cache && $cache instanceof SWR_Storage && $cache->value instanceof Response ) {
$cache = $cache->value;
}
if ( $cache && $cache instanceof Response ) {
$cache->cached = Cache_Status::CACHED;
/**
* Fires when a cached HTTP response is retrieved.
*
* @param Pending_Request $request The HTTP request.
* @param Response $cache The cached response.
* @param string $cache_key The cache key used.
*/
do_action( 'mantle_http_client_cache_hit', $request, $cache, $cache_key );
return $cache;
}
$response = $next( $request );
$response->cached = Cache_Status::MISSED;
/**
* Fires when a HTTP response is cached.
*
* @param Pending_Request $request The HTTP request.
* @param Response $response The cached response.
*/
do_action( 'mantle_http_client_cached', $request, $response );
wp_cache_set( $cache_key, $response, self::CACHE_GROUP, $this->calculate_ttl( $request, $response ) ); // phpcs:ignore WordPressVIPMinimum.Performance.LowExpiryCacheTime.CacheTimeUndetermined
return $response;
}
/**
* Purge the cache for a request.
*
* @param Pending_Request $request Request to purge the cache for.
*/
public function purge( Pending_Request $request ): bool {
return wp_cache_delete( $this->get_cache_key( $request ), self::CACHE_GROUP );
}
/**
* Retrieve the cache key for the request.
*
* @param Pending_Request $request Request to retrieve the cache key for.
*/
protected function get_cache_key( Pending_Request $request ): string {
return $this->key ?? md5( (string) json_encode( [ // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
$request->base_url(),
$request->url(),
$request->method(),
$request->body(),
$request->headers(),
] ) );
}
/**
* Calculate the time to live for the cache in seconds.
*
* @param Pending_Request $request Request to calculate the TTL for.
* @param Response $response Response to calculate the TTL for.
*/
private function calculate_ttl( Pending_Request $request, Response $response ): int {
$ttl = $this->ttl;
if ( $ttl instanceof Closure ) {
$ttl = $this->invoke_expiration_callback( $ttl, $request, $response );
}
return normalize_cache_ttl( $ttl );
}
/**
* Invoke the callback with the request and response and validate the return type.
*
* @throws \InvalidArgumentException If the callback does not return an integer or DateTimeInterface.
*
* @param Closure $callback Callback to invoke.
* @param Pending_Request $request Request to pass to the callback.
* @param Response $response Response to pass to the callback.
*/
protected function invoke_expiration_callback( Closure $callback, Pending_Request $request, Response $response ): int|DateTimeInterface {
$value = $callback( $request, $response );
if ( ! is_int( $value ) && ! $value instanceof DateTimeInterface ) {
throw new \InvalidArgumentException( 'Callback must return an integer or DateTimeInterface.' );
}
return $value;
}
}