Passed
Push — master ( 1f51b4...8c1ec1 )
by Mike
02:14
created

Cachable::checkCooldownAndFlushAfterPersiting()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php namespace GeneaLabs\LaravelModelCaching\Traits;
2
3
use GeneaLabs\LaravelModelCaching\CachedBuilder;
4
use GeneaLabs\LaravelModelCaching\CachedModel;
5
use GeneaLabs\LaravelModelCaching\CacheKey;
6
use GeneaLabs\LaravelModelCaching\CacheTags;
7
use Illuminate\Cache\TaggableStore;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
10
use Illuminate\Database\Query\Builder;
11
12
trait Cachable
13
{
14
    protected $isCachable = true;
15
16
    public function cache(array $tags = [])
17
    {
18
        $cache = cache();
19
20
        if (config('laravel-model-caching.store')) {
21
            $cache = $cache->store(config('laravel-model-caching.store'));
22
        }
23
24
        if (is_subclass_of($cache->getStore(), TaggableStore::class)) {
25
            $cache = $cache->tags($tags);
26
        }
27
28
        return $cache;
29
    }
30
31
    public function disableCache()
32
    {
33
        $this->isCachable = false;
34
35
        return $this;
36
    }
37
38
    public function flushCache(array $tags = [])
39
    {
40
        if (count($tags) === 0) {
41
            $tags = $this->makeCacheTags();
42
        }
43
44
        $this->cache($tags)->flush();
45
46
        [$cacheCooldown] = $this->getModelCacheCooldown($this);
1 ignored issue
show
Bug introduced by
$this of type GeneaLabs\LaravelModelCaching\Traits\Cachable is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $instance of GeneaLabs\LaravelModelCa...getModelCacheCooldown(). ( Ignorable by Annotation )

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

46
        [$cacheCooldown] = $this->getModelCacheCooldown(/** @scrutinizer ignore-type */ $this);
Loading history...
47
48
        if ($cacheCooldown) {
49
            $cachePrefix = $this->getCachePrefix();
50
            $modelClassName = get_class($this);
51
            $cacheKey = "{$cachePrefix}:{$modelClassName}-cooldown:saved-at";
52
53
            $this->cache()
54
                ->rememberForever($cacheKey, function () {
55
                    return now();
56
                });
57
        }
58
    }
59
60
    protected function getCachePrefix() : string
61
    {
62
        return "genealabs:laravel-model-caching:"
63
            . (config('laravel-model-caching.cache-prefix')
64
                ? config('laravel-model-caching.cache-prefix', '') . ":"
65
                : "");
66
    }
67
68
    protected function makeCacheKey(
69
        array $columns = ['*'],
70
        $idColumn = null,
71
        string $keyDifferentiator = ''
72
    ) : string {
73
        $eagerLoad = $this->eagerLoad ?? [];
74
        $model = $this->model ?? $this;
75
        $query = $this->query ?? app(Builder::class);
76
77
        return (new CacheKey($eagerLoad, $model, $query))
78
            ->make($columns, $idColumn, $keyDifferentiator);
79
    }
80
81
    protected function makeCacheTags() : array
82
    {
83
        $tags = (new CacheTags($this->eagerLoad ?? [], $this->model ?? $this))
84
            ->make();
85
86
        return $tags;
87
    }
88
89
    protected function getModelCacheCooldown(Model $instance)
90
    {
91
        $cachePrefix = $this->getCachePrefix();
92
        $modelClassName = get_class($instance);
93
        [$cacheCooldown, $invalidatedAt, $savedAt] = $this
94
            ->getCacheCooldownDetails($instance, $cachePrefix, $modelClassName);
95
96
        if (! $cacheCooldown) {
97
            return [null, null, null];
98
        }
99
100
        return [
101
            $cacheCooldown,
102
            $invalidatedAt,
103
            $savedAt,
104
        ];
105
    }
106
107
    protected function getCacheCooldownDetails(
108
        Model $instance,
109
        string $cachePrefix,
110
        string $modelClassName
111
    ) : array {
112
        return [
113
            $instance
114
                ->cache()
115
                ->get("{$cachePrefix}:{$modelClassName}-cooldown:seconds"),
116
            $instance
117
                ->cache()
118
                ->get("{$cachePrefix}:{$modelClassName}-cooldown:invalidated-at"),
119
            $instance
120
                ->cache()
121
                ->get("{$cachePrefix}:{$modelClassName}-cooldown:saved-at"),
122
        ];
123
    }
124
125
    protected function checkCooldownAndRemoveIfExpired(Model $instance)
126
    {
127
        [$cacheCooldown, $invalidatedAt] = $this->getModelCacheCooldown($instance);
128
129
        if (! $cacheCooldown
130
            || now()->diffInSeconds($invalidatedAt) < $cacheCooldown
131
        ) {
132
            return;
133
        }
134
135
        $cachePrefix = $this->getCachePrefix();
136
        $modelClassName = get_class($instance);
137
138
        $instance
139
            ->cache()
140
            ->forget("{$cachePrefix}:{$modelClassName}-cooldown:invalidated-at");
141
        $instance
142
            ->cache()
143
            ->forget("{$cachePrefix}:{$modelClassName}-cooldown:invalidated-at");
144
        $instance
145
            ->cache()
146
            ->forget("{$cachePrefix}:{$modelClassName}-cooldown:saved-at");
147
        $instance->flushCache();
148
    }
149
150
    protected function checkCooldownAndFlushAfterPersiting(Model $instance)
151
    {
152
        [$cacheCooldown, $invalidatedAt] = $instance->getModelCacheCooldown($instance);
153
154
        if (! $cacheCooldown) {
155
            $instance->flushCache();
156
157
            return;
158
        }
159
160
        $this->setCacheCooldownSavedAtTimestamp($instance);
161
162
        if (now()->diffInSeconds($invalidatedAt) >= $cacheCooldown) {
163
            $instance->flushCache();
164
        }
165
    }
166
167
    protected function setCacheCooldownSavedAtTimestamp(Model $instance)
168
    {
169
        $cachePrefix = $this->getCachePrefix();
170
        $modelClassName = get_class($instance);
171
        $cacheKey = "{$cachePrefix}:{$modelClassName}-cooldown:saved-at";
172
173
        $instance->cache()
174
            ->rememberForever($cacheKey, function () {
175
                return now();
176
            });
177
    }
178
179
    public static function bootCachable()
180
    {
181
        // TODO: add for deleted,updated,etc?
182
        static::saved(function ($instance) {
183
            $instance->checkCooldownAndFlushAfterPersiting($instance);
184
        });
185
    }
186
187
    public static function all($columns = ['*'])
188
    {
189
        if (config('laravel-model-caching.disabled')) {
190
            return parent::all($columns);
191
        }
192
193
        $class = get_called_class();
194
        $instance = new $class;
195
        $tags = [str_slug(get_called_class())];
196
        $key = $instance->makeCacheKey();
197
198
        return $instance->cache($tags)
199
            ->rememberForever($key, function () use ($columns) {
200
                return parent::all($columns);
201
            });
202
    }
203
204
    public function newEloquentBuilder($query)
205
    {
206
        if (! $this->isCachable()) {
207
            $this->isCachable = true;
208
209
            return new EloquentBuilder($query);
210
        }
211
212
        return new CachedBuilder($query);
213
    }
214
215
    public function isCachable() : bool
216
    {
217
        return $this->isCachable
218
            && ! config('laravel-model-caching.disabled');
219
    }
220
221
    public function scopeWithCacheCooldownSeconds(
222
        EloquentBuilder $query,
223
        int $seconds
224
    ) : EloquentBuilder {
225
        $cachePrefix = $this->getCachePrefix();
226
        $modelClassName = get_class($this);
227
        $cacheKey = "{$cachePrefix}:{$modelClassName}-cooldown:seconds";
228
229
        $this->cache()
230
            ->rememberForever($cacheKey, function () use ($seconds) {
231
                return $seconds;
232
            });
233
234
        $cacheKey = "{$cachePrefix}:{$modelClassName}-cooldown:invalidated-at";
235
        $this->cache()
236
            ->rememberForever($cacheKey, function () {
237
                return now();
238
            });
239
240
        return $query;
241
    }
242
}
243