Complex classes like HTTPCacheControl often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use HTTPCacheControl, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
8 | class HTTPCacheControl extends SS_Object { |
||
9 | |||
10 | /** |
||
11 | * @var static |
||
12 | */ |
||
13 | private static $inst; |
||
14 | |||
15 | /** |
||
16 | * Store for all the current directives and their values |
||
17 | * Starts with an implicit config for disabled caching |
||
18 | * |
||
19 | * @var array |
||
20 | */ |
||
21 | private $state = array(); |
||
22 | |||
23 | /** |
||
24 | * Forcing level of previous setting; higher number wins |
||
25 | * Combination of consts belo |
||
26 | *w |
||
27 | * @var int |
||
28 | */ |
||
29 | protected $forcingLevel = 0; |
||
30 | |||
31 | /** |
||
32 | * Forcing level forced, optionally combined with one of the below. |
||
33 | */ |
||
34 | const LEVEL_FORCED = 10; |
||
35 | |||
36 | /** |
||
37 | * Forcing level caching disabled. Overrides public/private. |
||
38 | */ |
||
39 | const LEVEL_DISABLED = 3; |
||
40 | |||
41 | /** |
||
42 | * Forcing level private-cached. Overrides public. |
||
43 | */ |
||
44 | const LEVEL_PRIVATE = 2; |
||
45 | |||
46 | /** |
||
47 | * Forcing level public cached. Lowest priority. |
||
48 | */ |
||
49 | const LEVEL_PUBLIC = 1; |
||
50 | |||
51 | /** |
||
52 | * Forcing level caching enabled. |
||
53 | */ |
||
54 | const LEVEL_ENABLED = 0; |
||
55 | |||
56 | |||
57 | /** |
||
58 | * A list of allowed cache directives for HTTPResponses |
||
59 | * |
||
60 | * This doesn't include any experimental directives, |
||
61 | * use the config system to add to these if you want to enable them |
||
62 | * |
||
63 | * @config |
||
64 | * @var array |
||
65 | */ |
||
66 | private static $allowed_directives = array( |
||
67 | 'public', |
||
68 | 'private', |
||
69 | 'no-cache', |
||
70 | 'max-age', |
||
71 | 's-maxage', |
||
72 | 'must-revalidate', |
||
73 | 'proxy-revalidate', |
||
74 | 'no-store', |
||
75 | 'no-transform', |
||
76 | ); |
||
77 | |||
78 | public function __construct() |
||
87 | |||
88 | /** |
||
89 | * Instruct the cache to apply a change with a given level, optionally |
||
90 | * modifying it with a force flag to increase priority of this action. |
||
91 | * |
||
92 | * If the apply level was successful, the change is made and the internal level |
||
93 | * threshold is incremented. |
||
94 | * |
||
95 | * @param int $level Priority of the given change |
||
96 | * @param bool $force If usercode has requested this action is forced to a higher priority. |
||
97 | * Note: Even if $force is set to true, other higher-priority forced changes can still |
||
98 | * cause a change to be rejected if it is below the required threshold. |
||
99 | * @return bool True if the given change is accepted, and that the internal |
||
100 | * level threshold is updated (if necessary) to the new minimum level. |
||
101 | */ |
||
102 | protected function applyChangeLevel($level, $force) |
||
111 | |||
112 | /** |
||
113 | * Low level method for setting directives include any experimental or custom ones added via config |
||
114 | * |
||
115 | * @param string $directive |
||
116 | * @param string|bool $value |
||
117 | * |
||
118 | * @return $this |
||
119 | */ |
||
120 | public function setDirective($directive, $value = null) |
||
132 | |||
133 | /** |
||
134 | * Low level method to set directives from an associative array |
||
135 | * |
||
136 | * @param array $directives |
||
137 | * |
||
138 | * @return $this |
||
139 | */ |
||
140 | public function setDirectivesFromArray($directives) |
||
157 | |||
158 | /** |
||
159 | * Low level method for removing directives |
||
160 | * |
||
161 | * @param string $directive |
||
162 | * |
||
163 | * @return $this |
||
164 | */ |
||
165 | public function removeDirective($directive) |
||
170 | |||
171 | /** |
||
172 | * Low level method to check if a directive is currently set |
||
173 | * |
||
174 | * @param string $directive |
||
175 | * |
||
176 | * @return bool |
||
177 | */ |
||
178 | public function hasDirective($directive) |
||
182 | |||
183 | /** |
||
184 | * Low level method to get the value of a directive |
||
185 | * |
||
186 | * Note that `null` value is acceptable for a directive |
||
187 | * |
||
188 | * @param string $directive |
||
189 | * |
||
190 | * @return string|false|null |
||
191 | */ |
||
192 | public function getDirective($directive) |
||
199 | |||
200 | /** |
||
201 | * The cache should not store anything about the client request or server response. |
||
202 | * |
||
203 | * Set the no-store directive (also removes max-age and s-maxage for consistency purposes) |
||
204 | * |
||
205 | * @param bool $noStore |
||
206 | * |
||
207 | * @return $this |
||
208 | */ |
||
209 | public function setNoStore($noStore = true) |
||
220 | |||
221 | /** |
||
222 | * Forces caches to submit the request to the origin server for validation before releasing a cached copy. |
||
223 | * |
||
224 | * @param bool $noCache |
||
225 | * |
||
226 | * @return $this |
||
227 | */ |
||
228 | public function setNoCache($noCache = true) |
||
237 | |||
238 | /** |
||
239 | * Specifies the maximum amount of time (seconds) a resource will be considered fresh. |
||
240 | * This directive is relative to the time of the request. |
||
241 | * |
||
242 | * @param int $age |
||
243 | * |
||
244 | * @return $this |
||
245 | */ |
||
246 | public function setMaxAge($age) |
||
251 | |||
252 | /** |
||
253 | * Overrides max-age or the Expires header, but it only applies to shared caches (e.g., proxies) |
||
254 | * and is ignored by a private cache. |
||
255 | * |
||
256 | * @param int $age |
||
257 | * |
||
258 | * @return $this |
||
259 | */ |
||
260 | public function setSharedMaxAge($age) |
||
265 | |||
266 | /** |
||
267 | * The cache must verify the status of the stale resources before using it and expired ones should not be used. |
||
268 | * |
||
269 | * @param bool $mustRevalidate |
||
270 | * |
||
271 | * @return $this |
||
272 | */ |
||
273 | public function setMustRevalidate($mustRevalidate = true) |
||
282 | |||
283 | /** |
||
284 | * Simple way to set cache control header to a cacheable state. |
||
285 | * Use this method over `publicCache()` if you are unsure about caching details. |
||
286 | * |
||
287 | * Removes `no-store` and `no-cache` directives; other directives will remain in place. |
||
288 | * Use alongside `setMaxAge()` to indicate caching. |
||
289 | * |
||
290 | * Does not set `public` directive. Usually, `setMaxAge()` is sufficient. Use `publicCache()` if this is explicitly required. |
||
291 | * See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#public_vs_private |
||
292 | * |
||
293 | * @see https://docs.silverstripe.org/en/developer_guides/performance/http_cache_headers/ |
||
294 | * @param bool $force Force the cache to public even if its unforced private or public |
||
295 | * @return $this |
||
296 | */ |
||
297 | public function enableCache($force = false) |
||
309 | |||
310 | /** |
||
311 | * Simple way to set cache control header to a non-cacheable state. |
||
312 | * Use this method over `privateCache()` if you are unsure about caching details. |
||
313 | * Takes precendence over unforced `enableCache()`, `privateCache()` or `publicCache()` calls. |
||
314 | * |
||
315 | * Removes all state and replaces it with `no-cache, no-store, must-revalidate`. Although `no-store` is sufficient |
||
316 | * the others are added under recommendation from Mozilla (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Examples) |
||
317 | * |
||
318 | * Does not set `private` directive, use `privateCache()` if this is explicitly required. |
||
319 | * See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#public_vs_private |
||
320 | * |
||
321 | * @see https://docs.silverstripe.org/en/developer_guides/performance/http_cache_headers/ |
||
322 | * @param bool $force Force the cache to diabled even if it's forced private or public |
||
323 | * @return $this |
||
324 | */ |
||
325 | public function disableCache($force = false) |
||
340 | |||
341 | /** |
||
342 | * Advanced way to set cache control header to a non-cacheable state. |
||
343 | * Indicates that the response is intended for a single user and must not be stored by a shared cache. |
||
344 | * A private cache (e.g. Web Browser) may store the response. Also removes `public` as this is a contradictory directive. |
||
345 | * |
||
346 | * @see https://docs.silverstripe.org/en/developer_guides/performance/http_cache_headers/ |
||
347 | * @param bool $force Force the cache to private even if it's forced public |
||
348 | * @return $this |
||
349 | */ |
||
350 | public function privateCache($force = false) |
||
365 | |||
366 | /** |
||
367 | * Advanced way to set cache control header to a cacheable state. |
||
368 | * Indicates that the response may be cached by any cache. (eg: CDNs, Proxies, Web browsers) |
||
369 | * Also removes `private` as this is a contradictory directive |
||
370 | * |
||
371 | * @see https://docs.silverstripe.org/en/developer_guides/performance/http_cache_headers/ |
||
372 | * @param bool $force Force the cache to public even if it's private, unless it's been forced private |
||
373 | * @return $this |
||
374 | */ |
||
375 | public function publicCache($force = false) |
||
389 | |||
390 | /** |
||
391 | * Generate and add the `Cache-Control` header to a response object |
||
392 | * |
||
393 | * @param SS_HTTPResponse $response |
||
394 | * |
||
395 | * @return $this |
||
396 | */ |
||
397 | public function applyToResponse($response) |
||
405 | |||
406 | /** |
||
407 | * Generate the cache header |
||
408 | * |
||
409 | * @return string |
||
410 | */ |
||
411 | protected function generateCacheHeader() |
||
423 | |||
424 | /** |
||
425 | * Generate all headers to output |
||
426 | * |
||
427 | * @return array |
||
428 | */ |
||
429 | public function generateHeaders() |
||
435 | |||
436 | /** |
||
437 | * Reset registered http cache control and force a fresh instance to be built |
||
438 | */ |
||
439 | public static function reset() { |
||
442 | } |
||
443 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.