Passed
Pull Request — 1.x (#99)
by Akihito
10:41
created

DonutRepository::putStatic()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 14
rs 9.9666
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
13
final class DonutRepository implements DonutRepositoryInterface
14
{
15
    /** @var ResourceStorageInterface */
16
    private $resourceStorage;
17
18
    /** @var HeaderSetter */
19
    private $headerSetter;
20
21
    /** @var ResourceInterface */
22
    private $resource;
23
24
    /** @var QueryRepository */
25
    private $queryRepository;
26
27
    /** @var CdnCacheControlHeaderSetterInterface */
28
    private $cdnCacheControlHeaderSetter;
29
30
    /** @var RepositoryLoggerInterface */
31
    private $logger;
32
33
    /** @var DonutRenderer */
34
    private $renderer;
35
36
    public function __construct(
37
        QueryRepository $queryRepository,
38
        HeaderSetter $headerSetter,
39
        ResourceStorageInterface $resourceStorage,
40
        ResourceInterface $resource,
41
        CdnCacheControlHeaderSetterInterface $cdnCacheControlHeaderSetter,
42
        RepositoryLoggerInterface $logger,
43
        DonutRenderer $renderer
44
    ) {
45
        $this->resourceStorage = $resourceStorage;
46
        $this->headerSetter = $headerSetter;
47
        $this->resource = $resource;
48
        $this->queryRepository = $queryRepository;
49
        $this->cdnCacheControlHeaderSetter = $cdnCacheControlHeaderSetter;
50
        $this->logger = $logger;
51
        $this->renderer = $renderer;
52
    }
53
54
    public function get(ResourceObject $ro): ?ResourceObject
55
    {
56
        $maybeState = $this->queryRepository->get($ro->uri);
57
        $this->logger->log('try-donut-view: uri:%s', $ro->uri);
58
        if ($maybeState instanceof ResourceState) {
59
            $this->logger->log('found-donut-view: uri:%s', $ro->uri);
60
            $ro->headers = $maybeState->headers;
61
            $ro->view = $maybeState->view;
62
63
            return $ro;
64
        }
65
66
        return $this->refreshDonut($ro);
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     */
72
    public function putStatic(ResourceObject $ro, ?int $ttl = null, ?int $sMaxAge = null): ResourceObject
73
    {
74
        $this->logger->log('put-donut: uri:%s ttl:%s s-maxage:%d', (string) $ro->uri, $sMaxAge, $ttl);
75
        $keys = new SurrogateKeys($ro->uri);
76
        $donut = ResourceDonut::create($ro, $this->renderer, $keys, $sMaxAge, true);
77
        $donut->render($ro, $this->renderer);
78
        $this->setHeaders($keys, $ro, $sMaxAge);
79
        // delete
80
        $this->resourceStorage->invalidateTags([(new UriTag())($ro->uri)]);
81
        // save content cache and donut
82
        $this->saveView($ro, $sMaxAge);
83
        $this->resourceStorage->saveDonut($ro->uri, $donut, $ttl);
84
85
        return $ro;
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91
    public function putDonut(ResourceObject $ro, ?int $donutTtl): ResourceObject
92
    {
93
        $this->logger->log('put-donut: uri:%s ttl:%s', (string) $ro->uri, $donutTtl);
94
        $keys = new SurrogateKeys($ro->uri);
95
        $donut = ResourceDonut::create($ro, $this->renderer, $keys, $donutTtl, false);
96
        $donut->render($ro, $this->renderer);
97
        $keys->setSurrogateHeader($ro);
98
        // delete
99
        $this->resourceStorage->invalidateTags([(new UriTag())($ro->uri)]);
100
        // save donut
101
        $this->resourceStorage->saveDonut($ro->uri, $donut, $donutTtl);
102
103
        return $ro;
104
    }
105
106
    /**
107
     * {@inheritDoc}
108
     */
109
    public function purge(AbstractUri $uri): void
110
    {
111
        $this->queryRepository->purge($uri);
112
    }
113
114
    /**
115
     * {@inheritDoc}
116
     */
117
    public function invalidateTags(array $tags): void
118
    {
119
        $this->resourceStorage->invalidateTags($tags);
120
    }
121
122
    private function refreshDonut(ResourceObject $ro): ?ResourceObject
123
    {
124
        $donut = $this->resourceStorage->getDonut($ro->uri);
125
        $this->logger->log('try-donut uri:%s', (string) $ro->uri);
126
        if (! $donut instanceof ResourceDonut) {
127
            $this->logger->log('no-donut-found uri:%s', (string) $ro->uri);
128
129
            return null;
130
        }
131
132
        $this->logger->log('refresh-donut: uri:%s', $ro->uri);
133
        $donut->refresh($this->resource, $ro);
134
        if (! $donut->isCacheble) {
135
            return $ro;
136
        }
137
138
        ($this->headerSetter)($ro, $donut->ttl, null);
139
        $ro->headers[Header::ETAG] .= 'r'; // mark refreshed by resource static
140
        ($this->cdnCacheControlHeaderSetter)($ro, $donut->ttl);
141
        $this->saveView($ro, $donut->ttl);
142
143
        return $ro;
144
    }
145
146
    private function saveView(ResourceObject $ro, ?int $ttl): bool
147
    {
148
        assert(isset($ro->headers[Header::ETAG]));
149
        $surrogateKeys = $ro->headers[Header::SURROGATE_KEY] ?? '';
150
        $this->resourceStorage->saveEtag($ro->uri, $ro->headers[Header::ETAG], $surrogateKeys, $ttl);
151
152
        return $this->resourceStorage->saveDonutView($ro, $ttl);
153
    }
154
155
    private function setHeaders(SurrogateKeys $keys, ResourceObject $ro, ?int $sMaxAge): void
156
    {
157
        $keys->setSurrogateHeader($ro);
158
        ($this->cdnCacheControlHeaderSetter)($ro, $sMaxAge);
159
        ($this->headerSetter)($ro, 0, null);
160
    }
161
}
162