Completed
Push — master ( fc9daf...df9d2c )
by Dion
01:00
created

DefaultCache::isHit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
1
<?php
2
3
declare (strict_types=1);
4
5
namespace Tardigrades\SectionField\Service;
6
7
use Psr\Cache\CacheItemInterface;
8
use Symfony\Component\Cache\Adapter\AdapterInterface;
9
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
10
use Tardigrades\SectionField\ValueObject\FullyQualifiedClassName;
11
12
/**
13
 * Class DefaultCache
14
 * @package Tardigrades\SectionField\Service
15
 */
16
class DefaultCache implements CacheInterface
17
{
18
    /** @var AdapterInterface */
19
    protected $cache;
20
21
    /** @var bool */
22
    protected $enabled;
23
24
    /** @var CacheItemInterface */
25
    private $item;
26
27
    /** @var string */
28
    private $sectionHandle;
29
30
    /** @var string */
31
    private $fieldKey;
32
33
    /** @var string */
34
    private $context;
35
    
36
    /** @var string[] */
37
    private $relationships;
38
39
    /**
40
     * DefaultCache constructor.
41
     *
42
     * @param TagAwareAdapterInterface $cache
43
     * @param bool $enabled
44
     */
45
    public function __construct(
46
        TagAwareAdapterInterface $cache,
47
        bool $enabled = false
48
    ) {
49
        $this->cache = $cache;
50
        $this->enabled = $enabled;
51
        $this->item = null;
52
        $this->sectionHandle = null;
53
        $this->fieldKey = null;
54
        $this->relationships = null;
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function start(
61
        FullyQualifiedClassName $fullyQualifiedClassName,
62
        array $requestedFields = null,
63
        string $context = null,
64
        string $id = null
65
    ): void {
66
        if ($this->enabled) {
67
            try {
68
                $this->item = $this->cache->getItem(
69
                    $this->getItemKey(
70
                        (string)$fullyQualifiedClassName,
71
                        $requestedFields,
72
                        $context,
73
                        $id
74
                    )
75
                );
76
                $this->context = sha1($context);
77
                $this->sectionHandle = sha1((string)$fullyQualifiedClassName);
78
                $this->fieldKey = $this->getFieldKey($requestedFields);
79
                $this->relationships = $this->getRelationships($fullyQualifiedClassName);
80
            } catch (\Exception $exception) {
81
                $this->enabled = false;
82
            }
83
        }
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    public function set(array $data): void
90
    {
91
        if ($this->enabled) {
92
            $this->item->set($data);
93
            $this->item->tag($this->sectionHandle);
94
            $this->item->tag($this->fieldKey);
95
            $this->item->tag($this->context);
96
            foreach ($this->relationships as $relationship) {
97
                $this->item->tag(sha1($relationship));
98
            }
99
            $this->cache->save($this->item);
100
        }
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function isHit(): bool
107
    {
108
        if (!$this->enabled) {
109
            return false;
110
        }
111
        return $this->item->isHit();
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117
    public function get(): array
118
    {
119
        if (!$this->enabled) {
120
            return [];
121
        }
122
        return $this->item->get();
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function invalidateForSection(FullyQualifiedClassName $fullyQualifiedClassName): void
129
    {
130
        if ($this->enabled) {
131
            $this->cache->invalidateTags([sha1((string)$fullyQualifiedClassName)]);
0 ignored issues
show
Bug introduced by
The method invalidateTags() does not exist on Symfony\Component\Cache\Adapter\AdapterInterface. It seems like you code against a sub-type of Symfony\Component\Cache\Adapter\AdapterInterface such as Symfony\Component\Cache\...agAwareAdapterInterface or Symfony\Component\Cache\...raceableTagAwareAdapter. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

131
            $this->cache->/** @scrutinizer ignore-call */ 
132
                          invalidateTags([sha1((string)$fullyQualifiedClassName)]);
Loading history...
132
        }
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function invalidateForContext(string $context): void
139
    {
140
        if ($this->enabled) {
141
            $this->cache->invalidateTags([sha1($context)]);
142
        }
143
    }
144
145
    /**
146
     * Get the key for the item so the key will be unique for this
147
     * specific cache item and can't be unexpectedly overridden.
148
     *
149
     * @param string $sectionHandle
150
     * @param array $requestedFields
151
     * @param string|null $context
152
     * @param string|null $id
153
     * @return string
154
     */
155
    private function getItemKey(
156
        string $sectionHandle,
157
        array $requestedFields = null,
158
        string $context = null,
159
        string $id = null
160
    ): string
161
    {
162
        return sha1($sectionHandle) .
163
            $this->getFieldKey($requestedFields) .
164
            $this->getContextKey($context) .
165
            $this->getIdKey($id);
166
    }
167
168
    /**
169
     * Make sure the context is as a key and sha1.
170
     * In some cases the context could be a fully qualified class name
171
     * and therefore contain invalid characters for use in a key
172
     *
173
     * @param string|null $context
174
     * @return string
175
     */
176
    private function getContextKey(string $context = null): string
177
    {
178
        return !is_null($context) ? ('.' . sha1($context)) : '.no-context';
179
    }
180
181
    /**
182
     * A lot of calls contain the fields one want's to have in return.
183
     * Make sure this is also added to the item key.
184
     *
185
     * @param array $requestedFields
186
     * @return string
187
     */
188
    private function getFieldKey(array $requestedFields = null): string
189
    {
190
        if (is_null($requestedFields)) {
191
            return 'no-field-key';
192
        }
193
        return $fieldKey = '.' . sha1(implode(',', $requestedFields));
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldKey is dead and can be removed.
Loading history...
194
    }
195
196
    /**
197
     * Cache a specific entry? Add the id.
198
     *
199
     * @param string|null $id
200
     * @return string
201
     */
202
    private function getIdKey(string $id = null): string
203
    {
204
        return !is_null($id) ? ('.' . $id) : '.no-id';
205
    }
206
207
    /**
208
     * Entries can have relationships, make sure to tag them.
209
     *
210
     * @param FullyQualifiedClassName $fullyQualifiedClassName
211
     * @return array
212
     * @throws UnableToGetEntityMetadataException
213
     */
214
    private function getRelationships(FullyQualifiedClassName $fullyQualifiedClassName): array
215
    {
216
        try {
217
            $fields = (string)$fullyQualifiedClassName;
218
            $relationships = [];
219
            foreach ($fields::FIELDS as $field) {
220
                try {
221
                    if (!is_null($field['relationship']['class'])) {
222
                        $relationships[] = $field['relationship']['class'];
223
                    }
224
                } catch (\Exception $exception) {
225
                    // Just go on
226
                }
227
            }
228
            return $relationships;
229
        } catch (\Exception $exception) {
230
            throw new UnableToGetEntityMetadataException(
231
                'Cannot get ::FIELDS' . $exception->getMessage()
232
            );
233
        }
234
    }
235
}
236