Completed
Push — 1.x ( d9db55...434f1d )
by Akihito
21s queued 12s
created

DonutRepository   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 144
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 65
dl 0
loc 144
rs 10
c 2
b 0
f 0
wmc 14

10 Methods

Rating   Name   Duplication   Size   Complexity  
A invalidateTags() 0 3 1
A purge() 0 3 1
A putStatic() 0 15 1
A __construct() 0 16 1
A getHeaderKeys() 0 3 2
A saveView() 0 7 1
A refreshDonut() 0 22 3
A setHeaders() 0 5 1
A putDonut() 0 14 1
A get() 0 13 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\QueryRepository;
6
7
use BEAR\Resource\AbstractUri;
8
use BEAR\Resource\ResourceInterface;
9
use BEAR\Resource\ResourceObject;
10
11
use function assert;
12
use function explode;
13
14
final class DonutRepository implements DonutRepositoryInterface
15
{
16
    private ResourceStorageInterface $resourceStorage;
17
    private HeaderSetter $headerSetter;
18
    private ResourceInterface $resource;
19
    private QueryRepository $queryRepository;
20
    private CdnCacheControlHeaderSetterInterface $cdnCacheControlHeaderSetter;
21
    private RepositoryLoggerInterface $logger;
22
    private DonutRenderer $renderer;
23
24
    public function __construct(
25
        QueryRepository $queryRepository,
26
        HeaderSetter $headerSetter,
27
        ResourceStorageInterface $resourceStorage,
28
        ResourceInterface $resource,
29
        CdnCacheControlHeaderSetterInterface $cdnCacheControlHeaderSetter,
30
        RepositoryLoggerInterface $logger,
31
        DonutRenderer $renderer
32
    ) {
33
        $this->resourceStorage = $resourceStorage;
34
        $this->headerSetter = $headerSetter;
35
        $this->resource = $resource;
36
        $this->queryRepository = $queryRepository;
37
        $this->cdnCacheControlHeaderSetter = $cdnCacheControlHeaderSetter;
38
        $this->logger = $logger;
39
        $this->renderer = $renderer;
40
    }
41
42
    public function get(ResourceObject $ro): ?ResourceObject
43
    {
44
        $maybeState = $this->queryRepository->get($ro->uri);
45
        $this->logger->log('try-donut-view: uri:%s', $ro->uri);
46
        if ($maybeState instanceof ResourceState) {
47
            $this->logger->log('found-donut-view: uri:%s', $ro->uri);
48
            $ro->headers = $maybeState->headers;
49
            $ro->view = $maybeState->view;
50
51
            return $ro;
52
        }
53
54
        return $this->refreshDonut($ro);
55
    }
56
57
    /**
58
     * {@inheritDoc}
59
     */
60
    public function putStatic(ResourceObject $ro, ?int $ttl = null, ?int $sMaxAge = null): ResourceObject
61
    {
62
        $this->logger->log('put-donut: uri:%s ttl:%s s-maxage:%d', (string) $ro->uri, $sMaxAge, $ttl);
63
        $keys = new SurrogateKeys($ro->uri);
64
        $headerKeys = $this->getHeaderKeys($ro);
65
        $donut = ResourceDonut::create($ro, $this->renderer, $keys, $sMaxAge, true);
66
        $donut->render($ro, $this->renderer);
67
        $this->setHeaders($keys, $ro, $sMaxAge);
68
        // delete
69
        $this->resourceStorage->invalidateTags([(new UriTag())($ro->uri)]);
70
        // save content cache and donut
71
        $this->saveView($ro, $sMaxAge);
72
        $this->resourceStorage->saveDonut($ro->uri, $donut, $ttl, $headerKeys);
73
74
        return $ro;
75
    }
76
77
    /**
78
     * {@inheritDoc}
79
     */
80
    public function putDonut(ResourceObject $ro, ?int $donutTtl): ResourceObject
81
    {
82
        $this->logger->log('put-donut: uri:%s ttl:%s', (string) $ro->uri, $donutTtl);
83
        $keys = new SurrogateKeys($ro->uri);
84
        $keyArrays = $this->getHeaderKeys($ro);
85
        $donut = ResourceDonut::create($ro, $this->renderer, $keys, $donutTtl, false);
86
        $donut->render($ro, $this->renderer);
87
        $keys->setSurrogateHeader($ro);
88
        // delete
89
        $this->resourceStorage->invalidateTags([(new UriTag())($ro->uri)]);
90
        // save donut
91
        $this->resourceStorage->saveDonut($ro->uri, $donut, $donutTtl, $keyArrays);
92
93
        return $ro;
94
    }
95
96
    /**
97
     * {@inheritDoc}
98
     */
99
    public function purge(AbstractUri $uri): void
100
    {
101
        $this->queryRepository->purge($uri);
102
    }
103
104
    /**
105
     * {@inheritDoc}
106
     */
107
    public function invalidateTags(array $tags): void
108
    {
109
        $this->resourceStorage->invalidateTags($tags);
110
    }
111
112
    private function refreshDonut(ResourceObject $ro): ?ResourceObject
113
    {
114
        $donut = $this->resourceStorage->getDonut($ro->uri);
115
        $this->logger->log('try-donut uri:%s', (string) $ro->uri);
116
        if (! $donut instanceof ResourceDonut) {
117
            $this->logger->log('no-donut-found uri:%s', (string) $ro->uri);
118
119
            return null;
120
        }
121
122
        $this->logger->log('refresh-donut: uri:%s', $ro->uri);
123
        $donut->refresh($this->resource, $ro);
124
        if (! $donut->isCacheble) {
125
            return $ro;
126
        }
127
128
        ($this->headerSetter)($ro, $donut->ttl, null);
129
        $ro->headers[Header::ETAG] .= 'r'; // mark refreshed by resource static
130
        ($this->cdnCacheControlHeaderSetter)($ro, $donut->ttl);
131
        $this->saveView($ro, $donut->ttl);
132
133
        return $ro;
134
    }
135
136
    private function saveView(ResourceObject $ro, ?int $ttl): bool
137
    {
138
        assert(isset($ro->headers[Header::ETAG]));
139
        $surrogateKeys = $ro->headers[Header::SURROGATE_KEY] ?? '';
140
        $this->resourceStorage->saveEtag($ro->uri, $ro->headers[Header::ETAG], $surrogateKeys, $ttl);
141
142
        return $this->resourceStorage->saveDonutView($ro, $ttl);
143
    }
144
145
    private function setHeaders(SurrogateKeys $keys, ResourceObject $ro, ?int $sMaxAge): void
146
    {
147
        $keys->setSurrogateHeader($ro);
148
        ($this->cdnCacheControlHeaderSetter)($ro, $sMaxAge);
149
        ($this->headerSetter)($ro, 0, null);
150
    }
151
152
    /**
153
     * @return list<string>
0 ignored issues
show
Bug introduced by
The type BEAR\QueryRepository\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
154
     */
155
    public function getHeaderKeys(ResourceObject $ro): array
156
    {
157
        return isset($ro->headers[Header::SURROGATE_KEY]) ? explode(' ', $ro->headers[Header::SURROGATE_KEY]) : [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? explo...RROGATE_KEY]) : array() returns the type array|string[] which is incompatible with the documented return type BEAR\QueryRepository\list.
Loading history...
158
    }
159
}
160