dionsnoeijen /
sexy-field
| 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\Generator\CommonSectionInterface; |
||
| 11 | use Tardigrades\SectionField\ValueObject\FullyQualifiedClassName; |
||
| 12 | |||
| 13 | /** |
||
| 14 | * Class DefaultCache |
||
| 15 | * @package Tardigrades\SectionField\Service |
||
| 16 | */ |
||
| 17 | class DefaultCache implements CacheInterface |
||
| 18 | { |
||
| 19 | /** @var AdapterInterface */ |
||
| 20 | protected $cache; |
||
| 21 | |||
| 22 | /** @var bool */ |
||
| 23 | protected $enabled; |
||
| 24 | |||
| 25 | /** @var CacheItemInterface */ |
||
| 26 | private $item; |
||
| 27 | |||
| 28 | /** @var string */ |
||
| 29 | private $sectionHandle; |
||
| 30 | |||
| 31 | /** @var string */ |
||
| 32 | private $fieldKey; |
||
| 33 | |||
| 34 | /** @var string */ |
||
| 35 | private $context; |
||
| 36 | |||
| 37 | /** @var string[] */ |
||
| 38 | private $relationships; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * DefaultCache constructor. |
||
| 42 | * |
||
| 43 | * @param TagAwareAdapterInterface $cache |
||
| 44 | * @param bool $enabled |
||
| 45 | */ |
||
| 46 | public function __construct( |
||
| 47 | TagAwareAdapterInterface $cache, |
||
| 48 | string $enabled = 'false' |
||
| 49 | ) { |
||
| 50 | $this->cache = $cache; |
||
| 51 | $this->enabled = $enabled === 'false' ? false : true ; |
||
| 52 | $this->item = null; |
||
| 53 | $this->sectionHandle = null; |
||
| 54 | $this->fieldKey = null; |
||
| 55 | $this->relationships = null; |
||
| 56 | } |
||
| 57 | |||
| 58 | /** |
||
| 59 | * {@inheritdoc} |
||
| 60 | */ |
||
| 61 | public function start( |
||
| 62 | FullyQualifiedClassName $fullyQualifiedClassName, |
||
| 63 | array $requestedFields = null, |
||
| 64 | string $context = null, |
||
| 65 | string $id = null |
||
| 66 | ): void { |
||
| 67 | if ($this->enabled) { |
||
| 68 | try { |
||
| 69 | $this->item = $this->cache->getItem( |
||
| 70 | $this->getItemKey( |
||
| 71 | (string)$fullyQualifiedClassName, |
||
| 72 | $requestedFields, |
||
| 73 | $context, |
||
| 74 | $id |
||
| 75 | ) |
||
| 76 | ); |
||
| 77 | $this->context = sha1($context); |
||
| 78 | $this->sectionHandle = sha1((string)$fullyQualifiedClassName); |
||
| 79 | $this->fieldKey = $this->getFieldKey($requestedFields); |
||
| 80 | $this->relationships = $this->getRelationships($fullyQualifiedClassName); |
||
| 81 | } catch (\Exception $exception) { |
||
| 82 | $this->enabled = false; |
||
| 83 | } |
||
| 84 | } |
||
| 85 | } |
||
| 86 | |||
| 87 | /** |
||
| 88 | * {@inheritdoc} |
||
| 89 | */ |
||
| 90 | public function set(array $data): void |
||
| 91 | { |
||
| 92 | if ($this->enabled) { |
||
| 93 | $this->item->set($data); |
||
| 94 | $this->item->tag($this->sectionHandle); |
||
| 95 | $this->item->tag($this->fieldKey); |
||
| 96 | $this->item->tag($this->context); |
||
| 97 | foreach ($this->relationships as $relationship) { |
||
| 98 | $this->item->tag(sha1($relationship)); |
||
| 99 | } |
||
| 100 | $this->cache->save($this->item); |
||
| 101 | } |
||
| 102 | } |
||
| 103 | |||
| 104 | /** |
||
| 105 | * {@inheritdoc} |
||
| 106 | */ |
||
| 107 | public function isHit(): bool |
||
| 108 | { |
||
| 109 | if (!$this->enabled) { |
||
| 110 | return false; |
||
| 111 | } |
||
| 112 | return $this->item->isHit(); |
||
| 113 | } |
||
| 114 | |||
| 115 | /** |
||
| 116 | * {@inheritdoc} |
||
| 117 | */ |
||
| 118 | public function get(): array |
||
| 119 | { |
||
| 120 | if (!$this->enabled) { |
||
| 121 | return []; |
||
| 122 | } |
||
| 123 | return $this->item->get(); |
||
| 124 | } |
||
| 125 | |||
| 126 | /** |
||
| 127 | * {@inheritdoc} |
||
| 128 | */ |
||
| 129 | public function invalidateForSection(FullyQualifiedClassName $fullyQualifiedClassName): void |
||
| 130 | { |
||
| 131 | if ($this->enabled) { |
||
| 132 | $this->cache->invalidateTags([sha1((string)$fullyQualifiedClassName)]); |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 133 | } |
||
| 134 | } |
||
| 135 | |||
| 136 | /** |
||
| 137 | * {@inheritdoc} |
||
| 138 | */ |
||
| 139 | public function invalidateForContext(string $context): void |
||
| 140 | { |
||
| 141 | if ($this->enabled) { |
||
| 142 | $this->cache->invalidateTags([sha1($context)]); |
||
| 143 | } |
||
| 144 | } |
||
| 145 | |||
| 146 | /** |
||
| 147 | * Get the key for the item so the key will be unique for this |
||
| 148 | * specific cache item and can't be unexpectedly overridden. |
||
| 149 | * |
||
| 150 | * @param string $sectionHandle |
||
| 151 | * @param array $requestedFields |
||
| 152 | * @param string|null $context |
||
| 153 | * @param string|null $id |
||
| 154 | * @return string |
||
| 155 | */ |
||
| 156 | private function getItemKey( |
||
| 157 | string $sectionHandle, |
||
| 158 | array $requestedFields = null, |
||
| 159 | string $context = null, |
||
| 160 | string $id = null |
||
| 161 | ): string { |
||
| 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
|
|||
| 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 NotASexyFieldEntityException |
||
| 213 | */ |
||
| 214 | private function getRelationships(FullyQualifiedClassName $fullyQualifiedClassName): array |
||
| 215 | { |
||
| 216 | $fields = (string)$fullyQualifiedClassName; |
||
| 217 | if (!is_subclass_of($fields, CommonSectionInterface::class)) { |
||
| 218 | throw new NotASexyFieldEntityException; |
||
| 219 | } |
||
| 220 | /** @var CommonSectionInterface $fields */ |
||
| 221 | $relationships = []; |
||
| 222 | foreach ($fields::fieldInfo() as $field) { |
||
| 223 | if (!is_null($field['relationship'])) { |
||
| 224 | $relationships[] = $field['relationship']['class']; |
||
| 225 | } |
||
| 226 | } |
||
| 227 | return $relationships; |
||
| 228 | } |
||
| 229 | } |
||
| 230 |