-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathQueryRepository.php
More file actions
124 lines (99 loc) · 3.52 KB
/
QueryRepository.php
File metadata and controls
124 lines (99 loc) · 3.52 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
<?php
declare(strict_types=1);
namespace BEAR\QueryRepository;
use BEAR\QueryRepository\Exception\ExpireAtKeyNotExists;
use BEAR\RepositoryModule\Annotation\Cacheable;
use BEAR\RepositoryModule\Annotation\HttpCache;
use BEAR\Resource\AbstractUri;
use BEAR\Resource\ResourceObject;
use Override;
use ReflectionClass;
use function is_array;
use function sprintf;
use function strtotime;
use function time;
final readonly class QueryRepository implements QueryRepositoryInterface
{
public function __construct(
private RepositoryLoggerInterface $logger,
private HeaderSetter $headerSetter,
private ResourceStorageInterface $storage,
private Expiry $expiry,
) {
}
/**
* {@inheritDoc}
*/
#[Override]
public function put(ResourceObject $ro)
{
$this->logger->log('put-query-repository uri:%s', $ro->uri);
$this->storage->deleteEtag($ro->uri);
$ro->toString();
$cacheable = $this->getCacheableAnnotation($ro);
$httpCache = $this->getHttpCacheAnnotation($ro);
$ttl = $this->getExpiryTime($ro, $cacheable);
($this->headerSetter)($ro, $ttl, $httpCache);
if (isset($ro->headers[Header::ETAG])) {
$etag = $ro->headers[Header::ETAG];
$surrogateKeys = $ro->headers[Header::SURROGATE_KEY] ?? '';
$this->storage->saveEtag($ro->uri, $etag, $surrogateKeys, $ttl);
}
if ($cacheable instanceof Cacheable && $cacheable->type === 'view') {
return $this->storage->saveView($ro, $ttl);
}
return $this->storage->saveValue($ro, $ttl);
}
/**
* {@inheritDoc}
*/
#[Override]
public function get(AbstractUri $uri): ResourceState|null
{
$state = $this->storage->get($uri);
if (! $state instanceof ResourceState) {
return null;
}
$state->headers[Header::AGE] = (string) (time() - (int) strtotime($state->headers[Header::LAST_MODIFIED]));
return $state;
}
/**
* {@inheritDoc}
*/
#[Override]
public function purge(AbstractUri $uri)
{
$this->logger->log('purge-query-repository uri:%s', $uri);
return $this->storage->deleteEtag($uri);
}
private function getHttpCacheAnnotation(ResourceObject $ro): HttpCache|null
{
$attributes = (new ReflectionClass($ro))->getAttributes(HttpCache::class);
return isset($attributes[0]) ? $attributes[0]->newInstance() : null;
}
private function getCacheableAnnotation(ResourceObject $ro): Cacheable|null
{
$attributes = (new ReflectionClass($ro))->getAttributes(Cacheable::class);
return isset($attributes[0]) ? $attributes[0]->newInstance() : null;
}
private function getExpiryTime(ResourceObject $ro, Cacheable|null $cacheable = null): int
{
if ($cacheable === null) {
return 0;
}
if ($cacheable->expiryAt !== '') {
return $this->getExpiryAtSec($ro, $cacheable);
}
return $cacheable->expirySecond ?: $this->expiry->getTime($cacheable->expiry);
}
private function getExpiryAtSec(ResourceObject $ro, Cacheable $cacheable): int
{
if (! is_array($ro->body) || ! isset($ro->body[$cacheable->expiryAt])) {
$msg = sprintf('%s::%s', $ro::class, $cacheable->expiryAt);
throw new ExpireAtKeyNotExists($msg);
}
/** @var string $expiryAt */
$expiryAt = $ro->body[$cacheable->expiryAt];
return (int) strtotime($expiryAt) - time();
}
}