InteractsWithCache::initCache()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
namespace Mostafaznv\LaraCache\Traits;
4
5
use Illuminate\Support\Facades\Cache;
6
use Illuminate\Support\Str;
7
use Mostafaznv\LaraCache\CacheEntity;
8
use Mostafaznv\LaraCache\DTOs\CacheData;
9
use Mostafaznv\LaraCache\DTOs\CacheEvent;
10
use Mostafaznv\LaraCache\DTOs\CacheStatus;
11
use Mostafaznv\LaraCache\Exceptions\CacheEntityDoesNotExist;
12
use Mostafaznv\LaraCache\Jobs\RefreshCache;
13
use Mostafaznv\LaraCache\Jobs\UpdateLaraCacheModelsList;
14
15
trait InteractsWithCache
16
{
17
    private string $prefix;
18
    private mixed $model;
19
    private string $laracacheListKey;
20
21
    public function __construct(string $model)
22
    {
23
        $this->prefix = Str::kebab(class_basename($model));
24
        $this->model = $model;
25
        $this->laracacheListKey = config('laracache.laracache-list');
26
    }
27
28
29
    private function getEntityFullName(CacheEntity $entity): string
30
    {
31
        return $this->prefix . '.' . $entity->name;
32
    }
33
34
    private function findCacheEntity(string $name, ?CacheEntity $entity = null): CacheEntity
35
    {
36
        if ($entity) {
37
            return $entity;
38
        }
39
40
        foreach ($this->model::cacheEntities() as $cacheEntity) {
41
            if ($cacheEntity->name === $name) {
42
                return $cacheEntity;
43
            }
44
        }
45
46
        throw CacheEntityDoesNotExist::make($name, $this->model);
47
    }
48
49
    private function entityIsCallable(CacheEntity $entity, ?CacheEvent $event = null): bool
50
    {
51
        return is_null($event)
52
            or ($event->equals(CacheEvent::CREATED()) and $entity->refreshAfterCreate)
53
            or ($event->equals(CacheEvent::UPDATED()) and $entity->refreshAfterUpdate)
54
            or ($event->equals(CacheEvent::DELETED()) and $entity->refreshAfterDelete)
55
            or ($event->equals(CacheEvent::RESTORED()) and $entity->refreshAfterRestore);
56
    }
57
58
    private function callCacheClosure(CacheEntity $entity, int $ttl, bool $delete = false): CacheData
59
    {
60
        if ($delete) {
61
            return CacheData::make(CacheStatus::DELETED(), $ttl, $entity->default);
62
        }
63
64
        $value = $entity->cacheClosure ? call_user_func($entity->cacheClosure) : null;
65
66
        return CacheData::make(
67
            status: CacheStatus::CREATED(),
68
            ttl: $ttl,
69
            value: $value ?: $entity->default
70
        );
71
    }
72
73
    private function updateCacheEntitiesList(CacheEntity $entity): void
74
    {
75
        $name = $this->getEntityFullName($entity);
76
        $list = Cache::store($entity->driver)->get($this->laracacheListKey);
77
78
        if (is_array($list)) {
79
            if (isset($list[$this->model]) and is_array($list[$this->model])) {
80
                if (!in_array($name, $list[$this->model])) {
81
                    $list[$this->model][] = $name;
82
                }
83
            }
84
            else {
85
                $list[$this->model] = [$name];
86
            }
87
        }
88
        else {
89
            $list = [
90
                $this->model => [$name]
91
            ];
92
        }
93
94
        Cache::store($entity->driver)->forever($this->laracacheListKey, $list);
95
    }
96
97
    private function putCacheIntoCacheStorage(CacheData $cache, string $driver, string $name, int $ttl): bool
98
    {
99
        if (is_null($cache->expiration)) {
100
            return Cache::store($driver)->forever($name, $cache);
101
        }
102
103
        return Cache::store($driver)->put($name, $cache, $ttl);
104
    }
105
106
    private function initCache(CacheEntity $entity, int $ttl): void
107
    {
108
        $name = $this->getEntityFullName($entity);
109
        $cache = CacheData::fromCache($entity, $this->prefix, $ttl);
110
111
        if ($cache->status->equals(CacheStatus::NOT_CREATED())) {
112
            $cache->value = $entity->default;
113
        }
114
115
        $cache->status = CacheStatus::CREATING();
116
117
        $this->putCacheIntoCacheStorage($cache, $entity->driver, $name, $ttl);
118
    }
119
120
    private function storeCache(CacheData $cache, CacheEntity $entity, int $ttl): void
121
    {
122
        $name = $this->getEntityFullName($entity);
123
124
        $this->putCacheIntoCacheStorage($cache, $entity->driver, $name, $ttl);
125
        $this->updateCacheEntitiesList($entity);
126
    }
127
128
    private function updateLaraCacheModelsList(): void
129
    {
130
        UpdateLaraCacheModelsList::dispatch($this->model);
131
    }
132
133
    private function updateCacheEntity(string $name, ?CacheEvent $event = null, CacheEntity $entity = null): CacheData
134
    {
135
        $entity = $this->findCacheEntity($name, $entity);
136
137
        if ($this->entityIsCallable($entity, $event)) {
138
            $ttl = $entity->getTtl();
139
140
            $this->initCache($entity, $ttl);
141
            $cache = $this->callCacheClosure($entity, $ttl);
142
            $this->storeCache($cache, $entity, $ttl);
143
144
            return $cache;
145
        }
146
147
        return CacheData::fromCache($entity, $this->prefix);
148
    }
149
150
    private function deleteCacheEntity(string $name, bool $deleteForever = false, CacheEntity $entity = null): CacheData
151
    {
152
        $entity = $this->findCacheEntity($name, $entity);
153
        $ttl = !$deleteForever ? $entity->getTtl() : 0;
154
        $cache = $this->callCacheClosure($entity, $ttl, true);
155
        $this->storeCache($cache, $entity, $ttl);
156
157
        return $cache;
158
    }
159
160
    private function retrieve(string $name): CacheData
161
    {
162
        $entity = $this->findCacheEntity($name);
163
        $cache = CacheData::fromCache($entity, $this->prefix);
164
165
        if ($cache->status->equals(CacheStatus::NOT_CREATED())) {
166
            if ($entity->isQueueable) {
167
                $this->initCache($entity, $entity->getTtl());
168
169
                RefreshCache::dispatch($this->model, $entity->name, CacheEvent::RETRIEVED())
170
                    ->onConnection($entity->queueConnection)
171
                    ->onQueue($entity->queueName);
172
173
                return CacheData::fromCache($entity, $this->prefix, $entity->ttl);
174
            }
175
176
            return $this->updateCacheEntity($name, null, $entity);
177
        }
178
179
        return $cache;
180
    }
181
}
182