71 lines
2 KiB
Markdown
71 lines
2 KiB
Markdown
---
|
|
title: Caching with decorators
|
|
date: 2025-04-06
|
|
permalink: daily/2025/04/06/caching
|
|
tags:
|
|
- software-development
|
|
- drupal
|
|
- php
|
|
cta: ~
|
|
snippet: |
|
|
TODO
|
|
---
|
|
|
|
As well as [working with different versions of an API][0], I was able to use the same technique I wrote about yesterday to easily add a cacheable version of the API client.
|
|
|
|
As they all implement the same `ApiClientInterface`, I can inject and decorate a client with another client, making one solely responsible for caching the result from the API whilst keeping the API interaction logic separate (aka [the Decorator design pattern][1]).
|
|
|
|
Here's an example based on the code I wrote:
|
|
|
|
```php
|
|
final class CacheableApiClient implements ApiClientInterface {
|
|
|
|
/**
|
|
* The cache duration in seconds.
|
|
*/
|
|
private const CACHE_DURATION = 3600;
|
|
|
|
public function __construct(
|
|
private readonly ApiClientInterface $client,
|
|
private readonly TimeInterface $time,
|
|
private readonly CacheBackendInterface $cache,
|
|
) {
|
|
}
|
|
|
|
public function getResults(): Collection {
|
|
$key = $this->getCacheKey();
|
|
|
|
$cache = $this->cache->get($key);
|
|
|
|
if ($cache !== FALSE) {
|
|
return $cache->data;
|
|
}
|
|
|
|
$result = $this->client->getResults();
|
|
|
|
$this->cache->set(
|
|
cid: $key,
|
|
data: $result,
|
|
expire: $this->time->getRequestTime() + self::CACHE_DURATION,
|
|
);
|
|
|
|
return $result;
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
Nothing in this instance is specific to either version of the API.
|
|
|
|
This client is only concerned with retrieving and saving cache data, and delegating any other logic to the original version.
|
|
|
|
With this approach, I can switch between `V1ApiClient`, `V2ApiClient` or any other version with the same methods without having to reimplement caching as that's handled within the `CacheableApiClient`.
|
|
|
|
But what if I don't want to interact with the API at all?
|
|
|
|
For local development, I have a `FakeApiClient` that returns a static response that I can work with.
|
|
|
|
The possibilities are endless.
|
|
|
|
[0]: {{site.url}}/daily/2025/04/05/strategies
|
|
[1]: {{site.url}}/daily/2022/12/08/the-decorator-design-pattern
|